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 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 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 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 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 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 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 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