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