setns01.c revision 605fa3362fd7cef0baa2131be32cf44661783d3e
1/*
2 * Copyright (C) 2013 Linux Test Project, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public
6 * License as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it
13 * is free of the rightful claim of any third person regarding
14 * infringement or the like.  Any license provided herein, whether
15 * implied or otherwise, applies only to this software file.  Patent
16 * licenses, if any, provided herein do not apply to combinations of
17 * this program with other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24/*
25 * errno tests for setns(2) - reassociate thread with a namespace
26 */
27#define _GNU_SOURCE
28#include <sys/stat.h>
29#include <sys/syscall.h>
30#include <sys/types.h>
31#include <errno.h>
32#include <sched.h>
33#include <pwd.h>
34#include <string.h>
35#include "config.h"
36#include "test.h"
37#include "usctest.h"
38#include "linux_syscall_numbers.h"
39#include "safe_macros.h"
40
41char *TCID = "setns01";
42
43#if defined(__NR_setns)
44#include "setns.h"
45
46struct testcase_t {
47	const char *msg;
48	int fd;
49	int ns_type;
50	int exp_ret;
51	int exp_errno;
52	int skip;
53	void (*setup) (struct testcase_t *, int i);
54	void (*cleanup) (struct testcase_t *);
55};
56
57static void setup(void);
58static void cleanup(void);
59static void setup0(struct testcase_t *, int);
60static void setup1(struct testcase_t *, int);
61static void setup2(struct testcase_t *, int);
62static void setup3(struct testcase_t *, int);
63static void setup4(struct testcase_t *, int);
64static void cleanup1(struct testcase_t *);
65static void cleanup4(struct testcase_t *);
66
67struct testcase_t tdat[] = {
68	{
69		.msg = "invalid fd",
70		.fd = -1,
71		.exp_ret = -1,
72		.exp_errno = EBADF,
73		.setup = setup0,
74	},
75	{
76		.msg = "regular file fd",
77		.exp_ret = -1,
78		.exp_errno = EINVAL,
79		.setup = setup1,
80		.cleanup = cleanup1
81	},
82	{
83		.msg = "invalid ns_type",
84		.ns_type = -1,
85		.exp_ret = -1,
86		.exp_errno = EINVAL,
87		.setup = setup2,
88	},
89	{
90		.msg = "mismatch ns_type/fd",
91		.exp_ret = -1,
92		.exp_errno = EINVAL,
93		.setup = setup3,
94	},
95	{
96		.msg = "without CAP_SYS_ADMIN",
97		.exp_ret = -1,
98		.exp_errno = EPERM,
99		.setup = setup4,
100		.cleanup = cleanup4,
101	}
102};
103
104static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
105static const char nobody_uid[] = "nobody";
106static struct passwd *ltpuser;
107
108static void setup0(struct testcase_t *t, int i)
109{
110	t->ns_type = ns_types[i];
111}
112
113static void setup1(struct testcase_t *t, int i)
114{
115	t->ns_type = ns_types[i];
116	t->fd = open("dummy", O_RDWR|O_CREAT, 0600);
117	if (t->fd == -1)
118		tst_brkm(TFAIL|TERRNO, cleanup, "setup1:open failed");
119	unlink("dummy");
120}
121
122static void cleanup1(struct testcase_t *t)
123{
124	close(t->fd);
125}
126
127static void setup2(struct testcase_t *t, int i)
128{
129	t->fd = ns_fds[i];
130}
131
132static void setup3(struct testcase_t *t, int i)
133{
134	if (ns_total < 2) {
135		t->skip = 1;
136		return;
137	}
138
139	t->fd = ns_fds[i];
140	t->ns_type = ns_types[(i+1) % ns_total];
141}
142
143static void setup4(struct testcase_t *t, int i)
144{
145	if (seteuid(ltpuser->pw_uid) == -1)
146		tst_brkm(TBROK | TERRNO, NULL, "seteuid failed");
147
148	t->fd = ns_fds[i];
149	t->ns_type = ns_types[i];
150}
151
152static void cleanup4(struct testcase_t *t)
153{
154	if (seteuid(0) == -1)
155		tst_brkm(TBROK | TERRNO, NULL, "seteuid restore failed");
156}
157
158static void test_setns(struct testcase_t *t)
159{
160	int ret, i;
161
162	for (i = 0; i < ns_total; i++) {
163		if (t->setup)
164			t->setup(t, i);
165
166		if (t->skip) {
167			tst_resm(TINFO, "skip %s", tdat->msg);
168			continue;
169		}
170
171		tst_resm(TINFO, "setns(%d, 0x%x)", t->fd, t->ns_type);
172		ret = syscall(__NR_setns, t->fd, t->ns_type);
173		if (ret == t->exp_ret) {
174			if (ret == -1 && errno == t->exp_errno)
175				tst_resm(TPASS, "%s exp_errno=%d", t->msg,
176						t->exp_errno);
177			else
178				tst_resm(TFAIL|TERRNO, "%s exp_errno=%d",
179					t->msg, t->exp_errno);
180		} else {
181			tst_resm(TFAIL, "%s ret=%d expected=%d", t->msg,
182					ret, t->exp_ret);
183		}
184
185		if (t->cleanup)
186			t->cleanup(t);
187	}
188}
189
190int main(int argc, char *argv[])
191{
192	int lc, testno;
193	const char *msg;
194
195	msg = parse_opts(argc, argv, NULL, NULL);
196	if (msg != NULL)
197		tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
198
199	setup();
200	for (lc = 0; TEST_LOOPING(lc); lc++) {
201		for (testno = 0; testno < TST_TOTAL; testno++)
202			test_setns(&tdat[testno]);
203	}
204	cleanup();
205	tst_exit();
206}
207
208static void setup(void)
209{
210	tst_require_root(NULL);
211
212	/* runtime check if syscall is supported */
213	ltp_syscall(__NR_setns, -1, 0);
214
215	init_available_ns();
216	if (ns_total == 0)
217		tst_brkm(TCONF, NULL, "no ns types/proc entries");
218
219	ltpuser = getpwnam(nobody_uid);
220	if (ltpuser == NULL)
221		tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed");
222
223
224	tst_tmpdir();
225	TEST_PAUSE;
226}
227
228static void cleanup(void)
229{
230	close_ns_fds();
231	tst_rmdir();
232}
233#else
234int main(int argc, char *argv[])
235{
236	tst_brkm(TCONF, NULL, "__NR_setns is not defined on your system.");
237
238}
239#endif
240