1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) Linux Test Project, 2014-2020 4 * 5 * functional test for setns(2) - reassociate thread with a namespace 6 * 1. create child with CLONE_NEWUTS, set different hostname in child, 7 * set namespace back to parent ns and check that hostname has changed 8 * 2. create child with CLONE_NEWIPC, set up shared memory in parent 9 * and verify that child can't shmat it, then set namespace 10 * back to parent one and verify that child is able to do shmat 11 */ 12#define _GNU_SOURCE 13#include <sys/ipc.h> 14#include <sys/shm.h> 15#include <sys/stat.h> 16#include <sys/types.h> 17#include <sys/utsname.h> 18#include <sys/wait.h> 19#include <errno.h> 20#include <sched.h> 21#include <stdlib.h> 22#include <string.h> 23#include "config.h" 24#include "tst_test.h" 25#include "tst_safe_sysv_ipc.h" 26#include "lapi/syscalls.h" 27#include "setns.h" 28 29#define CHILD_STACK_SIZE (1024*1024) 30#define CP "(child) " 31 32static char *dummy_hostname = "setns_dummy_uts"; 33static int ns_ipc_fd; 34static int ns_uts_fd; 35static key_t ipc_key; 36static int shmid; 37 38static void setup(void); 39static void cleanup(void); 40 41static int do_child_newuts(void *arg) 42{ 43 struct utsname uts, uts_parent; 44 int ns_flag = *(int *)arg; 45 46 if (uname(&uts_parent) == -1) 47 tst_res(TFAIL|TERRNO, CP"uname"); 48 tst_res(TINFO, CP"hostname (inherited from parent): %s", 49 uts_parent.nodename); 50 51 if (sethostname(dummy_hostname, strlen(dummy_hostname)) == -1) 52 tst_res(TFAIL|TERRNO, CP"sethostname"); 53 if (uname(&uts) == -1) 54 tst_res(TFAIL|TERRNO, CP"uname"); 55 56 tst_res(TINFO, CP"hostname changed to: %s", uts.nodename); 57 if (strcmp(uts_parent.nodename, uts.nodename) == 0) { 58 tst_res(TFAIL, CP"expected hostname to be different"); 59 return 1; 60 } else { 61 tst_res(TPASS, CP"hostname is different in parent/child"); 62 } 63 64 tst_res(TINFO, CP"attempting to switch ns back to parent ns"); 65 if (tst_syscall(__NR_setns, ns_uts_fd, ns_flag) == -1) { 66 tst_res(TFAIL|TERRNO, CP"setns"); 67 return 2; 68 } 69 if (uname(&uts) == -1) 70 tst_res(TFAIL|TERRNO, CP"uname"); 71 72 tst_res(TINFO, CP"hostname: %s", uts.nodename); 73 if (strcmp(uts_parent.nodename, uts.nodename) != 0) { 74 tst_res(TFAIL, CP"expected hostname to match parent"); 75 return 3; 76 } else { 77 tst_res(TPASS, CP"hostname now as expected"); 78 } 79 return 0; 80} 81 82static int do_child_newipc(void *arg) 83{ 84 void *p; 85 int ns_flag = *(int *)arg; 86 87 p = shmat(shmid, NULL, 0); 88 if (p == (void *) -1) { 89 tst_res(TPASS|TERRNO, CP"shmat failed as expected"); 90 } else { 91 tst_res(TFAIL, CP"shmat unexpectedly suceeded"); 92 shmdt(p); 93 return 1; 94 } 95 96 tst_res(TINFO, CP"attempting to switch ns back to parent ns"); 97 if (tst_syscall(__NR_setns, ns_ipc_fd, ns_flag) == -1) { 98 tst_res(TFAIL|TERRNO, CP"setns"); 99 return 2; 100 } 101 102 p = shmat(shmid, NULL, 0); 103 if (p == (void *) -1) { 104 tst_res(TFAIL|TERRNO, CP"shmat failed after setns"); 105 return 3; 106 } else { 107 tst_res(TPASS, CP"shmat suceeded"); 108 shmdt(p); 109 } 110 111 return 0; 112} 113 114static void test_flag(int clone_flag, int ns_flag, int (*fn) (void *arg)) 115{ 116 void *child_stack; 117 int ret, status; 118 119 child_stack = SAFE_MALLOC(CHILD_STACK_SIZE); 120 121 tst_res(TINFO, "creating child with clone_flag=0x%x, ns_flag=0x%x", 122 clone_flag, ns_flag); 123 ret = ltp_clone(SIGCHLD|clone_flag, fn, &ns_flag, 124 CHILD_STACK_SIZE, child_stack); 125 if (ret == -1) 126 tst_brk(TBROK|TERRNO, "ltp_clone"); 127 128 SAFE_WAITPID(ret, &status, 0); 129 free(child_stack); 130} 131 132void test_all(void) 133{ 134 if (ns_uts_fd != -1) { 135 tst_res(TINFO, "test_newuts"); 136 test_flag(CLONE_NEWUTS, CLONE_NEWUTS, do_child_newuts); 137 test_flag(CLONE_NEWUTS, 0, do_child_newuts); 138 } else 139 tst_res(TCONF, "CLONE_NEWUTS is not supported"); 140 141 if (ns_ipc_fd != -1) { 142 tst_res(TINFO, "test_newipc"); 143 test_flag(CLONE_NEWIPC, CLONE_NEWIPC, do_child_newipc); 144 test_flag(CLONE_NEWIPC, 0, do_child_newipc); 145 } else 146 tst_res(TCONF, "CLONE_NEWIPC is not supported"); 147} 148 149static void setup(void) 150{ 151 char tmp[PATH_MAX]; 152 153 /* runtime check if syscall is supported */ 154 tst_syscall(__NR_setns, -1, 0); 155 156 /* check if kernel has CONFIG_*_NS set and exports /proc entries */ 157 ns_ipc_fd = get_ns_fd(getpid(), "ipc"); 158 ns_uts_fd = get_ns_fd(getpid(), "uts"); 159 if (ns_ipc_fd == -1 && ns_uts_fd == -1) 160 tst_brk(TCONF, "your kernel has CONFIG_IPC_NS, " 161 "CONFIG_UTS_NS or CONFIG_PROC disabled"); 162 163 SAFE_GETCWD(tmp, PATH_MAX); 164 ipc_key = ftok(tmp, 65); 165 shmid = SAFE_SHMGET(ipc_key, getpagesize(), IPC_CREAT | 0666); 166} 167 168static void cleanup(void) 169{ 170 if (ns_ipc_fd != -1) 171 SAFE_CLOSE(ns_ipc_fd); 172 if (ns_uts_fd != -1) 173 SAFE_CLOSE(ns_uts_fd); 174 175 SAFE_SHMCTL(shmid, IPC_RMID, NULL); 176} 177 178static struct tst_test test = { 179 .test_all = test_all, 180 .setup = setup, 181 .cleanup = cleanup, 182 .needs_root = 1, 183}; 184