Linux Audio

Check our new training course

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