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