• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd., 2015
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  *  (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
11  * the GNU General Public License for more details.
12  */
13 
14 /*
15  * Verify that:
16  *  If a namespace isn't another namespace's ancestor, the process in
17  *  first namespace does not have the CAP_SYS_ADMIN capability in the
18  *  second namespace and the setns() call fails.
19  */
20 
21 #define _GNU_SOURCE
22 #include <sys/wait.h>
23 #include <assert.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include "userns_helper.h"
30 #include "test.h"
31 
32 char *TCID = "user_namespace4";
33 int TST_TOTAL = 1;
34 
setup(void)35 static void setup(void)
36 {
37 	check_newuser();
38 	ltp_syscall(__NR_setns, -1, 0);
39 	tst_tmpdir();
40 	TST_CHECKPOINT_INIT(NULL);
41 }
42 
cleanup(void)43 static void cleanup(void)
44 {
45 	tst_rmdir();
46 }
47 
child_fn1(void * arg LTP_ATTRIBUTE_UNUSED)48 static int child_fn1(void *arg LTP_ATTRIBUTE_UNUSED)
49 {
50 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
51 	return 0;
52 }
53 
child_fn2(void * arg)54 static int child_fn2(void *arg)
55 {
56 	int exit_val = 0;
57 	int ret;
58 
59 	ret = ltp_syscall(__NR_setns, ((long)arg), CLONE_NEWUSER);
60 	if (ret != -1) {
61 		printf("child2 setns() unexpected success\n");
62 		exit_val = 1;
63 	} else if (errno != EPERM) {
64 		printf("child2 setns() unexpected error: (%d) %s\n",
65 			errno, strerror(errno));
66 		exit_val = 1;
67 	}
68 
69 	TST_SAFE_CHECKPOINT_WAIT(NULL, 1);
70 	return exit_val;
71 }
72 
test_cap_sys_admin(void)73 static void test_cap_sys_admin(void)
74 {
75 	pid_t cpid1, cpid2, cpid3;
76 	char path[BUFSIZ];
77 	int fd;
78 
79 	/* child 1 */
80 	cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD,
81 		(void *)child_fn1, NULL);
82 	if (cpid1 < 0)
83 		tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
84 
85 	/* child 2 */
86 	sprintf(path, "/proc/%d/ns/user", cpid1);
87 	fd = SAFE_OPEN(cleanup, path, O_RDONLY, 0644);
88 	cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD,
89 		(void *)child_fn2, (void *)((long)fd));
90 	if (cpid2 < 0)
91 		tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
92 
93 	/* child 3 - throw-away process changing ns to child1 */
94 	switch (cpid3 = fork()) {
95 	case -1:
96 		tst_brkm(TBROK | TERRNO, cleanup, "fork");
97 	case 0:
98 		if (ltp_syscall(__NR_setns, fd, CLONE_NEWUSER) == -1) {
99 			printf("parent pid setns failure: (%d) %s",
100 				errno, strerror(errno));
101 			exit(1);
102 		}
103 		exit(0);
104 	}
105 
106 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 0);
107 	TST_SAFE_CHECKPOINT_WAKE(cleanup, 1);
108 
109 	tst_record_childstatus(cleanup, cpid1);
110 	tst_record_childstatus(cleanup, cpid2);
111 	tst_record_childstatus(cleanup, cpid3);
112 
113 	SAFE_CLOSE(cleanup, fd);
114 
115 }
116 
main(int argc,char * argv[])117 int main(int argc, char *argv[])
118 {
119 	int lc;
120 
121 	setup();
122 	tst_parse_opts(argc, argv, NULL, NULL);
123 
124 	for (lc = 0; TEST_LOOPING(lc); lc++) {
125 		tst_count = 0;
126 		test_cap_sys_admin();
127 	}
128 
129 	cleanup();
130 	tst_exit();
131 }
132