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