162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#define _GNU_SOURCE
362306a36Sopenharmony_ci#include <sched.h>
462306a36Sopenharmony_ci#include <unistd.h>
562306a36Sopenharmony_ci#include <stdio.h>
662306a36Sopenharmony_ci#include <stdlib.h>
762306a36Sopenharmony_ci#include <signal.h>
862306a36Sopenharmony_ci#include <errno.h>
962306a36Sopenharmony_ci#include <sys/types.h>
1062306a36Sopenharmony_ci#include <sys/stat.h>
1162306a36Sopenharmony_ci#include <fcntl.h>
1262306a36Sopenharmony_ci#include <sys/ioctl.h>
1362306a36Sopenharmony_ci#include <sys/prctl.h>
1462306a36Sopenharmony_ci#include <sys/wait.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define NSIO    0xb7
1762306a36Sopenharmony_ci#define NS_GET_USERNS   _IO(NSIO, 0x1)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define pr_err(fmt, ...) \
2062306a36Sopenharmony_ci		({ \
2162306a36Sopenharmony_ci			fprintf(stderr, "%s:%d:" fmt ": %m\n", \
2262306a36Sopenharmony_ci				__func__, __LINE__, ##__VA_ARGS__); \
2362306a36Sopenharmony_ci			1; \
2462306a36Sopenharmony_ci		})
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciint main(int argc, char *argvp[])
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	int pfd[2], ns, uns, init_uns;
2962306a36Sopenharmony_ci	struct stat st1, st2;
3062306a36Sopenharmony_ci	char path[128];
3162306a36Sopenharmony_ci	pid_t pid;
3262306a36Sopenharmony_ci	char c;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (pipe(pfd))
3562306a36Sopenharmony_ci		return 1;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	pid = fork();
3862306a36Sopenharmony_ci	if (pid < 0)
3962306a36Sopenharmony_ci		return pr_err("fork");
4062306a36Sopenharmony_ci	if (pid == 0) {
4162306a36Sopenharmony_ci		prctl(PR_SET_PDEATHSIG, SIGKILL);
4262306a36Sopenharmony_ci		if (unshare(CLONE_NEWUTS | CLONE_NEWUSER))
4362306a36Sopenharmony_ci			return pr_err("unshare");
4462306a36Sopenharmony_ci		close(pfd[0]);
4562306a36Sopenharmony_ci		close(pfd[1]);
4662306a36Sopenharmony_ci		while (1)
4762306a36Sopenharmony_ci			sleep(1);
4862306a36Sopenharmony_ci		return 0;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci	close(pfd[1]);
5162306a36Sopenharmony_ci	if (read(pfd[0], &c, 1) != 0)
5262306a36Sopenharmony_ci		return pr_err("Unable to read from pipe");
5362306a36Sopenharmony_ci	close(pfd[0]);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	snprintf(path, sizeof(path), "/proc/%d/ns/uts", pid);
5662306a36Sopenharmony_ci	ns = open(path, O_RDONLY);
5762306a36Sopenharmony_ci	if (ns < 0)
5862306a36Sopenharmony_ci		return pr_err("Unable to open %s", path);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	uns = ioctl(ns, NS_GET_USERNS);
6162306a36Sopenharmony_ci	if (uns < 0)
6262306a36Sopenharmony_ci		return pr_err("Unable to get an owning user namespace");
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (fstat(uns, &st1))
6562306a36Sopenharmony_ci		return pr_err("fstat");
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
6862306a36Sopenharmony_ci	if (stat(path, &st2))
6962306a36Sopenharmony_ci		return pr_err("stat");
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (st1.st_ino != st2.st_ino)
7262306a36Sopenharmony_ci		return pr_err("NS_GET_USERNS returned a wrong namespace");
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	init_uns = ioctl(uns, NS_GET_USERNS);
7562306a36Sopenharmony_ci	if (uns < 0)
7662306a36Sopenharmony_ci		return pr_err("Unable to get an owning user namespace");
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM)
7962306a36Sopenharmony_ci		return pr_err("Don't get EPERM");
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (unshare(CLONE_NEWUSER))
8262306a36Sopenharmony_ci		return pr_err("unshare");
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (ioctl(ns, NS_GET_USERNS) >= 0 || errno != EPERM)
8562306a36Sopenharmony_ci		return pr_err("Don't get EPERM");
8662306a36Sopenharmony_ci	if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM)
8762306a36Sopenharmony_ci		return pr_err("Don't get EPERM");
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	kill(pid, SIGKILL);
9062306a36Sopenharmony_ci	wait(NULL);
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
93