blob: e0a50f89d38902f48eb2f6aa4fabbdbd6ecc7886 [file] [log] [blame]
Jan Stancek263f8b32013-02-18 15:05:17 +01001/*
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 * functional test for setns(2) - reassociate thread with a namespace
26 * 1. create child with CLONE_NEWUTS, set different hostname in child,
27 * set namespace back to parent ns and check that hostname has changed
28 * 2. create child with CLONE_NEWIPC, set up shared memory in parent
29 * and verify that child can't shmat it, then set namespace
30 * back to parent one and verify that child is able to do shmat
31 */
32#define _GNU_SOURCE
33#include <sys/ipc.h>
34#include <sys/shm.h>
35#include <sys/stat.h>
36#include <sys/syscall.h>
37#include <sys/types.h>
38#include <sys/utsname.h>
39#include <sys/wait.h>
40#include <errno.h>
41#include <sched.h>
42#include <string.h>
43#include "config.h"
44#include "test.h"
Jan Stancek263f8b32013-02-18 15:05:17 +010045#include "linux_syscall_numbers.h"
46#include "safe_macros.h"
47
48#define CHILD_STACK_SIZE (1024*1024)
49#define CP "(child) "
50char *TCID = "setns02";
51
52#if defined(__NR_setns) && defined(CLONE_NEWIPC) && defined(CLONE_NEWUTS)
53#include "setns.h"
54
55static char *dummy_hostname = "setns_dummy_uts";
56static int ns_ipc_fd;
57static int ns_uts_fd;
58static key_t ipc_key;
59static int shmid;
60
61static void setup(void);
62static void cleanup(void);
63
64static int do_child_newuts(void *arg)
65{
66 struct utsname uts, uts_parent;
67 int ns_flag = *(int *)arg;
68
69 if (uname(&uts_parent) == -1)
70 tst_resm(TFAIL|TERRNO, CP"uname");
71 tst_resm(TINFO, CP"hostname (inherited from parent): %s",
72 uts_parent.nodename);
73
74 if (sethostname(dummy_hostname, strlen(dummy_hostname)) == -1)
75 tst_resm(TFAIL|TERRNO, CP"sethostname");
76 if (uname(&uts) == -1)
77 tst_resm(TFAIL|TERRNO, CP"uname");
78
79 tst_resm(TINFO, CP"hostname changed to: %s", uts.nodename);
80 if (strcmp(uts_parent.nodename, uts.nodename) == 0) {
81 tst_resm(TFAIL, CP"expected hostname to be different");
82 return 1;
83 } else {
84 tst_resm(TPASS, CP"hostname is different in parent/child");
85 }
86
87 tst_resm(TINFO, CP"attempting to switch ns back to parent ns");
88 if (syscall(__NR_setns, ns_uts_fd, ns_flag) == -1) {
89 tst_resm(TFAIL|TERRNO, CP"setns");
90 return 2;
91 }
92 if (uname(&uts) == -1)
93 tst_resm(TFAIL|TERRNO, CP"uname");
94
95 tst_resm(TINFO, CP"hostname: %s", uts.nodename);
96 if (strcmp(uts_parent.nodename, uts.nodename) != 0) {
97 tst_resm(TFAIL, CP"expected hostname to match parent");
98 return 3;
99 } else {
100 tst_resm(TPASS, CP"hostname now as expected");
101 }
102 return 0;
103}
104
105static int do_child_newipc(void *arg)
106{
107 void *p;
108 int ns_flag = *(int *)arg;
109
110 p = shmat(shmid, NULL, 0);
111 if (p == (void *) -1) {
112 tst_resm(TPASS|TERRNO, CP"shmat failed as expected");
113 } else {
114 tst_resm(TFAIL, CP"shmat unexpectedly suceeded");
115 shmdt(p);
116 return 1;
117 }
118
119 tst_resm(TINFO, CP"attempting to switch ns back to parent ns");
120 if (syscall(__NR_setns, ns_ipc_fd, ns_flag) == -1) {
121 tst_resm(TFAIL|TERRNO, CP"setns");
122 return 2;
123 }
124
125 p = shmat(shmid, NULL, 0);
126 if (p == (void *) -1) {
127 tst_resm(TFAIL|TERRNO, CP"shmat failed after setns");
128 return 3;
129 } else {
130 tst_resm(TPASS, CP"shmat suceeded");
131 shmdt(p);
132 }
133
134 return 0;
135}
136
137static void test_flag(int clone_flag, int ns_flag, int (*fn) (void *arg))
138{
139 void *child_stack;
140 int ret, status;
141
142 child_stack = malloc(CHILD_STACK_SIZE);
143 if (child_stack == NULL)
144 tst_brkm(TBROK, cleanup, "Cannot allocate stack for child");
145
146 tst_resm(TINFO, "creating child with clone_flag=0x%x, ns_flag=0x%x",
147 clone_flag, ns_flag);
148 ret = ltp_clone(SIGCHLD|clone_flag, fn, &ns_flag,
149 CHILD_STACK_SIZE, child_stack);
150 if (ret == -1)
151 tst_brkm(TBROK|TERRNO, cleanup, "ltp_clone");
152
153 if (waitpid(ret, &status, 0) == -1)
154 tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
155 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
156 tst_resm(TFAIL, "child returns %d", status);
157 else
158 tst_resm(TPASS, "child finished succesfully");
159 free(child_stack);
160}
161
162int main(int argc, char *argv[])
163{
164 int lc;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +0200165 const char *msg;
Jan Stancek263f8b32013-02-18 15:05:17 +0100166
167 msg = parse_opts(argc, argv, NULL, NULL);
168 if (msg != NULL)
169 tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
170
171 setup();
172 for (lc = 0; TEST_LOOPING(lc); lc++) {
173 if (ns_uts_fd != -1) {
174 tst_resm(TINFO, "test_newuts");
175 test_flag(CLONE_NEWUTS, CLONE_NEWUTS, do_child_newuts);
176 test_flag(CLONE_NEWUTS, 0, do_child_newuts);
177 }
178 if (ns_ipc_fd != -1) {
179 tst_resm(TINFO, "test_newipc");
180 test_flag(CLONE_NEWIPC, CLONE_NEWIPC, do_child_newipc);
181 test_flag(CLONE_NEWIPC, 0, do_child_newipc);
182 }
183 }
184 cleanup();
185 tst_exit();
186}
187
188static void setup(void)
189{
190 char tmp[PATH_MAX];
191
192 tst_require_root(NULL);
193
194 /* runtime check if syscall is supported */
195 ltp_syscall(__NR_setns, -1, 0);
196
197 /* check if kernel has CONFIG_*_NS set and exports /proc entries */
198 ns_ipc_fd = get_ns_fd(getpid(), "ipc");
199 ns_uts_fd = get_ns_fd(getpid(), "uts");
200 if (ns_ipc_fd == -1 && ns_uts_fd == -1)
201 tst_brkm(TCONF, NULL, "your kernel has CONFIG_IPC_NS, "
202 "CONFIG_UTS_NS or CONFIG_PROC disabled");
203
204 if (getcwd(tmp, PATH_MAX) == NULL)
205 tst_brkm(TBROK|TERRNO, NULL, "getcwd");
206 ipc_key = ftok(tmp, 65);
207 shmid = shmget(ipc_key, getpagesize(), IPC_CREAT | 0666);
208 if (shmid == -1)
209 tst_brkm(TBROK|TERRNO, NULL, "shmget");
210
211 TEST_PAUSE;
212}
213
214static void cleanup(void)
215{
216 if (ns_ipc_fd != -1)
217 close(ns_ipc_fd);
218 if (ns_uts_fd != -1)
219 close(ns_uts_fd);
220
221 shmctl(shmid, IPC_RMID, NULL);
Jan Stancek263f8b32013-02-18 15:05:17 +0100222}
223#else
224int main(int argc, char *argv[])
225{
226 tst_brkm(TCONF, NULL, "__NR_setns, CLONE_NEWIPC or CLONE_NEWUTS "
227 " is not defined on your system.");
228}
229#endif