1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Linux Test Project, 2014-2020
4 *
5 * errno tests for setns(2) - reassociate thread with a namespace
6 */
7 #define _GNU_SOURCE
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <errno.h>
11 #include <sched.h>
12 #include <pwd.h>
13 #include <string.h>
14 #include "config.h"
15 #include "tst_test.h"
16 #include "lapi/syscalls.h"
17 #include "setns.h"
18
19 static const char nobody_uid[] = "nobody";
20 static struct passwd *ltpuser;
21 static int regular_fd;
22
23 struct testcase_t {
24 const char *msg;
25 int fd;
26 int ns_type;
27 int exp_ret;
28 int exp_errno;
29 int skip;
30 void (*setup) (struct testcase_t *, int i);
31 void (*cleanup) (struct testcase_t *);
32 };
33
setup0(struct testcase_t * t,int i)34 static void setup0(struct testcase_t *t, int i)
35 {
36 t->ns_type = ns_types[i];
37 }
38
setup1(struct testcase_t * t,int i)39 static void setup1(struct testcase_t *t, int i)
40 {
41 t->ns_type = ns_types[i];
42 t->fd = regular_fd;
43 }
44
setup2(struct testcase_t * t,int i)45 static void setup2(struct testcase_t *t, int i)
46 {
47 t->fd = ns_fds[i];
48 }
49
setup3(struct testcase_t * t,int i)50 static void setup3(struct testcase_t *t, int i)
51 {
52 if (ns_total < 2) {
53 t->skip = 1;
54 return;
55 }
56
57 t->fd = ns_fds[i];
58 t->ns_type = ns_types[(i+1) % ns_total];
59 }
60
setup4(struct testcase_t * t,int i)61 static void setup4(struct testcase_t *t, int i)
62 {
63 SAFE_SETEUID(ltpuser->pw_uid);
64
65 t->fd = ns_fds[i];
66 t->ns_type = ns_types[i];
67 }
68
cleanup4(LTP_ATTRIBUTE_UNUSED struct testcase_t * t)69 static void cleanup4(LTP_ATTRIBUTE_UNUSED struct testcase_t *t)
70 {
71 SAFE_SETEUID(0);
72 }
73
74 static struct testcase_t tcases[] = {
75 {
76 .msg = "invalid fd",
77 .fd = -1,
78 .exp_ret = -1,
79 .exp_errno = EBADF,
80 .setup = setup0,
81 },
82 {
83 .msg = "regular file fd",
84 .exp_ret = -1,
85 .exp_errno = EINVAL,
86 .setup = setup1,
87 },
88 {
89 .msg = "invalid ns_type",
90 .ns_type = -1,
91 .exp_ret = -1,
92 .exp_errno = EINVAL,
93 .setup = setup2,
94 },
95 {
96 .msg = "mismatch ns_type/fd",
97 .exp_ret = -1,
98 .exp_errno = EINVAL,
99 .setup = setup3,
100 },
101 {
102 .msg = "without CAP_SYS_ADMIN",
103 .exp_ret = -1,
104 .exp_errno = EPERM,
105 .setup = setup4,
106 .cleanup = cleanup4,
107 }
108 };
109
test_setns(unsigned int testno)110 static void test_setns(unsigned int testno)
111 {
112 int ret, i;
113 struct testcase_t *t = &tcases[testno];
114
115 for (i = 0; i < ns_total; i++) {
116 if (t->setup)
117 t->setup(t, i);
118
119 if (t->skip) {
120 tst_res(TCONF, "skip %s", t->msg);
121 continue;
122 }
123
124 tst_res(TINFO, "setns(%d, 0x%x)", t->fd, t->ns_type);
125 ret = tst_syscall(__NR_setns, t->fd, t->ns_type);
126 if (ret == t->exp_ret) {
127 if (ret == -1 && errno == t->exp_errno) {
128 tst_res(TPASS, "%s exp_errno=%d (%s)",
129 t->msg, t->exp_errno,
130 tst_strerrno(t->exp_errno));
131 } else {
132 tst_res(TFAIL|TERRNO, "%s exp_errno=%d (%s)",
133 t->msg, t->exp_errno,
134 tst_strerrno(t->exp_errno));
135 }
136 } else {
137 tst_res(TFAIL, "%s ret=%d expected=%d",
138 t->msg, ret, t->exp_ret);
139 }
140
141 if (t->cleanup)
142 t->cleanup(t);
143 }
144 }
145
setup(void)146 static void setup(void)
147 {
148 /* runtime check if syscall is supported */
149 tst_syscall(__NR_setns, -1, 0);
150
151 init_available_ns();
152 if (ns_total == 0)
153 tst_brk(TCONF, "no ns types/proc entries");
154
155 ltpuser = SAFE_GETPWNAM(nobody_uid);
156 regular_fd = SAFE_OPEN("dummy", O_RDWR|O_CREAT, 0600);
157 SAFE_UNLINK("dummy");
158 }
159
cleanup(void)160 static void cleanup(void)
161 {
162 close_ns_fds();
163 if (regular_fd)
164 SAFE_CLOSE(regular_fd);
165 }
166
167 static struct tst_test test = {
168 .tcnt = ARRAY_SIZE(tcases),
169 .test = test_setns,
170 .setup = setup,
171 .cleanup = cleanup,
172 .needs_root = 1,
173 .needs_tmpdir = 1,
174 };
175
176