1 #define _GNU_SOURCE 2 #include <sched.h> 3 #include <unistd.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <signal.h> 7 #include <errno.h> 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 #include <fcntl.h> 11 #include <sys/ioctl.h> 12 #include <sys/prctl.h> 13 #include <sys/wait.h> 14 15 #define NSIO 0xb7 16 #define NS_GET_USERNS _IO(NSIO, 0x1) 17 18 #define pr_err(fmt, ...) \ 19 ({ \ 20 fprintf(stderr, "%s:%d:" fmt ": %m\n", \ 21 __func__, __LINE__, ##__VA_ARGS__); \ 22 1; \ 23 }) 24 25 int main(int argc, char *argvp[]) 26 { 27 int pfd[2], ns, uns, init_uns; 28 struct stat st1, st2; 29 char path[128]; 30 pid_t pid; 31 char c; 32 33 if (pipe(pfd)) 34 return 1; 35 36 pid = fork(); 37 if (pid < 0) 38 return pr_err("fork"); 39 if (pid == 0) { 40 prctl(PR_SET_PDEATHSIG, SIGKILL); 41 if (unshare(CLONE_NEWUTS | CLONE_NEWUSER)) 42 return pr_err("unshare"); 43 close(pfd[0]); 44 close(pfd[1]); 45 while (1) 46 sleep(1); 47 return 0; 48 } 49 close(pfd[1]); 50 if (read(pfd[0], &c, 1) != 0) 51 return pr_err("Unable to read from pipe"); 52 close(pfd[0]); 53 54 snprintf(path, sizeof(path), "/proc/%d/ns/uts", pid); 55 ns = open(path, O_RDONLY); 56 if (ns < 0) 57 return pr_err("Unable to open %s", path); 58 59 uns = ioctl(ns, NS_GET_USERNS); 60 if (uns < 0) 61 return pr_err("Unable to get an owning user namespace"); 62 63 if (fstat(uns, &st1)) 64 return pr_err("fstat"); 65 66 snprintf(path, sizeof(path), "/proc/%d/ns/user", pid); 67 if (stat(path, &st2)) 68 return pr_err("stat"); 69 70 if (st1.st_ino != st2.st_ino) 71 return pr_err("NS_GET_USERNS returned a wrong namespace"); 72 73 init_uns = ioctl(uns, NS_GET_USERNS); 74 if (uns < 0) 75 return pr_err("Unable to get an owning user namespace"); 76 77 if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM) 78 return pr_err("Don't get EPERM"); 79 80 if (unshare(CLONE_NEWUSER)) 81 return pr_err("unshare"); 82 83 if (ioctl(ns, NS_GET_USERNS) >= 0 || errno != EPERM) 84 return pr_err("Don't get EPERM"); 85 if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM) 86 return pr_err("Don't get EPERM"); 87 88 kill(pid, SIGKILL); 89 wait(NULL); 90 return 0; 91 } 92