1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Huawei Technologies Co., Ltd., 2015
4 * Copyright (C) 2022 SUSE LLC Andrea Cervesato <[email protected]>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Verify that when a process with non-zero user IDs performs an execve(),
11 * the process's capability sets are cleared.
12 * When a process with zero user IDs performs an execve(), the process's
13 * capability sets are set.
14 */
15
16 #include "tst_test.h"
17 #include "config.h"
18
19 #ifdef HAVE_LIBCAP
20 #define _GNU_SOURCE
21
22 #include <stdio.h>
23 #include "lapi/sched.h"
24 #include "common.h"
25
26 #define TEST_APP "userns06_capcheck"
27
28 #define CHILD1UID 0
29 #define CHILD1GID 0
30 #define CHILD2UID 200
31 #define CHILD2GID 200
32
child_fn1(void)33 static void child_fn1(void)
34 {
35 char *const args[] = { TEST_APP, "privileged", NULL };
36 int ret;
37
38 TST_CHECKPOINT_WAIT(0);
39
40 ret = execv(args[0], args);
41 if (ret == -1)
42 tst_brk(TBROK | TERRNO, "execv: unexpected error");
43 }
44
child_fn2(void)45 static void child_fn2(void)
46 {
47 int uid, gid, ret;
48 char *const args[] = { TEST_APP, "unprivileged", NULL };
49
50 TST_CHECKPOINT_WAIT(1);
51
52 uid = geteuid();
53 gid = getegid();
54
55 TST_EXP_EQ_LI(uid, CHILD2UID);
56 TST_EXP_EQ_LI(gid, CHILD2GID);
57
58 ret = execv(args[0], args);
59 if (ret == -1)
60 tst_brk(TBROK | TERRNO, "execv: unexpected error");
61 }
62
run(void)63 static void run(void)
64 {
65 const struct tst_clone_args args = {
66 .flags = CLONE_NEWUSER,
67 .exit_signal = SIGCHLD,
68 };
69 pid_t cpid1;
70 pid_t cpid2;
71 int parentuid;
72 int parentgid;
73 char path[BUFSIZ];
74 int fd;
75
76 parentuid = geteuid();
77 parentgid = getegid();
78
79 cpid1 = SAFE_CLONE(&args);
80 if (!cpid1) {
81 child_fn1();
82 return;
83 }
84
85 cpid2 = SAFE_CLONE(&args);
86 if (!cpid2) {
87 child_fn2();
88 return;
89 }
90
91 if (access("/proc/self/setgroups", F_OK) == 0) {
92 sprintf(path, "/proc/%d/setgroups", cpid1);
93
94 fd = SAFE_OPEN(path, O_WRONLY, 0644);
95 SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4);
96 SAFE_CLOSE(fd);
97
98 sprintf(path, "/proc/%d/setgroups", cpid2);
99
100 fd = SAFE_OPEN(path, O_WRONLY, 0644);
101 SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4);
102 SAFE_CLOSE(fd);
103 }
104
105 updatemap(cpid1, UID_MAP, CHILD1UID, parentuid);
106 updatemap(cpid2, UID_MAP, CHILD2UID, parentuid);
107
108 updatemap(cpid1, GID_MAP, CHILD1GID, parentgid);
109 updatemap(cpid2, GID_MAP, CHILD2GID, parentgid);
110
111 TST_CHECKPOINT_WAKE(0);
112 TST_CHECKPOINT_WAKE(1);
113 }
114
115 static struct tst_test test = {
116 .test_all = run,
117 .needs_root = 1,
118 .forks_child = 1,
119 .needs_checkpoints = 1,
120 .resource_files = (const char *[]) {
121 TEST_APP,
122 NULL,
123 },
124 .needs_kconfigs = (const char *[]) {
125 "CONFIG_USER_NS",
126 NULL,
127 },
128 };
129
130 #else
131 TST_TEST_TCONF("System is missing libcap");
132 #endif
133