1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2021 SUSE LLC <mdoucha@suse.cz> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci/*\ 6f08c3bdfSopenharmony_ci * [Description] 7f08c3bdfSopenharmony_ci * 8f08c3bdfSopenharmony_ci * CVE-2018-13405 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Check for possible privilege escalation through creating files with setgid 11f08c3bdfSopenharmony_ci * bit set inside a setgid directory owned by a group which the user does not 12f08c3bdfSopenharmony_ci * belong to. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * Fixed in: 15f08c3bdfSopenharmony_ci * 16f08c3bdfSopenharmony_ci * commit 0fa3ecd87848c9c93c2c828ef4c3a8ca36ce46c7 17f08c3bdfSopenharmony_ci * Author: Linus Torvalds <torvalds@linux-foundation.org> 18f08c3bdfSopenharmony_ci * Date: Tue Jul 3 17:10:19 2018 -0700 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * Fix up non-directory creation in SGID directories 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * This fix is incomplete if file is on xfs filesystem. 23f08c3bdfSopenharmony_ci * 24f08c3bdfSopenharmony_ci * Fixed in: 25f08c3bdfSopenharmony_ci * 26f08c3bdfSopenharmony_ci * commit 01ea173e103edd5ec41acec65b9261b87e123fc2 27f08c3bdfSopenharmony_ci * Author: Christoph Hellwig <hch@lst.de> 28f08c3bdfSopenharmony_ci * Date: Fri Jan 22 16:48:18 2021 -0800 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * xfs: fix up non-directory creation in SGID directories 31f08c3bdfSopenharmony_ci * 32f08c3bdfSopenharmony_ci * When use acl or umask, it still has bug. 33f08c3bdfSopenharmony_ci * 34f08c3bdfSopenharmony_ci * Fixed in: 35f08c3bdfSopenharmony_ci * 36f08c3bdfSopenharmony_ci * commit 1639a49ccdce58ea248841ed9b23babcce6dbb0b 37f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@fujitsu.com> 38f08c3bdfSopenharmony_ci * Date: Thu July 14 14:11:27 2022 +0800 39f08c3bdfSopenharmony_ci * 40f08c3bdfSopenharmony_ci * fs: move S_ISGID stripping into the vfs_*() helpers 41f08c3bdfSopenharmony_ci */ 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci#include <stdlib.h> 44f08c3bdfSopenharmony_ci#include <sys/types.h> 45f08c3bdfSopenharmony_ci#include <pwd.h> 46f08c3bdfSopenharmony_ci#include "tst_test.h" 47f08c3bdfSopenharmony_ci#include "tst_uid.h" 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci#define MODE_RWX 0777 50f08c3bdfSopenharmony_ci#define MODE_SGID (S_ISGID|0777) 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint" 53f08c3bdfSopenharmony_ci#define WORKDIR MNTPOINT "/testdir" 54f08c3bdfSopenharmony_ci#define CREAT_FILE WORKDIR "/creat.tmp" 55f08c3bdfSopenharmony_ci#define OPEN_FILE WORKDIR "/open.tmp" 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_cistatic gid_t free_gid; 58f08c3bdfSopenharmony_cistatic int fd = -1; 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_cistatic struct tcase { 61f08c3bdfSopenharmony_ci const char *msg; 62f08c3bdfSopenharmony_ci int mask; 63f08c3bdfSopenharmony_ci} tcases[] = { 64f08c3bdfSopenharmony_ci {"umask(0)", 0}, 65f08c3bdfSopenharmony_ci {"umask(S_IXGRP)", S_IXGRP} 66f08c3bdfSopenharmony_ci}; 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_cistatic void setup(void) 69f08c3bdfSopenharmony_ci{ 70f08c3bdfSopenharmony_ci struct stat buf; 71f08c3bdfSopenharmony_ci struct passwd *ltpuser = SAFE_GETPWNAM("nobody"); 72f08c3bdfSopenharmony_ci 73f08c3bdfSopenharmony_ci tst_res(TINFO, "User nobody: uid = %d, gid = %d", (int)ltpuser->pw_uid, 74f08c3bdfSopenharmony_ci (int)ltpuser->pw_gid); 75f08c3bdfSopenharmony_ci free_gid = tst_get_free_gid(ltpuser->pw_gid); 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci /* Create directories and set permissions */ 78f08c3bdfSopenharmony_ci SAFE_MKDIR(WORKDIR, MODE_RWX); 79f08c3bdfSopenharmony_ci SAFE_CHOWN(WORKDIR, ltpuser->pw_uid, free_gid); 80f08c3bdfSopenharmony_ci SAFE_CHMOD(WORKDIR, MODE_SGID); 81f08c3bdfSopenharmony_ci SAFE_STAT(WORKDIR, &buf); 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci if (!(buf.st_mode & S_ISGID)) 84f08c3bdfSopenharmony_ci tst_brk(TBROK, "%s: Setgid bit not set", WORKDIR); 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci if (buf.st_gid != free_gid) { 87f08c3bdfSopenharmony_ci tst_brk(TBROK, "%s: Incorrect group, %u != %u", WORKDIR, 88f08c3bdfSopenharmony_ci buf.st_gid, free_gid); 89f08c3bdfSopenharmony_ci } 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci /* Switch user */ 92f08c3bdfSopenharmony_ci SAFE_SETGID(ltpuser->pw_gid); 93f08c3bdfSopenharmony_ci SAFE_SETREUID(-1, ltpuser->pw_uid); 94f08c3bdfSopenharmony_ci} 95f08c3bdfSopenharmony_ci 96f08c3bdfSopenharmony_cistatic void file_test(const char *name) 97f08c3bdfSopenharmony_ci{ 98f08c3bdfSopenharmony_ci struct stat buf; 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci SAFE_STAT(name, &buf); 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci if (buf.st_gid != free_gid) { 103f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: Incorrect group, %u != %u", name, 104f08c3bdfSopenharmony_ci buf.st_gid, free_gid); 105f08c3bdfSopenharmony_ci } else { 106f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: Owned by correct group", name); 107f08c3bdfSopenharmony_ci } 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci if (buf.st_mode & S_ISGID) 110f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s: Setgid bit is set", name); 111f08c3bdfSopenharmony_ci else 112f08c3bdfSopenharmony_ci tst_res(TPASS, "%s: Setgid bit not set", name); 113f08c3bdfSopenharmony_ci} 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_cistatic void run(unsigned int n) 116f08c3bdfSopenharmony_ci{ 117f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci umask(tc->mask); 120f08c3bdfSopenharmony_ci tst_res(TINFO, "File created with %s", tc->msg); 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_ci fd = SAFE_CREAT(CREAT_FILE, MODE_SGID); 123f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 124f08c3bdfSopenharmony_ci file_test(CREAT_FILE); 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci fd = SAFE_OPEN(OPEN_FILE, O_CREAT | O_EXCL | O_RDWR, MODE_SGID); 127f08c3bdfSopenharmony_ci file_test(OPEN_FILE); 128f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci /* Cleanup between loops */ 131f08c3bdfSopenharmony_ci tst_purge_dir(WORKDIR); 132f08c3bdfSopenharmony_ci} 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_cistatic void cleanup(void) 135f08c3bdfSopenharmony_ci{ 136f08c3bdfSopenharmony_ci if (fd >= 0) 137f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 138f08c3bdfSopenharmony_ci} 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_cistatic struct tst_test test = { 141f08c3bdfSopenharmony_ci .test = run, 142f08c3bdfSopenharmony_ci .setup = setup, 143f08c3bdfSopenharmony_ci .cleanup = cleanup, 144f08c3bdfSopenharmony_ci .needs_root = 1, 145f08c3bdfSopenharmony_ci .all_filesystems = 1, 146f08c3bdfSopenharmony_ci .mount_device = 1, 147f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 148f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 149f08c3bdfSopenharmony_ci .skip_filesystems = (const char*[]) { 150f08c3bdfSopenharmony_ci "exfat", 151f08c3bdfSopenharmony_ci "ntfs", 152f08c3bdfSopenharmony_ci "vfat", 153f08c3bdfSopenharmony_ci NULL 154f08c3bdfSopenharmony_ci }, 155f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 156f08c3bdfSopenharmony_ci {"linux-git", "0fa3ecd87848"}, 157f08c3bdfSopenharmony_ci {"CVE", "2018-13405"}, 158f08c3bdfSopenharmony_ci {"CVE", "2021-4037"}, 159f08c3bdfSopenharmony_ci {"linux-git", "01ea173e103e"}, 160f08c3bdfSopenharmony_ci {"linux-git", "1639a49ccdce"}, 161f08c3bdfSopenharmony_ci {"linux-git", "426b4ca2d6a5"}, 162f08c3bdfSopenharmony_ci {} 163f08c3bdfSopenharmony_ci }, 164f08c3bdfSopenharmony_ci}; 165