• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2021 SUSE LLC <mdoucha@suse.cz>
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 <torvalds@linux-foundation.org>
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 <hch@lst.de>
28  *  Date:   Fri Jan 22 16:48:18 2021 -0800
29  *
30  *  xfs: fix up non-directory creation in SGID directories
31  */
32 
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <pwd.h>
36 #include "tst_test.h"
37 #include "tst_uid.h"
38 
39 #define MODE_RWX        0777
40 #define MODE_SGID       (S_ISGID|0777)
41 
42 #define MNTPOINT	"mntpoint"
43 #define WORKDIR		MNTPOINT "/testdir"
44 #define CREAT_FILE	WORKDIR "/creat.tmp"
45 #define OPEN_FILE	WORKDIR "/open.tmp"
46 
47 static gid_t free_gid;
48 static int fd = -1;
49 
setup(void)50 static void setup(void)
51 {
52 	struct stat buf;
53 	struct passwd *ltpuser = SAFE_GETPWNAM("nobody");
54 
55 	tst_res(TINFO, "User nobody: uid = %d, gid = %d", (int)ltpuser->pw_uid,
56 		(int)ltpuser->pw_gid);
57 	free_gid = tst_get_free_gid(ltpuser->pw_gid);
58 
59 	/* Create directories and set permissions */
60 	SAFE_MKDIR(WORKDIR, MODE_RWX);
61 	SAFE_CHOWN(WORKDIR, ltpuser->pw_uid, free_gid);
62 	SAFE_CHMOD(WORKDIR, MODE_SGID);
63 	SAFE_STAT(WORKDIR, &buf);
64 
65 	if (!(buf.st_mode & S_ISGID))
66 		tst_brk(TBROK, "%s: Setgid bit not set", WORKDIR);
67 
68 	if (buf.st_gid != free_gid) {
69 		tst_brk(TBROK, "%s: Incorrect group, %u != %u", WORKDIR,
70 			buf.st_gid, free_gid);
71 	}
72 
73 	/* Switch user */
74 	SAFE_SETGID(ltpuser->pw_gid);
75 	SAFE_SETREUID(-1, ltpuser->pw_uid);
76 }
77 
file_test(const char * name)78 static void file_test(const char *name)
79 {
80 	struct stat buf;
81 
82 	SAFE_STAT(name, &buf);
83 
84 	if (buf.st_gid != free_gid) {
85 		tst_res(TFAIL, "%s: Incorrect group, %u != %u", name,
86 			buf.st_gid, free_gid);
87 	} else {
88 		tst_res(TPASS, "%s: Owned by correct group", name);
89 	}
90 
91 	if (buf.st_mode & S_ISGID)
92 		tst_res(TFAIL, "%s: Setgid bit is set", name);
93 	else
94 		tst_res(TPASS, "%s: Setgid bit not set", name);
95 }
96 
run(void)97 static void run(void)
98 {
99 	fd = SAFE_CREAT(CREAT_FILE, MODE_SGID);
100 	SAFE_CLOSE(fd);
101 	file_test(CREAT_FILE);
102 
103 	fd = SAFE_OPEN(OPEN_FILE, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
104 	file_test(OPEN_FILE);
105 	SAFE_CLOSE(fd);
106 
107 	/* Cleanup between loops */
108 	tst_purge_dir(WORKDIR);
109 }
110 
cleanup(void)111 static void cleanup(void)
112 {
113 	if (fd >= 0)
114 		SAFE_CLOSE(fd);
115 }
116 
117 static struct tst_test test = {
118 	.test_all = run,
119 	.setup = setup,
120 	.cleanup = cleanup,
121 	.needs_root = 1,
122 	.all_filesystems = 1,
123 	.mount_device = 1,
124 	.mntpoint = MNTPOINT,
125 	.skip_filesystems = (const char*[]) {
126 		"exfat",
127 		"ntfs",
128 		"vfat",
129 		NULL
130 	},
131 	.tags = (const struct tst_tag[]) {
132 		{"linux-git", "0fa3ecd87848"},
133 		{"CVE", "2018-13405"},
134 		{"linux-git", "01ea173e103e"},
135 		{}
136 	},
137 };
138