1 // SPDX-License-Identifier: GPL-2.0
8 #include <sys/capability.h>
10 #include <sys/mount.h>
11 #include <sys/prctl.h>
20 # define CLONE_NEWUSER 0x10000000
24 #define RESTRICTED_PARENT 1
25 #define ALLOWED_CHILD1 2
26 #define ALLOWED_CHILD2 3
27 #define NO_POLICY_USER 4
29 char* add_whitelist_policy_file
= "/sys/kernel/security/safesetid/add_whitelist_policy";
31 static void die(char *fmt
, ...)
35 vfprintf(stderr
, fmt
, ap
);
40 static bool vmaybe_write_file(bool enoent_ok
, char *filename
, char *fmt
, va_list ap
)
47 buf_len
= vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
49 printf("vsnprintf failed: %s\n",
53 if (buf_len
>= sizeof(buf
)) {
54 printf("vsnprintf output truncated\n");
58 fd
= open(filename
, O_WRONLY
);
60 if ((errno
== ENOENT
) && enoent_ok
)
64 written
= write(fd
, buf
, buf_len
);
65 if (written
!= buf_len
) {
67 printf("short write to %s\n", filename
);
70 printf("write to %s failed: %s\n",
71 filename
, strerror(errno
));
76 printf("close of %s failed: %s\n",
77 filename
, strerror(errno
));
83 static bool write_file(char *filename
, char *fmt
, ...)
89 ret
= vmaybe_write_file(false, filename
, fmt
, ap
);
95 static void ensure_user_exists(uid_t uid
)
102 if (getpwuid(uid
) == NULL
) {
103 memset(&p
,0x00,sizeof(p
));
104 fd
=fopen("/etc/passwd","a");
106 die("couldn't open file\n");
107 if (fseek(fd
, 0, SEEK_END
))
108 die("couldn't fseek\n");
109 snprintf(name_str
, 10, "%d", uid
);
112 p
.pw_gecos
="Test account";
113 p
.pw_dir
="/dev/null";
114 p
.pw_shell
="/bin/false";
115 int value
= putpwent(&p
,fd
);
117 die("putpwent failed\n");
119 die("fclose failed\n");
123 static void ensure_securityfs_mounted(void)
125 int fd
= open(add_whitelist_policy_file
, O_WRONLY
);
127 if (errno
== ENOENT
) {
128 // Need to mount securityfs
129 if (mount("securityfs", "/sys/kernel/security",
130 "securityfs", 0, NULL
) < 0)
131 die("mounting securityfs failed\n");
133 die("couldn't find securityfs for unknown reason\n");
136 if (close(fd
) != 0) {
137 die("close of %s failed: %s\n",
138 add_whitelist_policy_file
, strerror(errno
));
143 static void write_policies(void)
145 static char *policy_str
=
153 fd
= open(add_whitelist_policy_file
, O_WRONLY
);
155 die("cant open add_whitelist_policy file\n");
156 written
= write(fd
, policy_str
, strlen(policy_str
));
157 if (written
!= strlen(policy_str
)) {
159 die("short write to %s\n", add_whitelist_policy_file
);
161 die("write to %s failed: %s\n",
162 add_whitelist_policy_file
, strerror(errno
));
165 if (close(fd
) != 0) {
166 die("close of %s failed: %s\n",
167 add_whitelist_policy_file
, strerror(errno
));
171 static bool test_userns(bool expect_success
)
174 char map_file_name
[32];
175 size_t sz
= sizeof(map_file_name
);
181 int clone_flags
= CLONE_NEWUSER
;
182 cpid
= syscall(SYS_clone
, clone_flags
, NULL
);
184 printf("clone failed");
188 if (cpid
== 0) { /* Code executed by child */
189 // Give parent 1 second to write map file
192 } else { /* Code executed by parent */
193 if(snprintf(map_file_name
, sz
, "/proc/%d/uid_map", cpid
) < 0) {
194 printf("preparing file name string failed");
197 success
= write_file(map_file_name
, "0 0 1", uid
);
198 return success
== expect_success
;
201 printf("should not reach here");
205 static void test_setuid(uid_t child_uid
, bool expect_success
)
215 if (cpid
== 0) { /* Code executed by child */
217 if (getuid() == child_uid
)
221 } else { /* Code executed by parent */
223 w
= waitpid(cpid
, &wstatus
, WUNTRACED
| WCONTINUED
);
228 if (WIFEXITED(wstatus
)) {
229 if (WEXITSTATUS(wstatus
) == EXIT_SUCCESS
) {
230 if (expect_success
) {
233 die("unexpected success\n");
236 if (expect_success
) {
237 die("unexpected failure\n");
242 } else if (WIFSIGNALED(wstatus
)) {
243 if (WTERMSIG(wstatus
) == 9) {
245 die("killed unexpectedly\n");
249 die("unexpected signal: %d\n", wstatus
);
252 die("unexpected status: %d\n", wstatus
);
254 } while (!WIFEXITED(wstatus
) && !WIFSIGNALED(wstatus
));
257 die("should not reach here\n");
260 static void ensure_users_exist(void)
262 ensure_user_exists(ROOT_USER
);
263 ensure_user_exists(RESTRICTED_PARENT
);
264 ensure_user_exists(ALLOWED_CHILD1
);
265 ensure_user_exists(ALLOWED_CHILD2
);
266 ensure_user_exists(NO_POLICY_USER
);
269 static void drop_caps(bool setid_retained
)
271 cap_value_t cap_values
[] = {CAP_SETUID
, CAP_SETGID
};
274 caps
= cap_get_proc();
276 cap_set_flag(caps
, CAP_EFFECTIVE
, 2, cap_values
, CAP_SET
);
283 int main(int argc
, char **argv
)
285 ensure_users_exist();
286 ensure_securityfs_mounted();
289 if (prctl(PR_SET_KEEPCAPS
, 1L))
290 die("Error with set keepcaps\n");
292 // First test to make sure we can write userns mappings from a user
293 // that doesn't have any restrictions (as long as it has CAP_SETUID);
294 setuid(NO_POLICY_USER
);
295 setgid(NO_POLICY_USER
);
297 // Take away all but setid caps
300 // Need PR_SET_DUMPABLE flag set so we can write /proc/[pid]/uid_map
301 // from non-root parent process.
302 if (prctl(PR_SET_DUMPABLE
, 1, 0, 0, 0))
303 die("Error with set dumpable\n");
305 if (!test_userns(true)) {
306 die("test_userns failed when it should work\n");
309 setuid(RESTRICTED_PARENT
);
310 setgid(RESTRICTED_PARENT
);
312 test_setuid(ROOT_USER
, false);
313 test_setuid(ALLOWED_CHILD1
, true);
314 test_setuid(ALLOWED_CHILD2
, true);
315 test_setuid(NO_POLICY_USER
, false);
317 if (!test_userns(false)) {
318 die("test_userns worked when it should fail\n");
321 // Now take away all caps
323 test_setuid(2, false);
324 test_setuid(3, false);
325 test_setuid(4, false);
327 // NOTE: this test doesn't clean up users that were created in
328 // /etc/passwd or flush policies that were added to the LSM.