Linux Audio

Check our new training course

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