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