owner.c (2022B)
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 26int 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}