Home | History | Annotate | Download | only in nsfs
      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