xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/capabilities/test_execve.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #define _GNU_SOURCE
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <cap-ng.h>
5*4882a593Smuzhiyun #include <linux/capability.h>
6*4882a593Smuzhiyun #include <stdbool.h>
7*4882a593Smuzhiyun #include <string.h>
8*4882a593Smuzhiyun #include <stdio.h>
9*4882a593Smuzhiyun #include <fcntl.h>
10*4882a593Smuzhiyun #include <errno.h>
11*4882a593Smuzhiyun #include <stdarg.h>
12*4882a593Smuzhiyun #include <sched.h>
13*4882a593Smuzhiyun #include <sys/mount.h>
14*4882a593Smuzhiyun #include <limits.h>
15*4882a593Smuzhiyun #include <libgen.h>
16*4882a593Smuzhiyun #include <malloc.h>
17*4882a593Smuzhiyun #include <sys/wait.h>
18*4882a593Smuzhiyun #include <sys/prctl.h>
19*4882a593Smuzhiyun #include <sys/stat.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "../kselftest.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #ifndef PR_CAP_AMBIENT
24*4882a593Smuzhiyun #define PR_CAP_AMBIENT			47
25*4882a593Smuzhiyun # define PR_CAP_AMBIENT_IS_SET		1
26*4882a593Smuzhiyun # define PR_CAP_AMBIENT_RAISE		2
27*4882a593Smuzhiyun # define PR_CAP_AMBIENT_LOWER		3
28*4882a593Smuzhiyun # define PR_CAP_AMBIENT_CLEAR_ALL	4
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static int nerrs;
32*4882a593Smuzhiyun static pid_t mpid;	/*  main() pid is used to avoid duplicate test counts */
33*4882a593Smuzhiyun 
vmaybe_write_file(bool enoent_ok,char * filename,char * fmt,va_list ap)34*4882a593Smuzhiyun static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list ap)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	char buf[4096];
37*4882a593Smuzhiyun 	int fd;
38*4882a593Smuzhiyun 	ssize_t written;
39*4882a593Smuzhiyun 	int buf_len;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	buf_len = vsnprintf(buf, sizeof(buf), fmt, ap);
42*4882a593Smuzhiyun 	if (buf_len < 0)
43*4882a593Smuzhiyun 		ksft_exit_fail_msg("vsnprintf failed - %s\n", strerror(errno));
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	if (buf_len >= sizeof(buf))
46*4882a593Smuzhiyun 		ksft_exit_fail_msg("vsnprintf output truncated\n");
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	fd = open(filename, O_WRONLY);
50*4882a593Smuzhiyun 	if (fd < 0) {
51*4882a593Smuzhiyun 		if ((errno == ENOENT) && enoent_ok)
52*4882a593Smuzhiyun 			return;
53*4882a593Smuzhiyun 		ksft_exit_fail_msg("open of %s failed - %s\n",
54*4882a593Smuzhiyun 					filename, strerror(errno));
55*4882a593Smuzhiyun 	}
56*4882a593Smuzhiyun 	written = write(fd, buf, buf_len);
57*4882a593Smuzhiyun 	if (written != buf_len) {
58*4882a593Smuzhiyun 		if (written >= 0) {
59*4882a593Smuzhiyun 			ksft_exit_fail_msg("short write to %s\n", filename);
60*4882a593Smuzhiyun 		} else {
61*4882a593Smuzhiyun 			ksft_exit_fail_msg("write to %s failed - %s\n",
62*4882a593Smuzhiyun 						filename, strerror(errno));
63*4882a593Smuzhiyun 		}
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 	if (close(fd) != 0) {
66*4882a593Smuzhiyun 		ksft_exit_fail_msg("close of %s failed - %s\n",
67*4882a593Smuzhiyun 					filename, strerror(errno));
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
maybe_write_file(char * filename,char * fmt,...)71*4882a593Smuzhiyun static void maybe_write_file(char *filename, char *fmt, ...)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	va_list ap;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	va_start(ap, fmt);
76*4882a593Smuzhiyun 	vmaybe_write_file(true, filename, fmt, ap);
77*4882a593Smuzhiyun 	va_end(ap);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
write_file(char * filename,char * fmt,...)80*4882a593Smuzhiyun static void write_file(char *filename, char *fmt, ...)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	va_list ap;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	va_start(ap, fmt);
85*4882a593Smuzhiyun 	vmaybe_write_file(false, filename, fmt, ap);
86*4882a593Smuzhiyun 	va_end(ap);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
create_and_enter_ns(uid_t inner_uid)89*4882a593Smuzhiyun static bool create_and_enter_ns(uid_t inner_uid)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	uid_t outer_uid;
92*4882a593Smuzhiyun 	gid_t outer_gid;
93*4882a593Smuzhiyun 	int i;
94*4882a593Smuzhiyun 	bool have_outer_privilege;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	outer_uid = getuid();
97*4882a593Smuzhiyun 	outer_gid = getgid();
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	/*
100*4882a593Smuzhiyun 	 * TODO: If we're already root, we could skip creating the userns.
101*4882a593Smuzhiyun 	 */
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if (unshare(CLONE_NEWNS) == 0) {
104*4882a593Smuzhiyun 		ksft_print_msg("[NOTE]\tUsing global UIDs for tests\n");
105*4882a593Smuzhiyun 		if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0)
106*4882a593Smuzhiyun 			ksft_exit_fail_msg("PR_SET_KEEPCAPS - %s\n",
107*4882a593Smuzhiyun 						strerror(errno));
108*4882a593Smuzhiyun 		if (setresuid(inner_uid, inner_uid, -1) != 0)
109*4882a593Smuzhiyun 			ksft_exit_fail_msg("setresuid - %s\n", strerror(errno));
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		// Re-enable effective caps
112*4882a593Smuzhiyun 		capng_get_caps_process();
113*4882a593Smuzhiyun 		for (i = 0; i < CAP_LAST_CAP; i++)
114*4882a593Smuzhiyun 			if (capng_have_capability(CAPNG_PERMITTED, i))
115*4882a593Smuzhiyun 				capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, i);
116*4882a593Smuzhiyun 		if (capng_apply(CAPNG_SELECT_CAPS) != 0)
117*4882a593Smuzhiyun 			ksft_exit_fail_msg(
118*4882a593Smuzhiyun 					"capng_apply - %s\n", strerror(errno));
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		have_outer_privilege = true;
121*4882a593Smuzhiyun 	} else if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == 0) {
122*4882a593Smuzhiyun 		ksft_print_msg("[NOTE]\tUsing a user namespace for tests\n");
123*4882a593Smuzhiyun 		maybe_write_file("/proc/self/setgroups", "deny");
124*4882a593Smuzhiyun 		write_file("/proc/self/uid_map", "%d %d 1", inner_uid, outer_uid);
125*4882a593Smuzhiyun 		write_file("/proc/self/gid_map", "0 %d 1", outer_gid);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 		have_outer_privilege = false;
128*4882a593Smuzhiyun 	} else {
129*4882a593Smuzhiyun 		ksft_exit_skip("must be root or be able to create a userns\n");
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	if (mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
133*4882a593Smuzhiyun 		ksft_exit_fail_msg("remount everything private - %s\n",
134*4882a593Smuzhiyun 					strerror(errno));
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	return have_outer_privilege;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
chdir_to_tmpfs(void)139*4882a593Smuzhiyun static void chdir_to_tmpfs(void)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	char cwd[PATH_MAX];
142*4882a593Smuzhiyun 	if (getcwd(cwd, sizeof(cwd)) != cwd)
143*4882a593Smuzhiyun 		ksft_exit_fail_msg("getcwd - %s\n", strerror(errno));
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	if (mount("private_tmp", ".", "tmpfs", 0, "mode=0777") != 0)
146*4882a593Smuzhiyun 		ksft_exit_fail_msg("mount private tmpfs - %s\n",
147*4882a593Smuzhiyun 					strerror(errno));
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (chdir(cwd) != 0)
150*4882a593Smuzhiyun 		ksft_exit_fail_msg("chdir to private tmpfs - %s\n",
151*4882a593Smuzhiyun 					strerror(errno));
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
copy_fromat_to(int fromfd,const char * fromname,const char * toname)154*4882a593Smuzhiyun static void copy_fromat_to(int fromfd, const char *fromname, const char *toname)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	int from = openat(fromfd, fromname, O_RDONLY);
157*4882a593Smuzhiyun 	if (from == -1)
158*4882a593Smuzhiyun 		ksft_exit_fail_msg("open copy source - %s\n", strerror(errno));
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	int to = open(toname, O_CREAT | O_WRONLY | O_EXCL, 0700);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	while (true) {
163*4882a593Smuzhiyun 		char buf[4096];
164*4882a593Smuzhiyun 		ssize_t sz = read(from, buf, sizeof(buf));
165*4882a593Smuzhiyun 		if (sz == 0)
166*4882a593Smuzhiyun 			break;
167*4882a593Smuzhiyun 		if (sz < 0)
168*4882a593Smuzhiyun 			ksft_exit_fail_msg("read - %s\n", strerror(errno));
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 		if (write(to, buf, sz) != sz)
171*4882a593Smuzhiyun 			/* no short writes on tmpfs */
172*4882a593Smuzhiyun 			ksft_exit_fail_msg("write - %s\n", strerror(errno));
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	close(from);
176*4882a593Smuzhiyun 	close(to);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
fork_wait(void)179*4882a593Smuzhiyun static bool fork_wait(void)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	pid_t child = fork();
182*4882a593Smuzhiyun 	if (child == 0) {
183*4882a593Smuzhiyun 		nerrs = 0;
184*4882a593Smuzhiyun 		return true;
185*4882a593Smuzhiyun 	} else if (child > 0) {
186*4882a593Smuzhiyun 		int status;
187*4882a593Smuzhiyun 		if (waitpid(child, &status, 0) != child ||
188*4882a593Smuzhiyun 		    !WIFEXITED(status)) {
189*4882a593Smuzhiyun 			ksft_print_msg("Child died\n");
190*4882a593Smuzhiyun 			nerrs++;
191*4882a593Smuzhiyun 		} else if (WEXITSTATUS(status) != 0) {
192*4882a593Smuzhiyun 			ksft_print_msg("Child failed\n");
193*4882a593Smuzhiyun 			nerrs++;
194*4882a593Smuzhiyun 		} else {
195*4882a593Smuzhiyun 			/* don't print this message for mpid */
196*4882a593Smuzhiyun 			if (getpid() != mpid)
197*4882a593Smuzhiyun 				ksft_test_result_pass("Passed\n");
198*4882a593Smuzhiyun 		}
199*4882a593Smuzhiyun 		return false;
200*4882a593Smuzhiyun 	} else {
201*4882a593Smuzhiyun 		ksft_exit_fail_msg("fork - %s\n", strerror(errno));
202*4882a593Smuzhiyun 		return false;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
exec_other_validate_cap(const char * name,bool eff,bool perm,bool inh,bool ambient)206*4882a593Smuzhiyun static void exec_other_validate_cap(const char *name,
207*4882a593Smuzhiyun 				    bool eff, bool perm, bool inh, bool ambient)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	execl(name, name, (eff ? "1" : "0"),
210*4882a593Smuzhiyun 	      (perm ? "1" : "0"), (inh ? "1" : "0"), (ambient ? "1" : "0"),
211*4882a593Smuzhiyun 	      NULL);
212*4882a593Smuzhiyun 	ksft_exit_fail_msg("execl - %s\n", strerror(errno));
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
exec_validate_cap(bool eff,bool perm,bool inh,bool ambient)215*4882a593Smuzhiyun static void exec_validate_cap(bool eff, bool perm, bool inh, bool ambient)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	exec_other_validate_cap("./validate_cap", eff, perm, inh, ambient);
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
do_tests(int uid,const char * our_path)220*4882a593Smuzhiyun static int do_tests(int uid, const char *our_path)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	bool have_outer_privilege = create_and_enter_ns(uid);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	int ourpath_fd = open(our_path, O_RDONLY | O_DIRECTORY);
225*4882a593Smuzhiyun 	if (ourpath_fd == -1)
226*4882a593Smuzhiyun 		ksft_exit_fail_msg("open '%s' - %s\n",
227*4882a593Smuzhiyun 					our_path, strerror(errno));
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	chdir_to_tmpfs();
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	copy_fromat_to(ourpath_fd, "validate_cap", "validate_cap");
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	if (have_outer_privilege) {
234*4882a593Smuzhiyun 		uid_t gid = getegid();
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 		copy_fromat_to(ourpath_fd, "validate_cap",
237*4882a593Smuzhiyun 			       "validate_cap_suidroot");
238*4882a593Smuzhiyun 		if (chown("validate_cap_suidroot", 0, -1) != 0)
239*4882a593Smuzhiyun 			ksft_exit_fail_msg("chown - %s\n", strerror(errno));
240*4882a593Smuzhiyun 		if (chmod("validate_cap_suidroot", S_ISUID | 0700) != 0)
241*4882a593Smuzhiyun 			ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 		copy_fromat_to(ourpath_fd, "validate_cap",
244*4882a593Smuzhiyun 			       "validate_cap_suidnonroot");
245*4882a593Smuzhiyun 		if (chown("validate_cap_suidnonroot", uid + 1, -1) != 0)
246*4882a593Smuzhiyun 			ksft_exit_fail_msg("chown - %s\n", strerror(errno));
247*4882a593Smuzhiyun 		if (chmod("validate_cap_suidnonroot", S_ISUID | 0700) != 0)
248*4882a593Smuzhiyun 			ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 		copy_fromat_to(ourpath_fd, "validate_cap",
251*4882a593Smuzhiyun 			       "validate_cap_sgidroot");
252*4882a593Smuzhiyun 		if (chown("validate_cap_sgidroot", -1, 0) != 0)
253*4882a593Smuzhiyun 			ksft_exit_fail_msg("chown - %s\n", strerror(errno));
254*4882a593Smuzhiyun 		if (chmod("validate_cap_sgidroot", S_ISGID | 0710) != 0)
255*4882a593Smuzhiyun 			ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		copy_fromat_to(ourpath_fd, "validate_cap",
258*4882a593Smuzhiyun 			       "validate_cap_sgidnonroot");
259*4882a593Smuzhiyun 		if (chown("validate_cap_sgidnonroot", -1, gid + 1) != 0)
260*4882a593Smuzhiyun 			ksft_exit_fail_msg("chown - %s\n", strerror(errno));
261*4882a593Smuzhiyun 		if (chmod("validate_cap_sgidnonroot", S_ISGID | 0710) != 0)
262*4882a593Smuzhiyun 			ksft_exit_fail_msg("chmod - %s\n", strerror(errno));
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	capng_get_caps_process();
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	/* Make sure that i starts out clear */
268*4882a593Smuzhiyun 	capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
269*4882a593Smuzhiyun 	if (capng_apply(CAPNG_SELECT_CAPS) != 0)
270*4882a593Smuzhiyun 		ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (uid == 0) {
273*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tRoot => ep\n");
274*4882a593Smuzhiyun 		if (fork_wait())
275*4882a593Smuzhiyun 			exec_validate_cap(true, true, false, false);
276*4882a593Smuzhiyun 	} else {
277*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tNon-root => no caps\n");
278*4882a593Smuzhiyun 		if (fork_wait())
279*4882a593Smuzhiyun 			exec_validate_cap(false, false, false, false);
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	ksft_print_msg("Check cap_ambient manipulation rules\n");
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* We should not be able to add ambient caps yet. */
285*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != -1 || errno != EPERM) {
286*4882a593Smuzhiyun 		if (errno == EINVAL)
287*4882a593Smuzhiyun 			ksft_test_result_fail(
288*4882a593Smuzhiyun 				"PR_CAP_AMBIENT_RAISE isn't supported\n");
289*4882a593Smuzhiyun 		else
290*4882a593Smuzhiyun 			ksft_test_result_fail(
291*4882a593Smuzhiyun 				"PR_CAP_AMBIENT_RAISE should have failed eith EPERM on a non-inheritable cap\n");
292*4882a593Smuzhiyun 		return 1;
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 	ksft_test_result_pass(
295*4882a593Smuzhiyun 		"PR_CAP_AMBIENT_RAISE failed on non-inheritable cap\n");
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_RAW);
298*4882a593Smuzhiyun 	capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_NET_RAW);
299*4882a593Smuzhiyun 	capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_NET_RAW);
300*4882a593Smuzhiyun 	if (capng_apply(CAPNG_SELECT_CAPS) != 0)
301*4882a593Smuzhiyun 		ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
302*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0, 0) != -1 || errno != EPERM) {
303*4882a593Smuzhiyun 		ksft_test_result_fail(
304*4882a593Smuzhiyun 			"PR_CAP_AMBIENT_RAISE should have failed on a non-permitted cap\n");
305*4882a593Smuzhiyun 		return 1;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 	ksft_test_result_pass(
308*4882a593Smuzhiyun 		"PR_CAP_AMBIENT_RAISE failed on non-permitted cap\n");
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
311*4882a593Smuzhiyun 	if (capng_apply(CAPNG_SELECT_CAPS) != 0)
312*4882a593Smuzhiyun 		ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
313*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) {
314*4882a593Smuzhiyun 		ksft_test_result_fail(
315*4882a593Smuzhiyun 			"PR_CAP_AMBIENT_RAISE should have succeeded\n");
316*4882a593Smuzhiyun 		return 1;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 	ksft_test_result_pass("PR_CAP_AMBIENT_RAISE worked\n");
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 1) {
321*4882a593Smuzhiyun 		ksft_test_result_fail("PR_CAP_AMBIENT_IS_SET is broken\n");
322*4882a593Smuzhiyun 		return 1;
323*4882a593Smuzhiyun 	}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0) != 0)
326*4882a593Smuzhiyun 		ksft_exit_fail_msg("PR_CAP_AMBIENT_CLEAR_ALL - %s\n",
327*4882a593Smuzhiyun 					strerror(errno));
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) {
330*4882a593Smuzhiyun 		ksft_test_result_fail(
331*4882a593Smuzhiyun 			"PR_CAP_AMBIENT_CLEAR_ALL didn't work\n");
332*4882a593Smuzhiyun 		return 1;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0)
336*4882a593Smuzhiyun 		ksft_exit_fail_msg("PR_CAP_AMBIENT_RAISE - %s\n",
337*4882a593Smuzhiyun 					strerror(errno));
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
340*4882a593Smuzhiyun 	if (capng_apply(CAPNG_SELECT_CAPS) != 0)
341*4882a593Smuzhiyun 		ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) {
344*4882a593Smuzhiyun 		ksft_test_result_fail("Dropping I should have dropped A\n");
345*4882a593Smuzhiyun 		return 1;
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	ksft_test_result_pass("Basic manipulation appears to work\n");
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE);
351*4882a593Smuzhiyun 	if (capng_apply(CAPNG_SELECT_CAPS) != 0)
352*4882a593Smuzhiyun 		ksft_exit_fail_msg("capng_apply - %s\n", strerror(errno));
353*4882a593Smuzhiyun 	if (uid == 0) {
354*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tRoot +i => eip\n");
355*4882a593Smuzhiyun 		if (fork_wait())
356*4882a593Smuzhiyun 			exec_validate_cap(true, true, true, false);
357*4882a593Smuzhiyun 	} else {
358*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tNon-root +i => i\n");
359*4882a593Smuzhiyun 		if (fork_wait())
360*4882a593Smuzhiyun 			exec_validate_cap(false, false, true, false);
361*4882a593Smuzhiyun 	}
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0)
364*4882a593Smuzhiyun 		ksft_exit_fail_msg("PR_CAP_AMBIENT_RAISE - %s\n",
365*4882a593Smuzhiyun 					strerror(errno));
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	ksft_print_msg("[RUN]\tUID %d +ia => eipa\n", uid);
368*4882a593Smuzhiyun 	if (fork_wait())
369*4882a593Smuzhiyun 		exec_validate_cap(true, true, true, true);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	/* The remaining tests need real privilege */
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	if (!have_outer_privilege) {
374*4882a593Smuzhiyun 		ksft_test_result_skip("SUID/SGID tests (needs privilege)\n");
375*4882a593Smuzhiyun 		goto done;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (uid == 0) {
379*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tRoot +ia, suidroot => eipa\n");
380*4882a593Smuzhiyun 		if (fork_wait())
381*4882a593Smuzhiyun 			exec_other_validate_cap("./validate_cap_suidroot",
382*4882a593Smuzhiyun 						true, true, true, true);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tRoot +ia, suidnonroot => ip\n");
385*4882a593Smuzhiyun 		if (fork_wait())
386*4882a593Smuzhiyun 			exec_other_validate_cap("./validate_cap_suidnonroot",
387*4882a593Smuzhiyun 						false, true, true, false);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tRoot +ia, sgidroot => eipa\n");
390*4882a593Smuzhiyun 		if (fork_wait())
391*4882a593Smuzhiyun 			exec_other_validate_cap("./validate_cap_sgidroot",
392*4882a593Smuzhiyun 						true, true, true, true);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 		if (fork_wait()) {
395*4882a593Smuzhiyun 			ksft_print_msg(
396*4882a593Smuzhiyun 				"[RUN]\tRoot, gid != 0, +ia, sgidroot => eip\n");
397*4882a593Smuzhiyun 			if (setresgid(1, 1, 1) != 0)
398*4882a593Smuzhiyun 				ksft_exit_fail_msg("setresgid - %s\n",
399*4882a593Smuzhiyun 							strerror(errno));
400*4882a593Smuzhiyun 			exec_other_validate_cap("./validate_cap_sgidroot",
401*4882a593Smuzhiyun 						true, true, true, false);
402*4882a593Smuzhiyun 		}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tRoot +ia, sgidnonroot => eip\n");
405*4882a593Smuzhiyun 		if (fork_wait())
406*4882a593Smuzhiyun 			exec_other_validate_cap("./validate_cap_sgidnonroot",
407*4882a593Smuzhiyun 						true, true, true, false);
408*4882a593Smuzhiyun 	} else {
409*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\tNon-root +ia, sgidnonroot => i\n");
410*4882a593Smuzhiyun 		if (fork_wait())
411*4882a593Smuzhiyun 			exec_other_validate_cap("./validate_cap_sgidnonroot",
412*4882a593Smuzhiyun 					false, false, true, false);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 		if (fork_wait()) {
415*4882a593Smuzhiyun 			ksft_print_msg("[RUN]\tNon-root +ia, sgidroot => i\n");
416*4882a593Smuzhiyun 			if (setresgid(1, 1, 1) != 0)
417*4882a593Smuzhiyun 				ksft_exit_fail_msg("setresgid - %s\n",
418*4882a593Smuzhiyun 							strerror(errno));
419*4882a593Smuzhiyun 			exec_other_validate_cap("./validate_cap_sgidroot",
420*4882a593Smuzhiyun 						false, false, true, false);
421*4882a593Smuzhiyun 		}
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun done:
425*4882a593Smuzhiyun 	ksft_print_cnts();
426*4882a593Smuzhiyun 	return nerrs ? 1 : 0;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
main(int argc,char ** argv)429*4882a593Smuzhiyun int main(int argc, char **argv)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun 	char *tmp1, *tmp2, *our_path;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	/* Find our path */
434*4882a593Smuzhiyun 	tmp1 = strdup(argv[0]);
435*4882a593Smuzhiyun 	if (!tmp1)
436*4882a593Smuzhiyun 		ksft_exit_fail_msg("strdup - %s\n", strerror(errno));
437*4882a593Smuzhiyun 	tmp2 = dirname(tmp1);
438*4882a593Smuzhiyun 	our_path = strdup(tmp2);
439*4882a593Smuzhiyun 	if (!our_path)
440*4882a593Smuzhiyun 		ksft_exit_fail_msg("strdup - %s\n", strerror(errno));
441*4882a593Smuzhiyun 	free(tmp1);
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	mpid = getpid();
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	if (fork_wait()) {
446*4882a593Smuzhiyun 		ksft_print_header();
447*4882a593Smuzhiyun 		ksft_set_plan(12);
448*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\t+++ Tests with uid == 0 +++\n");
449*4882a593Smuzhiyun 		return do_tests(0, our_path);
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	ksft_print_msg("==================================================\n");
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (fork_wait()) {
455*4882a593Smuzhiyun 		ksft_print_header();
456*4882a593Smuzhiyun 		ksft_set_plan(9);
457*4882a593Smuzhiyun 		ksft_print_msg("[RUN]\t+++ Tests with uid != 0 +++\n");
458*4882a593Smuzhiyun 		return do_tests(1, our_path);
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	return nerrs ? 1 : 0;
462*4882a593Smuzhiyun }
463