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 "lapi/syscalls.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 SAFE_WAITPID(cleanup, ret, &status, 0);
154 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
155 tst_resm(TFAIL, "child returns %d", status);
156 else
157 tst_resm(TPASS, "child finished succesfully");
158 free(child_stack);
159 }
160
main(int argc,char * argv[])161 int main(int argc, char *argv[])
162 {
163 int lc;
164
165 tst_parse_opts(argc, argv, NULL, NULL);
166
167 setup();
168 for (lc = 0; TEST_LOOPING(lc); lc++) {
169 if (ns_uts_fd != -1) {
170 tst_resm(TINFO, "test_newuts");
171 test_flag(CLONE_NEWUTS, CLONE_NEWUTS, do_child_newuts);
172 test_flag(CLONE_NEWUTS, 0, do_child_newuts);
173 }
174 if (ns_ipc_fd != -1) {
175 tst_resm(TINFO, "test_newipc");
176 test_flag(CLONE_NEWIPC, CLONE_NEWIPC, do_child_newipc);
177 test_flag(CLONE_NEWIPC, 0, do_child_newipc);
178 }
179 }
180 cleanup();
181 tst_exit();
182 }
183
setup(void)184 static void setup(void)
185 {
186 char tmp[PATH_MAX];
187
188 tst_require_root();
189
190 /* runtime check if syscall is supported */
191 ltp_syscall(__NR_setns, -1, 0);
192
193 /* check if kernel has CONFIG_*_NS set and exports /proc entries */
194 ns_ipc_fd = get_ns_fd(getpid(), "ipc");
195 ns_uts_fd = get_ns_fd(getpid(), "uts");
196 if (ns_ipc_fd == -1 && ns_uts_fd == -1)
197 tst_brkm(TCONF, NULL, "your kernel has CONFIG_IPC_NS, "
198 "CONFIG_UTS_NS or CONFIG_PROC disabled");
199
200 if (getcwd(tmp, PATH_MAX) == NULL)
201 tst_brkm(TBROK|TERRNO, NULL, "getcwd");
202 ipc_key = ftok(tmp, 65);
203 shmid = shmget(ipc_key, getpagesize(), IPC_CREAT | 0666);
204 if (shmid == -1)
205 tst_brkm(TBROK|TERRNO, NULL, "shmget");
206
207 TEST_PAUSE;
208 }
209
cleanup(void)210 static void cleanup(void)
211 {
212 if (ns_ipc_fd != -1)
213 close(ns_ipc_fd);
214 if (ns_uts_fd != -1)
215 close(ns_uts_fd);
216
217 shmctl(shmid, IPC_RMID, NULL);
218 }
219 #else
main(int argc,char * argv[])220 int main(int argc, char *argv[])
221 {
222 tst_brkm(TCONF, NULL, "__NR_setns, CLONE_NEWIPC or CLONE_NEWUTS "
223 " is not defined on your system.");
224 }
225 #endif
226