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 * 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"
45 #include "linux_syscall_numbers.h"
46 #include "safe_macros.h"
47
48 #define CHILD_STACK_SIZE (1024*1024)
49 #define CP "(child) "
50 char *TCID = "setns02";
51
52 #if defined(__NR_setns) && defined(CLONE_NEWIPC) && defined(CLONE_NEWUTS)
53 #include "setns.h"
54
55 static char *dummy_hostname = "setns_dummy_uts";
56 static int ns_ipc_fd;
57 static int ns_uts_fd;
58 static key_t ipc_key;
59 static int shmid;
60
61 static void setup(void);
62 static void cleanup(void);
63
do_child_newuts(void * arg)64 static 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
do_child_newipc(void * arg)105 static 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
test_flag(int clone_flag,int ns_flag,int (* fn)(void * arg))137 static 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
main(int argc,char * argv[])162 int main(int argc, char *argv[])
163 {
164 int lc;
165
166 tst_parse_opts(argc, argv, NULL, NULL);
167
168 setup();
169 for (lc = 0; TEST_LOOPING(lc); lc++) {
170 if (ns_uts_fd != -1) {
171 tst_resm(TINFO, "test_newuts");
172 test_flag(CLONE_NEWUTS, CLONE_NEWUTS, do_child_newuts);
173 test_flag(CLONE_NEWUTS, 0, do_child_newuts);
174 }
175 if (ns_ipc_fd != -1) {
176 tst_resm(TINFO, "test_newipc");
177 test_flag(CLONE_NEWIPC, CLONE_NEWIPC, do_child_newipc);
178 test_flag(CLONE_NEWIPC, 0, do_child_newipc);
179 }
180 }
181 cleanup();
182 tst_exit();
183 }
184
setup(void)185 static void setup(void)
186 {
187 char tmp[PATH_MAX];
188
189 tst_require_root();
190
191 /* runtime check if syscall is supported */
192 ltp_syscall(__NR_setns, -1, 0);
193
194 /* check if kernel has CONFIG_*_NS set and exports /proc entries */
195 ns_ipc_fd = get_ns_fd(getpid(), "ipc");
196 ns_uts_fd = get_ns_fd(getpid(), "uts");
197 if (ns_ipc_fd == -1 && ns_uts_fd == -1)
198 tst_brkm(TCONF, NULL, "your kernel has CONFIG_IPC_NS, "
199 "CONFIG_UTS_NS or CONFIG_PROC disabled");
200
201 if (getcwd(tmp, PATH_MAX) == NULL)
202 tst_brkm(TBROK|TERRNO, NULL, "getcwd");
203 ipc_key = ftok(tmp, 65);
204 shmid = shmget(ipc_key, getpagesize(), IPC_CREAT | 0666);
205 if (shmid == -1)
206 tst_brkm(TBROK|TERRNO, NULL, "shmget");
207
208 TEST_PAUSE;
209 }
210
cleanup(void)211 static void cleanup(void)
212 {
213 if (ns_ipc_fd != -1)
214 close(ns_ipc_fd);
215 if (ns_uts_fd != -1)
216 close(ns_uts_fd);
217
218 shmctl(shmid, IPC_RMID, NULL);
219 }
220 #else
main(int argc,char * argv[])221 int main(int argc, char *argv[])
222 {
223 tst_brkm(TCONF, NULL, "__NR_setns, CLONE_NEWIPC or CLONE_NEWUTS "
224 " is not defined on your system.");
225 }
226 #endif
227