1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd., 2015
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU General Public License as published by the Free
5 * Software Foundation; either version 2 of the License, or (at your option)
6 * any later version. This program is distributed in the hope that it will be
7 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
9 * Public License for more details. You should have received a copy of the GNU
10 * General Public License along with this program.
11 */
12
13 /*
14 * Verify that:
15 * When a process with non-zero user IDs performs an execve(), the process's
16 * capability sets are cleared.
17 * When a process with zero user IDs performs an execve(), the process's
18 * capability sets are set.
19 *
20 */
21
22 #define _GNU_SOURCE
23 #include <sys/wait.h>
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdbool.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31 #include "libclone.h"
32 #include "test.h"
33 #include "config.h"
34 #include "userns_helper.h"
35
36 #define CHILD1UID 0
37 #define CHILD1GID 0
38 #define CHILD2UID 200
39 #define CHILD2GID 200
40
41 char *TCID = "user_namespace6";
42 int TST_TOTAL = 1;
43
44 static int cpid1, parentuid, parentgid;
45
46 /*
47 * child_fn1() - Inside a new user namespace
48 */
child_fn1(void)49 static int child_fn1(void)
50 {
51 int exit_val = 0;
52 char *const args[] = { "userns06_capcheck", "privileged", NULL };
53
54 TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
55
56 if (execve(args[0], args, NULL) == -1) {
57 printf("execvp unexpected error: (%d) %s\n",
58 errno, strerror(errno));
59 exit_val = 1;
60 }
61
62 return exit_val;
63 }
64
65 /*
66 * child_fn2() - Inside a new user namespace
67 */
child_fn2(void)68 static int child_fn2(void)
69 {
70 int exit_val = 0;
71 int uid, gid;
72 char *const args[] = { "userns06_capcheck", "unprivileged", NULL };
73
74 TST_SAFE_CHECKPOINT_WAIT(NULL, 1);
75
76 uid = geteuid();
77 gid = getegid();
78
79 if (uid != CHILD2UID || gid != CHILD2GID) {
80 printf("unexpected uid=%d gid=%d\n", uid, gid);
81 exit_val = 1;
82 }
83
84 if (execve(args[0], args, NULL) == -1) {
85 printf("execvp unexpected error: (%d) %s\n",
86 errno, strerror(errno));
87 exit_val = 1;
88 }
89
90 return exit_val;
91 }
92
cleanup(void)93 static void cleanup(void)
94 {
95 tst_rmdir();
96 }
97
setup(void)98 static void setup(void)
99 {
100 check_newuser();
101 tst_tmpdir();
102 TST_CHECKPOINT_INIT(NULL);
103 TST_RESOURCE_COPY(cleanup, "userns06_capcheck", NULL);
104 }
105
main(int argc,char * argv[])106 int main(int argc, char *argv[])
107 {
108 pid_t cpid2;
109 char path[BUFSIZ];
110 int lc;
111 int fd;
112
113 tst_parse_opts(argc, argv, NULL, NULL);
114 #ifndef HAVE_LIBCAP
115 tst_brkm(TCONF, NULL, "System is missing libcap.");
116 #endif
117 setup();
118
119 for (lc = 0; TEST_LOOPING(lc); lc++) {
120 tst_count = 0;
121
122 parentuid = geteuid();
123 parentgid = getegid();
124
125 cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD,
126 (void *)child_fn1, NULL);
127 if (cpid1 < 0)
128 tst_brkm(TBROK | TERRNO, cleanup,
129 "cpid1 clone failed");
130
131 cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD,
132 (void *)child_fn2, NULL);
133 if (cpid2 < 0)
134 tst_brkm(TBROK | TERRNO, cleanup,
135 "cpid2 clone failed");
136
137 if (access("/proc/self/setgroups", F_OK) == 0) {
138 sprintf(path, "/proc/%d/setgroups", cpid1);
139 fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644);
140 SAFE_WRITE(cleanup, 1, fd, "deny", 4);
141 SAFE_CLOSE(cleanup, fd);
142
143 sprintf(path, "/proc/%d/setgroups", cpid2);
144 fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644);
145 SAFE_WRITE(cleanup, 1, fd, "deny", 4);
146 SAFE_CLOSE(cleanup, fd);
147 }
148
149 updatemap(cpid1, UID_MAP, CHILD1UID, parentuid, cleanup);
150 updatemap(cpid2, UID_MAP, CHILD2UID, parentuid, cleanup);
151
152 updatemap(cpid1, GID_MAP, CHILD1GID, parentgid, cleanup);
153 updatemap(cpid2, GID_MAP, CHILD2GID, parentgid, cleanup);
154
155 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
156 TST_SAFE_CHECKPOINT_WAKE(cleanup, 1);
157
158 tst_record_childstatus(cleanup, cpid1);
159 tst_record_childstatus(cleanup, cpid2);
160 }
161 cleanup();
162 tst_exit();
163 }
164