xref: /aosp_15_r20/external/ltp/testcases/kernel/containers/userns/userns03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) Huawei Technologies Co., Ltd., 2015
4*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (C) 2022 SUSE LLC Andrea Cervesato <[email protected]>
5*49cdfc7eSAndroid Build Coastguard Worker  */
6*49cdfc7eSAndroid Build Coastguard Worker 
7*49cdfc7eSAndroid Build Coastguard Worker /*\
8*49cdfc7eSAndroid Build Coastguard Worker  * [Description]
9*49cdfc7eSAndroid Build Coastguard Worker  *
10*49cdfc7eSAndroid Build Coastguard Worker  * Verify that /proc/PID/uid_map and /proc/PID/gid_map contains three values
11*49cdfc7eSAndroid Build Coastguard Worker  * separated by white space:
12*49cdfc7eSAndroid Build Coastguard Worker  *
13*49cdfc7eSAndroid Build Coastguard Worker  * ID-inside-ns   ID-outside-ns   length
14*49cdfc7eSAndroid Build Coastguard Worker  *
15*49cdfc7eSAndroid Build Coastguard Worker  * ID-outside-ns is interpreted according to which process is opening the file.
16*49cdfc7eSAndroid Build Coastguard Worker  *
17*49cdfc7eSAndroid Build Coastguard Worker  * If the process opening the file is in the same user namespace as the process
18*49cdfc7eSAndroid Build Coastguard Worker  * PID, then ID-outside-ns is defined with respect to the parent user namespace.
19*49cdfc7eSAndroid Build Coastguard Worker  *
20*49cdfc7eSAndroid Build Coastguard Worker  * If the process opening the file is in a different user namespace, then
21*49cdfc7eSAndroid Build Coastguard Worker  * ID-outside-ns is defined with respect to the user namespace of the process
22*49cdfc7eSAndroid Build Coastguard Worker  * opening the file.
23*49cdfc7eSAndroid Build Coastguard Worker  *
24*49cdfc7eSAndroid Build Coastguard Worker  * The string "deny" would be written to /proc/self/setgroups before GID
25*49cdfc7eSAndroid Build Coastguard Worker  * check if setgroups is allowed, see kernel commits:
26*49cdfc7eSAndroid Build Coastguard Worker  *
27*49cdfc7eSAndroid Build Coastguard Worker  * - 9cc46516ddf4 ("userns: Add a knob to disable setgroups on a per user namespace basis")
28*49cdfc7eSAndroid Build Coastguard Worker  * - 66d2f338ee4c ("userns: Allow setting gid_maps without privilege when setgroups is disabled")
29*49cdfc7eSAndroid Build Coastguard Worker  */
30*49cdfc7eSAndroid Build Coastguard Worker 
31*49cdfc7eSAndroid Build Coastguard Worker #define _GNU_SOURCE
32*49cdfc7eSAndroid Build Coastguard Worker 
33*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
34*49cdfc7eSAndroid Build Coastguard Worker #include <stdbool.h>
35*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
36*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/sched.h"
37*49cdfc7eSAndroid Build Coastguard Worker #include "common.h"
38*49cdfc7eSAndroid Build Coastguard Worker 
39*49cdfc7eSAndroid Build Coastguard Worker #define CHILD1UID 0
40*49cdfc7eSAndroid Build Coastguard Worker #define CHILD1GID 0
41*49cdfc7eSAndroid Build Coastguard Worker #define CHILD2UID 200
42*49cdfc7eSAndroid Build Coastguard Worker #define CHILD2GID 200
43*49cdfc7eSAndroid Build Coastguard Worker #define UID_MAP 0
44*49cdfc7eSAndroid Build Coastguard Worker #define GID_MAP 1
45*49cdfc7eSAndroid Build Coastguard Worker 
child_fn1(void)46*49cdfc7eSAndroid Build Coastguard Worker static void child_fn1(void)
47*49cdfc7eSAndroid Build Coastguard Worker {
48*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAIT(0);
49*49cdfc7eSAndroid Build Coastguard Worker }
50*49cdfc7eSAndroid Build Coastguard Worker 
child_fn2(int cpid1,int parentuid,int parentgid)51*49cdfc7eSAndroid Build Coastguard Worker static void child_fn2(int cpid1, int parentuid, int parentgid)
52*49cdfc7eSAndroid Build Coastguard Worker {
53*49cdfc7eSAndroid Build Coastguard Worker 	int uid, gid;
54*49cdfc7eSAndroid Build Coastguard Worker 	char cpid1uidpath[BUFSIZ];
55*49cdfc7eSAndroid Build Coastguard Worker 	char cpid1gidpath[BUFSIZ];
56*49cdfc7eSAndroid Build Coastguard Worker 	int idinsidens, idoutsidens, length;
57*49cdfc7eSAndroid Build Coastguard Worker 
58*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAIT(1);
59*49cdfc7eSAndroid Build Coastguard Worker 
60*49cdfc7eSAndroid Build Coastguard Worker 	uid = geteuid();
61*49cdfc7eSAndroid Build Coastguard Worker 	gid = getegid();
62*49cdfc7eSAndroid Build Coastguard Worker 
63*49cdfc7eSAndroid Build Coastguard Worker 	TST_EXP_EQ_LI(uid, CHILD2UID);
64*49cdfc7eSAndroid Build Coastguard Worker 	TST_EXP_EQ_LI(gid, CHILD2GID);
65*49cdfc7eSAndroid Build Coastguard Worker 
66*49cdfc7eSAndroid Build Coastguard Worker 	/* Get the uid parameters of the child_fn2 process */
67*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_SCANF("/proc/self/uid_map", "%d %d %d", &idinsidens, &idoutsidens, &length);
68*49cdfc7eSAndroid Build Coastguard Worker 
69*49cdfc7eSAndroid Build Coastguard Worker 	/* map file format:ID-inside-ns   ID-outside-ns   length
70*49cdfc7eSAndroid Build Coastguard Worker 	 * If the process opening the file is in the same user namespace as
71*49cdfc7eSAndroid Build Coastguard Worker 	 * the process PID, then ID-outside-ns is defined with respect to the
72*49cdfc7eSAndroid Build Coastguard Worker 	 * parent user namespace
73*49cdfc7eSAndroid Build Coastguard Worker 	 */
74*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "child2 checks /proc/cpid2/uid_map");
75*49cdfc7eSAndroid Build Coastguard Worker 
76*49cdfc7eSAndroid Build Coastguard Worker 	if (idinsidens != CHILD2UID || idoutsidens != parentuid)
77*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
78*49cdfc7eSAndroid Build Coastguard Worker 	else
79*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "expected namespaces IDs");
80*49cdfc7eSAndroid Build Coastguard Worker 
81*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(cpid1uidpath, "/proc/%d/uid_map", cpid1);
82*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_SCANF(cpid1uidpath, "%d %d %d", &idinsidens, &idoutsidens, &length);
83*49cdfc7eSAndroid Build Coastguard Worker 
84*49cdfc7eSAndroid Build Coastguard Worker 	/* If the process opening the file is in a different user namespace,
85*49cdfc7eSAndroid Build Coastguard Worker 	 * then ID-outside-ns is defined with respect to the user namespace
86*49cdfc7eSAndroid Build Coastguard Worker 	 * of the process opening the file
87*49cdfc7eSAndroid Build Coastguard Worker 	 */
88*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "child2 checks /proc/cpid1/uid_map");
89*49cdfc7eSAndroid Build Coastguard Worker 
90*49cdfc7eSAndroid Build Coastguard Worker 	if (idinsidens != CHILD1UID || idoutsidens != CHILD2UID)
91*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
92*49cdfc7eSAndroid Build Coastguard Worker 	else
93*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "expected namespaces IDs");
94*49cdfc7eSAndroid Build Coastguard Worker 
95*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(cpid1gidpath, "/proc/%d/gid_map", cpid1);
96*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_SCANF("/proc/self/gid_map", "%d %d %d", &idinsidens, &idoutsidens, &length);
97*49cdfc7eSAndroid Build Coastguard Worker 
98*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "child2 checks /proc/cpid2/gid_map");
99*49cdfc7eSAndroid Build Coastguard Worker 
100*49cdfc7eSAndroid Build Coastguard Worker 	if (idinsidens != CHILD2GID || idoutsidens != parentgid)
101*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
102*49cdfc7eSAndroid Build Coastguard Worker 	else
103*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "expected namespaces IDs");
104*49cdfc7eSAndroid Build Coastguard Worker 
105*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_SCANF(cpid1gidpath, "%d %d %d", &idinsidens, &idoutsidens, &length);
106*49cdfc7eSAndroid Build Coastguard Worker 
107*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "child1 checks /proc/cpid1/gid_map");
108*49cdfc7eSAndroid Build Coastguard Worker 
109*49cdfc7eSAndroid Build Coastguard Worker 	if (idinsidens != CHILD1GID || idoutsidens != CHILD2GID)
110*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens);
111*49cdfc7eSAndroid Build Coastguard Worker 	else
112*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TPASS, "expected namespaces IDs");
113*49cdfc7eSAndroid Build Coastguard Worker 
114*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAKE(0);
115*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAKE(1);
116*49cdfc7eSAndroid Build Coastguard Worker }
117*49cdfc7eSAndroid Build Coastguard Worker 
run(void)118*49cdfc7eSAndroid Build Coastguard Worker static void run(void)
119*49cdfc7eSAndroid Build Coastguard Worker {
120*49cdfc7eSAndroid Build Coastguard Worker 	const struct tst_clone_args args = {
121*49cdfc7eSAndroid Build Coastguard Worker 		.flags = CLONE_NEWUSER,
122*49cdfc7eSAndroid Build Coastguard Worker 		.exit_signal = SIGCHLD,
123*49cdfc7eSAndroid Build Coastguard Worker 	};
124*49cdfc7eSAndroid Build Coastguard Worker 	pid_t cpid1, cpid2;
125*49cdfc7eSAndroid Build Coastguard Worker 	uid_t parentuid;
126*49cdfc7eSAndroid Build Coastguard Worker 	gid_t parentgid;
127*49cdfc7eSAndroid Build Coastguard Worker 	char path[BUFSIZ];
128*49cdfc7eSAndroid Build Coastguard Worker 	int fd;
129*49cdfc7eSAndroid Build Coastguard Worker 
130*49cdfc7eSAndroid Build Coastguard Worker 	parentuid = geteuid();
131*49cdfc7eSAndroid Build Coastguard Worker 	parentgid = getegid();
132*49cdfc7eSAndroid Build Coastguard Worker 
133*49cdfc7eSAndroid Build Coastguard Worker 	cpid1 = SAFE_CLONE(&args);
134*49cdfc7eSAndroid Build Coastguard Worker 	if (!cpid1) {
135*49cdfc7eSAndroid Build Coastguard Worker 		child_fn1();
136*49cdfc7eSAndroid Build Coastguard Worker 		return;
137*49cdfc7eSAndroid Build Coastguard Worker 	}
138*49cdfc7eSAndroid Build Coastguard Worker 
139*49cdfc7eSAndroid Build Coastguard Worker 	cpid2 = SAFE_CLONE(&args);
140*49cdfc7eSAndroid Build Coastguard Worker 	if (!cpid2) {
141*49cdfc7eSAndroid Build Coastguard Worker 		child_fn2(cpid1, parentuid, parentgid);
142*49cdfc7eSAndroid Build Coastguard Worker 		return;
143*49cdfc7eSAndroid Build Coastguard Worker 	}
144*49cdfc7eSAndroid Build Coastguard Worker 
145*49cdfc7eSAndroid Build Coastguard Worker 	if (access("/proc/self/setgroups", F_OK) == 0) {
146*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(path, "/proc/%d/setgroups", cpid1);
147*49cdfc7eSAndroid Build Coastguard Worker 
148*49cdfc7eSAndroid Build Coastguard Worker 		fd = SAFE_OPEN(path, O_WRONLY, 0644);
149*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4);
150*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd);
151*49cdfc7eSAndroid Build Coastguard Worker 
152*49cdfc7eSAndroid Build Coastguard Worker 		/* If the setgroups file has the value "deny",
153*49cdfc7eSAndroid Build Coastguard Worker 		 * then the setgroups(2) system call can't
154*49cdfc7eSAndroid Build Coastguard Worker 		 * subsequently be reenabled (by writing "allow" to
155*49cdfc7eSAndroid Build Coastguard Worker 		 * the file) in this user namespace.  (Attempts to
156*49cdfc7eSAndroid Build Coastguard Worker 		 * do so will fail with the error EPERM.)
157*49cdfc7eSAndroid Build Coastguard Worker 		 */
158*49cdfc7eSAndroid Build Coastguard Worker 
159*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "Check if setgroups can be re-enabled");
160*49cdfc7eSAndroid Build Coastguard Worker 
161*49cdfc7eSAndroid Build Coastguard Worker 		fd = SAFE_OPEN(path, O_WRONLY, 0644);
162*49cdfc7eSAndroid Build Coastguard Worker 		TST_EXP_FAIL2(write(fd, "allow", 5), EPERM);
163*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd);
164*49cdfc7eSAndroid Build Coastguard Worker 
165*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(path, "/proc/%d/setgroups", cpid2);
166*49cdfc7eSAndroid Build Coastguard Worker 
167*49cdfc7eSAndroid Build Coastguard Worker 		fd = SAFE_OPEN(path, O_WRONLY, 0644);
168*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4);
169*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd);
170*49cdfc7eSAndroid Build Coastguard Worker 	}
171*49cdfc7eSAndroid Build Coastguard Worker 
172*49cdfc7eSAndroid Build Coastguard Worker 	updatemap(cpid1, UID_MAP, CHILD1UID, parentuid);
173*49cdfc7eSAndroid Build Coastguard Worker 	updatemap(cpid2, UID_MAP, CHILD2UID, parentuid);
174*49cdfc7eSAndroid Build Coastguard Worker 
175*49cdfc7eSAndroid Build Coastguard Worker 	updatemap(cpid1, GID_MAP, CHILD1GID, parentgid);
176*49cdfc7eSAndroid Build Coastguard Worker 	updatemap(cpid2, GID_MAP, CHILD2GID, parentgid);
177*49cdfc7eSAndroid Build Coastguard Worker 
178*49cdfc7eSAndroid Build Coastguard Worker 	TST_CHECKPOINT_WAKE_AND_WAIT(1);
179*49cdfc7eSAndroid Build Coastguard Worker }
180*49cdfc7eSAndroid Build Coastguard Worker 
181*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
182*49cdfc7eSAndroid Build Coastguard Worker 	.test_all = run,
183*49cdfc7eSAndroid Build Coastguard Worker 	.needs_root = 1,
184*49cdfc7eSAndroid Build Coastguard Worker 	.forks_child = 1,
185*49cdfc7eSAndroid Build Coastguard Worker 	.needs_checkpoints = 1,
186*49cdfc7eSAndroid Build Coastguard Worker 	.needs_kconfigs = (const char *[]) {
187*49cdfc7eSAndroid Build Coastguard Worker 		"CONFIG_USER_NS",
188*49cdfc7eSAndroid Build Coastguard Worker 		NULL,
189*49cdfc7eSAndroid Build Coastguard Worker 	},
190*49cdfc7eSAndroid Build Coastguard Worker };
191