18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#define _GNU_SOURCE
48c2ecf20Sopenharmony_ci#include <errno.h>
58c2ecf20Sopenharmony_ci#include <fcntl.h>
68c2ecf20Sopenharmony_ci#include <limits.h>
78c2ecf20Sopenharmony_ci#include <linux/types.h>
88c2ecf20Sopenharmony_ci#include <sched.h>
98c2ecf20Sopenharmony_ci#include <signal.h>
108c2ecf20Sopenharmony_ci#include <stdio.h>
118c2ecf20Sopenharmony_ci#include <stdlib.h>
128c2ecf20Sopenharmony_ci#include <string.h>
138c2ecf20Sopenharmony_ci#include <syscall.h>
148c2ecf20Sopenharmony_ci#include <sys/prctl.h>
158c2ecf20Sopenharmony_ci#include <sys/wait.h>
168c2ecf20Sopenharmony_ci#include <unistd.h>
178c2ecf20Sopenharmony_ci#include <sys/socket.h>
188c2ecf20Sopenharmony_ci#include <sys/stat.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "pidfd.h"
218c2ecf20Sopenharmony_ci#include "../clone3/clone3_selftests.h"
228c2ecf20Sopenharmony_ci#include "../kselftest_harness.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cienum {
258c2ecf20Sopenharmony_ci	PIDFD_NS_USER,
268c2ecf20Sopenharmony_ci	PIDFD_NS_MNT,
278c2ecf20Sopenharmony_ci	PIDFD_NS_PID,
288c2ecf20Sopenharmony_ci	PIDFD_NS_UTS,
298c2ecf20Sopenharmony_ci	PIDFD_NS_IPC,
308c2ecf20Sopenharmony_ci	PIDFD_NS_NET,
318c2ecf20Sopenharmony_ci	PIDFD_NS_CGROUP,
328c2ecf20Sopenharmony_ci	PIDFD_NS_PIDCLD,
338c2ecf20Sopenharmony_ci	PIDFD_NS_TIME,
348c2ecf20Sopenharmony_ci	PIDFD_NS_MAX
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ciconst struct ns_info {
388c2ecf20Sopenharmony_ci	const char *name;
398c2ecf20Sopenharmony_ci	int flag;
408c2ecf20Sopenharmony_ci} ns_info[] = {
418c2ecf20Sopenharmony_ci	[PIDFD_NS_USER]   = { "user",             CLONE_NEWUSER,   },
428c2ecf20Sopenharmony_ci	[PIDFD_NS_MNT]    = { "mnt",              CLONE_NEWNS,     },
438c2ecf20Sopenharmony_ci	[PIDFD_NS_PID]    = { "pid",              CLONE_NEWPID,    },
448c2ecf20Sopenharmony_ci	[PIDFD_NS_UTS]    = { "uts",              CLONE_NEWUTS,    },
458c2ecf20Sopenharmony_ci	[PIDFD_NS_IPC]    = { "ipc",              CLONE_NEWIPC,    },
468c2ecf20Sopenharmony_ci	[PIDFD_NS_NET]    = { "net",              CLONE_NEWNET,    },
478c2ecf20Sopenharmony_ci	[PIDFD_NS_CGROUP] = { "cgroup",           CLONE_NEWCGROUP, },
488c2ecf20Sopenharmony_ci	[PIDFD_NS_PIDCLD] = { "pid_for_children", 0,               },
498c2ecf20Sopenharmony_ci	[PIDFD_NS_TIME]	  = { "time",             CLONE_NEWTIME,   },
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciFIXTURE(current_nsset)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	pid_t pid;
558c2ecf20Sopenharmony_ci	int pidfd;
568c2ecf20Sopenharmony_ci	int nsfds[PIDFD_NS_MAX];
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	pid_t child_pid_exited;
598c2ecf20Sopenharmony_ci	int child_pidfd_exited;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	pid_t child_pid1;
628c2ecf20Sopenharmony_ci	int child_pidfd1;
638c2ecf20Sopenharmony_ci	int child_nsfds1[PIDFD_NS_MAX];
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	pid_t child_pid2;
668c2ecf20Sopenharmony_ci	int child_pidfd2;
678c2ecf20Sopenharmony_ci	int child_nsfds2[PIDFD_NS_MAX];
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int sys_waitid(int which, pid_t pid, int options)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	return syscall(__NR_waitid, which, pid, NULL, options, NULL);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cipid_t create_child(int *pidfd, unsigned flags)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct __clone_args args = {
788c2ecf20Sopenharmony_ci		.flags		= CLONE_PIDFD | flags,
798c2ecf20Sopenharmony_ci		.exit_signal	= SIGCHLD,
808c2ecf20Sopenharmony_ci		.pidfd		= ptr_to_u64(pidfd),
818c2ecf20Sopenharmony_ci	};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return sys_clone3(&args, sizeof(struct clone_args));
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic bool switch_timens(void)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int fd, ret;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (unshare(CLONE_NEWTIME))
918c2ecf20Sopenharmony_ci		return false;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	fd = open("/proc/self/ns/time_for_children", O_RDONLY | O_CLOEXEC);
948c2ecf20Sopenharmony_ci	if (fd < 0)
958c2ecf20Sopenharmony_ci		return false;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	ret = setns(fd, CLONE_NEWTIME);
988c2ecf20Sopenharmony_ci	close(fd);
998c2ecf20Sopenharmony_ci	return ret == 0;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic ssize_t read_nointr(int fd, void *buf, size_t count)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	ssize_t ret;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	do {
1078c2ecf20Sopenharmony_ci		ret = read(fd, buf, count);
1088c2ecf20Sopenharmony_ci	} while (ret < 0 && errno == EINTR);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return ret;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic ssize_t write_nointr(int fd, const void *buf, size_t count)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	ssize_t ret;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	do {
1188c2ecf20Sopenharmony_ci		ret = write(fd, buf, count);
1198c2ecf20Sopenharmony_ci	} while (ret < 0 && errno == EINTR);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return ret;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ciFIXTURE_SETUP(current_nsset)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	int i, proc_fd, ret;
1278c2ecf20Sopenharmony_ci	int ipc_sockets[2];
1288c2ecf20Sopenharmony_ci	char c;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
1318c2ecf20Sopenharmony_ci		self->nsfds[i]		= -EBADF;
1328c2ecf20Sopenharmony_ci		self->child_nsfds1[i]	= -EBADF;
1338c2ecf20Sopenharmony_ci		self->child_nsfds2[i]	= -EBADF;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	proc_fd = open("/proc/self/ns", O_DIRECTORY | O_CLOEXEC);
1378c2ecf20Sopenharmony_ci	ASSERT_GE(proc_fd, 0) {
1388c2ecf20Sopenharmony_ci		TH_LOG("%m - Failed to open /proc/self/ns");
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	self->pid = getpid();
1428c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
1438c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
1448c2ecf20Sopenharmony_ci		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
1458c2ecf20Sopenharmony_ci		if (self->nsfds[i] < 0) {
1468c2ecf20Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
1478c2ecf20Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
1488c2ecf20Sopenharmony_ci				       info->name, self->pid);
1498c2ecf20Sopenharmony_ci			}
1508c2ecf20Sopenharmony_ci		}
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	self->pidfd = sys_pidfd_open(self->pid, 0);
1548c2ecf20Sopenharmony_ci	EXPECT_GT(self->pidfd, 0) {
1558c2ecf20Sopenharmony_ci		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* Create task that exits right away. */
1598c2ecf20Sopenharmony_ci	self->child_pid_exited = create_child(&self->child_pidfd_exited,
1608c2ecf20Sopenharmony_ci					      CLONE_NEWUSER | CLONE_NEWNET);
1618c2ecf20Sopenharmony_ci	EXPECT_GT(self->child_pid_exited, 0);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (self->child_pid_exited == 0)
1648c2ecf20Sopenharmony_ci		_exit(EXIT_SUCCESS);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED | WNOWAIT), 0);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	self->pidfd = sys_pidfd_open(self->pid, 0);
1698c2ecf20Sopenharmony_ci	EXPECT_GE(self->pidfd, 0) {
1708c2ecf20Sopenharmony_ci		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1748c2ecf20Sopenharmony_ci	EXPECT_EQ(ret, 0);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* Create tasks that will be stopped. */
1778c2ecf20Sopenharmony_ci	self->child_pid1 = create_child(&self->child_pidfd1,
1788c2ecf20Sopenharmony_ci					CLONE_NEWUSER | CLONE_NEWNS |
1798c2ecf20Sopenharmony_ci					CLONE_NEWCGROUP | CLONE_NEWIPC |
1808c2ecf20Sopenharmony_ci					CLONE_NEWUTS | CLONE_NEWPID |
1818c2ecf20Sopenharmony_ci					CLONE_NEWNET);
1828c2ecf20Sopenharmony_ci	EXPECT_GE(self->child_pid1, 0);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (self->child_pid1 == 0) {
1858c2ecf20Sopenharmony_ci		close(ipc_sockets[0]);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		if (!switch_timens())
1888c2ecf20Sopenharmony_ci			_exit(EXIT_FAILURE);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
1918c2ecf20Sopenharmony_ci			_exit(EXIT_FAILURE);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		close(ipc_sockets[1]);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		pause();
1968c2ecf20Sopenharmony_ci		_exit(EXIT_SUCCESS);
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	close(ipc_sockets[1]);
2008c2ecf20Sopenharmony_ci	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
2018c2ecf20Sopenharmony_ci	close(ipc_sockets[0]);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
2048c2ecf20Sopenharmony_ci	EXPECT_EQ(ret, 0);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	self->child_pid2 = create_child(&self->child_pidfd2,
2078c2ecf20Sopenharmony_ci					CLONE_NEWUSER | CLONE_NEWNS |
2088c2ecf20Sopenharmony_ci					CLONE_NEWCGROUP | CLONE_NEWIPC |
2098c2ecf20Sopenharmony_ci					CLONE_NEWUTS | CLONE_NEWPID |
2108c2ecf20Sopenharmony_ci					CLONE_NEWNET);
2118c2ecf20Sopenharmony_ci	EXPECT_GE(self->child_pid2, 0);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (self->child_pid2 == 0) {
2148c2ecf20Sopenharmony_ci		close(ipc_sockets[0]);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		if (!switch_timens())
2178c2ecf20Sopenharmony_ci			_exit(EXIT_FAILURE);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
2208c2ecf20Sopenharmony_ci			_exit(EXIT_FAILURE);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		close(ipc_sockets[1]);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		pause();
2258c2ecf20Sopenharmony_ci		_exit(EXIT_SUCCESS);
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	close(ipc_sockets[1]);
2298c2ecf20Sopenharmony_ci	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
2308c2ecf20Sopenharmony_ci	close(ipc_sockets[0]);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
2338c2ecf20Sopenharmony_ci		char p[100];
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
2388c2ecf20Sopenharmony_ci		if (self->nsfds[i] < 0) {
2398c2ecf20Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
2408c2ecf20Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
2418c2ecf20Sopenharmony_ci				       info->name, self->pid);
2428c2ecf20Sopenharmony_ci			}
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
2468c2ecf20Sopenharmony_ci			       self->child_pid1, info->name);
2478c2ecf20Sopenharmony_ci		EXPECT_GT(ret, 0);
2488c2ecf20Sopenharmony_ci		EXPECT_LT(ret, sizeof(p));
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		self->child_nsfds1[i] = open(p, O_RDONLY | O_CLOEXEC);
2518c2ecf20Sopenharmony_ci		if (self->child_nsfds1[i] < 0) {
2528c2ecf20Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
2538c2ecf20Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
2548c2ecf20Sopenharmony_ci				       info->name, self->child_pid1);
2558c2ecf20Sopenharmony_ci			}
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
2598c2ecf20Sopenharmony_ci			       self->child_pid2, info->name);
2608c2ecf20Sopenharmony_ci		EXPECT_GT(ret, 0);
2618c2ecf20Sopenharmony_ci		EXPECT_LT(ret, sizeof(p));
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		self->child_nsfds2[i] = open(p, O_RDONLY | O_CLOEXEC);
2648c2ecf20Sopenharmony_ci		if (self->child_nsfds2[i] < 0) {
2658c2ecf20Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
2668c2ecf20Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
2678c2ecf20Sopenharmony_ci				       info->name, self->child_pid1);
2688c2ecf20Sopenharmony_ci			}
2698c2ecf20Sopenharmony_ci		}
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	close(proc_fd);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ciFIXTURE_TEARDOWN(current_nsset)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int i;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd1,
2808c2ecf20Sopenharmony_ci					SIGKILL, NULL, 0), 0);
2818c2ecf20Sopenharmony_ci	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd2,
2828c2ecf20Sopenharmony_ci					SIGKILL, NULL, 0), 0);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
2858c2ecf20Sopenharmony_ci		if (self->nsfds[i] >= 0)
2868c2ecf20Sopenharmony_ci			close(self->nsfds[i]);
2878c2ecf20Sopenharmony_ci		if (self->child_nsfds1[i] >= 0)
2888c2ecf20Sopenharmony_ci			close(self->child_nsfds1[i]);
2898c2ecf20Sopenharmony_ci		if (self->child_nsfds2[i] >= 0)
2908c2ecf20Sopenharmony_ci			close(self->child_nsfds2[i]);
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (self->child_pidfd1 >= 0)
2948c2ecf20Sopenharmony_ci		EXPECT_EQ(0, close(self->child_pidfd1));
2958c2ecf20Sopenharmony_ci	if (self->child_pidfd2 >= 0)
2968c2ecf20Sopenharmony_ci		EXPECT_EQ(0, close(self->child_pidfd2));
2978c2ecf20Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED), 0);
2988c2ecf20Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid1, WEXITED), 0);
2998c2ecf20Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid2, WEXITED), 0);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int preserve_ns(const int pid, const char *ns)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	int ret;
3058c2ecf20Sopenharmony_ci	char path[50];
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	ret = snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns);
3088c2ecf20Sopenharmony_ci	if (ret < 0 || (size_t)ret >= sizeof(path))
3098c2ecf20Sopenharmony_ci		return -EIO;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return open(path, O_RDONLY | O_CLOEXEC);
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int in_same_namespace(int ns_fd1, pid_t pid2, const char *ns)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	int ns_fd2 = -EBADF;
3178c2ecf20Sopenharmony_ci	int ret = -1;
3188c2ecf20Sopenharmony_ci	struct stat ns_st1, ns_st2;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	ret = fstat(ns_fd1, &ns_st1);
3218c2ecf20Sopenharmony_ci	if (ret < 0)
3228c2ecf20Sopenharmony_ci		return -1;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	ns_fd2 = preserve_ns(pid2, ns);
3258c2ecf20Sopenharmony_ci	if (ns_fd2 < 0)
3268c2ecf20Sopenharmony_ci		return -1;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	ret = fstat(ns_fd2, &ns_st2);
3298c2ecf20Sopenharmony_ci	close(ns_fd2);
3308c2ecf20Sopenharmony_ci	if (ret < 0)
3318c2ecf20Sopenharmony_ci		return -1;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* processes are in the same namespace */
3348c2ecf20Sopenharmony_ci	if ((ns_st1.st_dev == ns_st2.st_dev) &&
3358c2ecf20Sopenharmony_ci	    (ns_st1.st_ino == ns_st2.st_ino))
3368c2ecf20Sopenharmony_ci		return 1;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/* processes are in different namespaces */
3398c2ecf20Sopenharmony_ci	return 0;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/* Test that we can't pass garbage to the kernel. */
3438c2ecf20Sopenharmony_ciTEST_F(current_nsset, invalid_flags)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, 0), 0);
3468c2ecf20Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, -1), 0);
3498c2ecf20Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, CLONE_VM), 0);
3528c2ecf20Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, CLONE_NEWUSER | CLONE_VM), 0);
3558c2ecf20Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci/* Test that we can't attach to a task that has already exited. */
3598c2ecf20Sopenharmony_ciTEST_F(current_nsset, pidfd_exited_child)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	int i;
3628c2ecf20Sopenharmony_ci	pid_t pid;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	ASSERT_NE(setns(self->child_pidfd_exited, CLONE_NEWUSER | CLONE_NEWNET),
3658c2ecf20Sopenharmony_ci		  0);
3668c2ecf20Sopenharmony_ci	EXPECT_EQ(errno, ESRCH);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	pid = getpid();
3698c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
3708c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
3718c2ecf20Sopenharmony_ci		/* Verify that we haven't changed any namespaces. */
3728c2ecf20Sopenharmony_ci		if (self->nsfds[i] >= 0)
3738c2ecf20Sopenharmony_ci			ASSERT_EQ(in_same_namespace(self->nsfds[i], pid, info->name), 1);
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ciTEST_F(current_nsset, pidfd_incremental_setns)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	int i;
3808c2ecf20Sopenharmony_ci	pid_t pid;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	pid = getpid();
3838c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
3848c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
3858c2ecf20Sopenharmony_ci		int nsfd;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
3888c2ecf20Sopenharmony_ci			continue;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		if (info->flag) {
3918c2ecf20Sopenharmony_ci			ASSERT_EQ(setns(self->child_pidfd1, info->flag), 0) {
3928c2ecf20Sopenharmony_ci				TH_LOG("%m - Failed to setns to %s namespace of %d via pidfd %d",
3938c2ecf20Sopenharmony_ci				       info->name, self->child_pid1,
3948c2ecf20Sopenharmony_ci				       self->child_pidfd1);
3958c2ecf20Sopenharmony_ci			}
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci		/* Verify that we have changed to the correct namespaces. */
3998c2ecf20Sopenharmony_ci		if (info->flag == CLONE_NEWPID)
4008c2ecf20Sopenharmony_ci			nsfd = self->nsfds[i];
4018c2ecf20Sopenharmony_ci		else
4028c2ecf20Sopenharmony_ci			nsfd = self->child_nsfds1[i];
4038c2ecf20Sopenharmony_ci		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
4048c2ecf20Sopenharmony_ci			TH_LOG("setns failed to place us correctly into %s namespace of %d via pidfd %d",
4058c2ecf20Sopenharmony_ci			       info->name, self->child_pid1,
4068c2ecf20Sopenharmony_ci			       self->child_pidfd1);
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci		TH_LOG("Managed to correctly setns to %s namespace of %d via pidfd %d",
4098c2ecf20Sopenharmony_ci		       info->name, self->child_pid1, self->child_pidfd1);
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ciTEST_F(current_nsset, nsfd_incremental_setns)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	int i;
4168c2ecf20Sopenharmony_ci	pid_t pid;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	pid = getpid();
4198c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
4208c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
4218c2ecf20Sopenharmony_ci		int nsfd;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
4248c2ecf20Sopenharmony_ci			continue;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		if (info->flag) {
4278c2ecf20Sopenharmony_ci			ASSERT_EQ(setns(self->child_nsfds1[i], info->flag), 0) {
4288c2ecf20Sopenharmony_ci				TH_LOG("%m - Failed to setns to %s namespace of %d via nsfd %d",
4298c2ecf20Sopenharmony_ci				       info->name, self->child_pid1,
4308c2ecf20Sopenharmony_ci				       self->child_nsfds1[i]);
4318c2ecf20Sopenharmony_ci			}
4328c2ecf20Sopenharmony_ci		}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		/* Verify that we have changed to the correct namespaces. */
4358c2ecf20Sopenharmony_ci		if (info->flag == CLONE_NEWPID)
4368c2ecf20Sopenharmony_ci			nsfd = self->nsfds[i];
4378c2ecf20Sopenharmony_ci		else
4388c2ecf20Sopenharmony_ci			nsfd = self->child_nsfds1[i];
4398c2ecf20Sopenharmony_ci		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
4408c2ecf20Sopenharmony_ci			TH_LOG("setns failed to place us correctly into %s namespace of %d via nsfd %d",
4418c2ecf20Sopenharmony_ci			       info->name, self->child_pid1,
4428c2ecf20Sopenharmony_ci			       self->child_nsfds1[i]);
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci		TH_LOG("Managed to correctly setns to %s namespace of %d via nsfd %d",
4458c2ecf20Sopenharmony_ci		       info->name, self->child_pid1, self->child_nsfds1[i]);
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ciTEST_F(current_nsset, pidfd_one_shot_setns)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	unsigned flags = 0;
4528c2ecf20Sopenharmony_ci	int i;
4538c2ecf20Sopenharmony_ci	pid_t pid;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
4568c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
4598c2ecf20Sopenharmony_ci			continue;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		flags |= info->flag;
4628c2ecf20Sopenharmony_ci		TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
4638c2ecf20Sopenharmony_ci		       info->name, self->child_pid1);
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
4678c2ecf20Sopenharmony_ci		TH_LOG("%m - Failed to setns to namespaces of %d",
4688c2ecf20Sopenharmony_ci		       self->child_pid1);
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	pid = getpid();
4728c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
4738c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
4748c2ecf20Sopenharmony_ci		int nsfd;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
4778c2ecf20Sopenharmony_ci			continue;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci		/* Verify that we have changed to the correct namespaces. */
4808c2ecf20Sopenharmony_ci		if (info->flag == CLONE_NEWPID)
4818c2ecf20Sopenharmony_ci			nsfd = self->nsfds[i];
4828c2ecf20Sopenharmony_ci		else
4838c2ecf20Sopenharmony_ci			nsfd = self->child_nsfds1[i];
4848c2ecf20Sopenharmony_ci		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
4858c2ecf20Sopenharmony_ci			TH_LOG("setns failed to place us correctly into %s namespace of %d",
4868c2ecf20Sopenharmony_ci			       info->name, self->child_pid1);
4878c2ecf20Sopenharmony_ci		}
4888c2ecf20Sopenharmony_ci		TH_LOG("Managed to correctly setns to %s namespace of %d",
4898c2ecf20Sopenharmony_ci		       info->name, self->child_pid1);
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ciTEST_F(current_nsset, no_foul_play)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	unsigned flags = 0;
4968c2ecf20Sopenharmony_ci	int i;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
4998c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
5028c2ecf20Sopenharmony_ci			continue;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		flags |= info->flag;
5058c2ecf20Sopenharmony_ci		if (info->flag) /* No use logging pid_for_children. */
5068c2ecf20Sopenharmony_ci			TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
5078c2ecf20Sopenharmony_ci			       info->name, self->child_pid1);
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
5118c2ecf20Sopenharmony_ci		TH_LOG("%m - Failed to setns to namespaces of %d vid pidfd %d",
5128c2ecf20Sopenharmony_ci		       self->child_pid1, self->child_pidfd1);
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/*
5168c2ecf20Sopenharmony_ci	 * Can't setns to a user namespace outside of our hierarchy since we
5178c2ecf20Sopenharmony_ci	 * don't have caps in there and didn't create it. That means that under
5188c2ecf20Sopenharmony_ci	 * no circumstances should we be able to setns to any of the other
5198c2ecf20Sopenharmony_ci	 * ones since they aren't owned by our user namespace.
5208c2ecf20Sopenharmony_ci	 */
5218c2ecf20Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
5228c2ecf20Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci		if (self->child_nsfds2[i] < 0 || !info->flag)
5258c2ecf20Sopenharmony_ci			continue;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci		ASSERT_NE(setns(self->child_pidfd2, info->flag), 0) {
5288c2ecf20Sopenharmony_ci			TH_LOG("Managed to setns to %s namespace of %d via pidfd %d",
5298c2ecf20Sopenharmony_ci			       info->name, self->child_pid2,
5308c2ecf20Sopenharmony_ci			       self->child_pidfd2);
5318c2ecf20Sopenharmony_ci		}
5328c2ecf20Sopenharmony_ci		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via pidfd %d",
5338c2ecf20Sopenharmony_ci		       info->name, self->child_pid2,
5348c2ecf20Sopenharmony_ci		       self->child_pidfd2);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		ASSERT_NE(setns(self->child_nsfds2[i], info->flag), 0) {
5378c2ecf20Sopenharmony_ci			TH_LOG("Managed to setns to %s namespace of %d via nsfd %d",
5388c2ecf20Sopenharmony_ci			       info->name, self->child_pid2,
5398c2ecf20Sopenharmony_ci			       self->child_nsfds2[i]);
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via nsfd %d",
5428c2ecf20Sopenharmony_ci		       info->name, self->child_pid2,
5438c2ecf20Sopenharmony_ci		       self->child_nsfds2[i]);
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ciTEST(setns_einval)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	int fd;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	fd = sys_memfd_create("rostock", 0);
5528c2ecf20Sopenharmony_ci	EXPECT_GT(fd, 0);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	ASSERT_NE(setns(fd, 0), 0);
5558c2ecf20Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
5568c2ecf20Sopenharmony_ci	close(fd);
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ciTEST_HARNESS_MAIN
560