162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#define _GNU_SOURCE
462306a36Sopenharmony_ci#include <errno.h>
562306a36Sopenharmony_ci#include <fcntl.h>
662306a36Sopenharmony_ci#include <limits.h>
762306a36Sopenharmony_ci#include <linux/types.h>
862306a36Sopenharmony_ci#include <sched.h>
962306a36Sopenharmony_ci#include <signal.h>
1062306a36Sopenharmony_ci#include <stdio.h>
1162306a36Sopenharmony_ci#include <stdlib.h>
1262306a36Sopenharmony_ci#include <string.h>
1362306a36Sopenharmony_ci#include <syscall.h>
1462306a36Sopenharmony_ci#include <sys/prctl.h>
1562306a36Sopenharmony_ci#include <sys/wait.h>
1662306a36Sopenharmony_ci#include <unistd.h>
1762306a36Sopenharmony_ci#include <sys/socket.h>
1862306a36Sopenharmony_ci#include <sys/stat.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "pidfd.h"
2162306a36Sopenharmony_ci#include "../clone3/clone3_selftests.h"
2262306a36Sopenharmony_ci#include "../kselftest_harness.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cienum {
2562306a36Sopenharmony_ci	PIDFD_NS_USER,
2662306a36Sopenharmony_ci	PIDFD_NS_MNT,
2762306a36Sopenharmony_ci	PIDFD_NS_PID,
2862306a36Sopenharmony_ci	PIDFD_NS_UTS,
2962306a36Sopenharmony_ci	PIDFD_NS_IPC,
3062306a36Sopenharmony_ci	PIDFD_NS_NET,
3162306a36Sopenharmony_ci	PIDFD_NS_CGROUP,
3262306a36Sopenharmony_ci	PIDFD_NS_PIDCLD,
3362306a36Sopenharmony_ci	PIDFD_NS_TIME,
3462306a36Sopenharmony_ci	PIDFD_NS_MAX
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciconst struct ns_info {
3862306a36Sopenharmony_ci	const char *name;
3962306a36Sopenharmony_ci	int flag;
4062306a36Sopenharmony_ci} ns_info[] = {
4162306a36Sopenharmony_ci	[PIDFD_NS_USER]   = { "user",             CLONE_NEWUSER,   },
4262306a36Sopenharmony_ci	[PIDFD_NS_MNT]    = { "mnt",              CLONE_NEWNS,     },
4362306a36Sopenharmony_ci	[PIDFD_NS_PID]    = { "pid",              CLONE_NEWPID,    },
4462306a36Sopenharmony_ci	[PIDFD_NS_UTS]    = { "uts",              CLONE_NEWUTS,    },
4562306a36Sopenharmony_ci	[PIDFD_NS_IPC]    = { "ipc",              CLONE_NEWIPC,    },
4662306a36Sopenharmony_ci	[PIDFD_NS_NET]    = { "net",              CLONE_NEWNET,    },
4762306a36Sopenharmony_ci	[PIDFD_NS_CGROUP] = { "cgroup",           CLONE_NEWCGROUP, },
4862306a36Sopenharmony_ci	[PIDFD_NS_PIDCLD] = { "pid_for_children", 0,               },
4962306a36Sopenharmony_ci	[PIDFD_NS_TIME]	  = { "time",             CLONE_NEWTIME,   },
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciFIXTURE(current_nsset)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	pid_t pid;
5562306a36Sopenharmony_ci	int pidfd;
5662306a36Sopenharmony_ci	int nsfds[PIDFD_NS_MAX];
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	pid_t child_pid_exited;
5962306a36Sopenharmony_ci	int child_pidfd_exited;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	pid_t child_pid1;
6262306a36Sopenharmony_ci	int child_pidfd1;
6362306a36Sopenharmony_ci	int child_nsfds1[PIDFD_NS_MAX];
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	pid_t child_pid2;
6662306a36Sopenharmony_ci	int child_pidfd2;
6762306a36Sopenharmony_ci	int child_nsfds2[PIDFD_NS_MAX];
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic int sys_waitid(int which, pid_t pid, int options)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	return syscall(__NR_waitid, which, pid, NULL, options, NULL);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cipid_t create_child(int *pidfd, unsigned flags)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct __clone_args args = {
7862306a36Sopenharmony_ci		.flags		= CLONE_PIDFD | flags,
7962306a36Sopenharmony_ci		.exit_signal	= SIGCHLD,
8062306a36Sopenharmony_ci		.pidfd		= ptr_to_u64(pidfd),
8162306a36Sopenharmony_ci	};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return sys_clone3(&args, sizeof(struct clone_args));
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic bool switch_timens(void)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	int fd, ret;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (unshare(CLONE_NEWTIME))
9162306a36Sopenharmony_ci		return false;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	fd = open("/proc/self/ns/time_for_children", O_RDONLY | O_CLOEXEC);
9462306a36Sopenharmony_ci	if (fd < 0)
9562306a36Sopenharmony_ci		return false;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ret = setns(fd, CLONE_NEWTIME);
9862306a36Sopenharmony_ci	close(fd);
9962306a36Sopenharmony_ci	return ret == 0;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic ssize_t read_nointr(int fd, void *buf, size_t count)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	ssize_t ret;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	do {
10762306a36Sopenharmony_ci		ret = read(fd, buf, count);
10862306a36Sopenharmony_ci	} while (ret < 0 && errno == EINTR);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return ret;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic ssize_t write_nointr(int fd, const void *buf, size_t count)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	ssize_t ret;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	do {
11862306a36Sopenharmony_ci		ret = write(fd, buf, count);
11962306a36Sopenharmony_ci	} while (ret < 0 && errno == EINTR);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return ret;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciFIXTURE_SETUP(current_nsset)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	int i, proc_fd, ret;
12762306a36Sopenharmony_ci	int ipc_sockets[2];
12862306a36Sopenharmony_ci	char c;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
13162306a36Sopenharmony_ci		self->nsfds[i]		= -EBADF;
13262306a36Sopenharmony_ci		self->child_nsfds1[i]	= -EBADF;
13362306a36Sopenharmony_ci		self->child_nsfds2[i]	= -EBADF;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	proc_fd = open("/proc/self/ns", O_DIRECTORY | O_CLOEXEC);
13762306a36Sopenharmony_ci	ASSERT_GE(proc_fd, 0) {
13862306a36Sopenharmony_ci		TH_LOG("%m - Failed to open /proc/self/ns");
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	self->pid = getpid();
14262306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
14362306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
14462306a36Sopenharmony_ci		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
14562306a36Sopenharmony_ci		if (self->nsfds[i] < 0) {
14662306a36Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
14762306a36Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
14862306a36Sopenharmony_ci				       info->name, self->pid);
14962306a36Sopenharmony_ci			}
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	self->pidfd = sys_pidfd_open(self->pid, 0);
15462306a36Sopenharmony_ci	EXPECT_GT(self->pidfd, 0) {
15562306a36Sopenharmony_ci		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Create task that exits right away. */
15962306a36Sopenharmony_ci	self->child_pid_exited = create_child(&self->child_pidfd_exited,
16062306a36Sopenharmony_ci					      CLONE_NEWUSER | CLONE_NEWNET);
16162306a36Sopenharmony_ci	EXPECT_GT(self->child_pid_exited, 0);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (self->child_pid_exited == 0)
16462306a36Sopenharmony_ci		_exit(EXIT_SUCCESS);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED | WNOWAIT), 0);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	self->pidfd = sys_pidfd_open(self->pid, 0);
16962306a36Sopenharmony_ci	EXPECT_GE(self->pidfd, 0) {
17062306a36Sopenharmony_ci		TH_LOG("%m - Failed to open pidfd for process %d", self->pid);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
17462306a36Sopenharmony_ci	EXPECT_EQ(ret, 0);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* Create tasks that will be stopped. */
17762306a36Sopenharmony_ci	self->child_pid1 = create_child(&self->child_pidfd1,
17862306a36Sopenharmony_ci					CLONE_NEWUSER | CLONE_NEWNS |
17962306a36Sopenharmony_ci					CLONE_NEWCGROUP | CLONE_NEWIPC |
18062306a36Sopenharmony_ci					CLONE_NEWUTS | CLONE_NEWPID |
18162306a36Sopenharmony_ci					CLONE_NEWNET);
18262306a36Sopenharmony_ci	EXPECT_GE(self->child_pid1, 0);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (self->child_pid1 == 0) {
18562306a36Sopenharmony_ci		close(ipc_sockets[0]);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		if (!switch_timens())
18862306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
19162306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		close(ipc_sockets[1]);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		pause();
19662306a36Sopenharmony_ci		_exit(EXIT_SUCCESS);
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	close(ipc_sockets[1]);
20062306a36Sopenharmony_ci	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
20162306a36Sopenharmony_ci	close(ipc_sockets[0]);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
20462306a36Sopenharmony_ci	EXPECT_EQ(ret, 0);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	self->child_pid2 = create_child(&self->child_pidfd2,
20762306a36Sopenharmony_ci					CLONE_NEWUSER | CLONE_NEWNS |
20862306a36Sopenharmony_ci					CLONE_NEWCGROUP | CLONE_NEWIPC |
20962306a36Sopenharmony_ci					CLONE_NEWUTS | CLONE_NEWPID |
21062306a36Sopenharmony_ci					CLONE_NEWNET);
21162306a36Sopenharmony_ci	EXPECT_GE(self->child_pid2, 0);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (self->child_pid2 == 0) {
21462306a36Sopenharmony_ci		close(ipc_sockets[0]);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		if (!switch_timens())
21762306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		if (write_nointr(ipc_sockets[1], "1", 1) < 0)
22062306a36Sopenharmony_ci			_exit(EXIT_FAILURE);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		close(ipc_sockets[1]);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		pause();
22562306a36Sopenharmony_ci		_exit(EXIT_SUCCESS);
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	close(ipc_sockets[1]);
22962306a36Sopenharmony_ci	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
23062306a36Sopenharmony_ci	close(ipc_sockets[0]);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
23362306a36Sopenharmony_ci		char p[100];
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		self->nsfds[i] = openat(proc_fd, info->name, O_RDONLY | O_CLOEXEC);
23862306a36Sopenharmony_ci		if (self->nsfds[i] < 0) {
23962306a36Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
24062306a36Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
24162306a36Sopenharmony_ci				       info->name, self->pid);
24262306a36Sopenharmony_ci			}
24362306a36Sopenharmony_ci		}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
24662306a36Sopenharmony_ci			       self->child_pid1, info->name);
24762306a36Sopenharmony_ci		EXPECT_GT(ret, 0);
24862306a36Sopenharmony_ci		EXPECT_LT(ret, sizeof(p));
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		self->child_nsfds1[i] = open(p, O_RDONLY | O_CLOEXEC);
25162306a36Sopenharmony_ci		if (self->child_nsfds1[i] < 0) {
25262306a36Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
25362306a36Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
25462306a36Sopenharmony_ci				       info->name, self->child_pid1);
25562306a36Sopenharmony_ci			}
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		ret = snprintf(p, sizeof(p), "/proc/%d/ns/%s",
25962306a36Sopenharmony_ci			       self->child_pid2, info->name);
26062306a36Sopenharmony_ci		EXPECT_GT(ret, 0);
26162306a36Sopenharmony_ci		EXPECT_LT(ret, sizeof(p));
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		self->child_nsfds2[i] = open(p, O_RDONLY | O_CLOEXEC);
26462306a36Sopenharmony_ci		if (self->child_nsfds2[i] < 0) {
26562306a36Sopenharmony_ci			EXPECT_EQ(errno, ENOENT) {
26662306a36Sopenharmony_ci				TH_LOG("%m - Failed to open %s namespace for process %d",
26762306a36Sopenharmony_ci				       info->name, self->child_pid1);
26862306a36Sopenharmony_ci			}
26962306a36Sopenharmony_ci		}
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	close(proc_fd);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ciFIXTURE_TEARDOWN(current_nsset)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	int i;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd1,
28062306a36Sopenharmony_ci					SIGKILL, NULL, 0), 0);
28162306a36Sopenharmony_ci	ASSERT_EQ(sys_pidfd_send_signal(self->child_pidfd2,
28262306a36Sopenharmony_ci					SIGKILL, NULL, 0), 0);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
28562306a36Sopenharmony_ci		if (self->nsfds[i] >= 0)
28662306a36Sopenharmony_ci			close(self->nsfds[i]);
28762306a36Sopenharmony_ci		if (self->child_nsfds1[i] >= 0)
28862306a36Sopenharmony_ci			close(self->child_nsfds1[i]);
28962306a36Sopenharmony_ci		if (self->child_nsfds2[i] >= 0)
29062306a36Sopenharmony_ci			close(self->child_nsfds2[i]);
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (self->child_pidfd1 >= 0)
29462306a36Sopenharmony_ci		EXPECT_EQ(0, close(self->child_pidfd1));
29562306a36Sopenharmony_ci	if (self->child_pidfd2 >= 0)
29662306a36Sopenharmony_ci		EXPECT_EQ(0, close(self->child_pidfd2));
29762306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid_exited, WEXITED), 0);
29862306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid1, WEXITED), 0);
29962306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PID, self->child_pid2, WEXITED), 0);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic int preserve_ns(const int pid, const char *ns)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	int ret;
30562306a36Sopenharmony_ci	char path[50];
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	ret = snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns);
30862306a36Sopenharmony_ci	if (ret < 0 || (size_t)ret >= sizeof(path))
30962306a36Sopenharmony_ci		return -EIO;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return open(path, O_RDONLY | O_CLOEXEC);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int in_same_namespace(int ns_fd1, pid_t pid2, const char *ns)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	int ns_fd2 = -EBADF;
31762306a36Sopenharmony_ci	int ret = -1;
31862306a36Sopenharmony_ci	struct stat ns_st1, ns_st2;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	ret = fstat(ns_fd1, &ns_st1);
32162306a36Sopenharmony_ci	if (ret < 0)
32262306a36Sopenharmony_ci		return -1;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	ns_fd2 = preserve_ns(pid2, ns);
32562306a36Sopenharmony_ci	if (ns_fd2 < 0)
32662306a36Sopenharmony_ci		return -1;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	ret = fstat(ns_fd2, &ns_st2);
32962306a36Sopenharmony_ci	close(ns_fd2);
33062306a36Sopenharmony_ci	if (ret < 0)
33162306a36Sopenharmony_ci		return -1;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* processes are in the same namespace */
33462306a36Sopenharmony_ci	if ((ns_st1.st_dev == ns_st2.st_dev) &&
33562306a36Sopenharmony_ci	    (ns_st1.st_ino == ns_st2.st_ino))
33662306a36Sopenharmony_ci		return 1;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* processes are in different namespaces */
33962306a36Sopenharmony_ci	return 0;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci/* Test that we can't pass garbage to the kernel. */
34362306a36Sopenharmony_ciTEST_F(current_nsset, invalid_flags)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, 0), 0);
34662306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, -1), 0);
34962306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, CLONE_VM), 0);
35262306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	ASSERT_NE(setns(self->pidfd, CLONE_NEWUSER | CLONE_VM), 0);
35562306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/* Test that we can't attach to a task that has already exited. */
35962306a36Sopenharmony_ciTEST_F(current_nsset, pidfd_exited_child)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	int i;
36262306a36Sopenharmony_ci	pid_t pid;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	ASSERT_NE(setns(self->child_pidfd_exited, CLONE_NEWUSER | CLONE_NEWNET),
36562306a36Sopenharmony_ci		  0);
36662306a36Sopenharmony_ci	EXPECT_EQ(errno, ESRCH);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	pid = getpid();
36962306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
37062306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
37162306a36Sopenharmony_ci		/* Verify that we haven't changed any namespaces. */
37262306a36Sopenharmony_ci		if (self->nsfds[i] >= 0)
37362306a36Sopenharmony_ci			ASSERT_EQ(in_same_namespace(self->nsfds[i], pid, info->name), 1);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ciTEST_F(current_nsset, pidfd_incremental_setns)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	int i;
38062306a36Sopenharmony_ci	pid_t pid;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	pid = getpid();
38362306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
38462306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
38562306a36Sopenharmony_ci		int nsfd;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
38862306a36Sopenharmony_ci			continue;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		if (info->flag) {
39162306a36Sopenharmony_ci			ASSERT_EQ(setns(self->child_pidfd1, info->flag), 0) {
39262306a36Sopenharmony_ci				TH_LOG("%m - Failed to setns to %s namespace of %d via pidfd %d",
39362306a36Sopenharmony_ci				       info->name, self->child_pid1,
39462306a36Sopenharmony_ci				       self->child_pidfd1);
39562306a36Sopenharmony_ci			}
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		/* Verify that we have changed to the correct namespaces. */
39962306a36Sopenharmony_ci		if (info->flag == CLONE_NEWPID)
40062306a36Sopenharmony_ci			nsfd = self->nsfds[i];
40162306a36Sopenharmony_ci		else
40262306a36Sopenharmony_ci			nsfd = self->child_nsfds1[i];
40362306a36Sopenharmony_ci		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
40462306a36Sopenharmony_ci			TH_LOG("setns failed to place us correctly into %s namespace of %d via pidfd %d",
40562306a36Sopenharmony_ci			       info->name, self->child_pid1,
40662306a36Sopenharmony_ci			       self->child_pidfd1);
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci		TH_LOG("Managed to correctly setns to %s namespace of %d via pidfd %d",
40962306a36Sopenharmony_ci		       info->name, self->child_pid1, self->child_pidfd1);
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ciTEST_F(current_nsset, nsfd_incremental_setns)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	int i;
41662306a36Sopenharmony_ci	pid_t pid;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	pid = getpid();
41962306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
42062306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
42162306a36Sopenharmony_ci		int nsfd;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
42462306a36Sopenharmony_ci			continue;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		if (info->flag) {
42762306a36Sopenharmony_ci			ASSERT_EQ(setns(self->child_nsfds1[i], info->flag), 0) {
42862306a36Sopenharmony_ci				TH_LOG("%m - Failed to setns to %s namespace of %d via nsfd %d",
42962306a36Sopenharmony_ci				       info->name, self->child_pid1,
43062306a36Sopenharmony_ci				       self->child_nsfds1[i]);
43162306a36Sopenharmony_ci			}
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		/* Verify that we have changed to the correct namespaces. */
43562306a36Sopenharmony_ci		if (info->flag == CLONE_NEWPID)
43662306a36Sopenharmony_ci			nsfd = self->nsfds[i];
43762306a36Sopenharmony_ci		else
43862306a36Sopenharmony_ci			nsfd = self->child_nsfds1[i];
43962306a36Sopenharmony_ci		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
44062306a36Sopenharmony_ci			TH_LOG("setns failed to place us correctly into %s namespace of %d via nsfd %d",
44162306a36Sopenharmony_ci			       info->name, self->child_pid1,
44262306a36Sopenharmony_ci			       self->child_nsfds1[i]);
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci		TH_LOG("Managed to correctly setns to %s namespace of %d via nsfd %d",
44562306a36Sopenharmony_ci		       info->name, self->child_pid1, self->child_nsfds1[i]);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ciTEST_F(current_nsset, pidfd_one_shot_setns)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	unsigned flags = 0;
45262306a36Sopenharmony_ci	int i;
45362306a36Sopenharmony_ci	pid_t pid;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
45662306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
45962306a36Sopenharmony_ci			continue;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		flags |= info->flag;
46262306a36Sopenharmony_ci		TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
46362306a36Sopenharmony_ci		       info->name, self->child_pid1);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
46762306a36Sopenharmony_ci		TH_LOG("%m - Failed to setns to namespaces of %d",
46862306a36Sopenharmony_ci		       self->child_pid1);
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	pid = getpid();
47262306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
47362306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
47462306a36Sopenharmony_ci		int nsfd;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
47762306a36Sopenharmony_ci			continue;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		/* Verify that we have changed to the correct namespaces. */
48062306a36Sopenharmony_ci		if (info->flag == CLONE_NEWPID)
48162306a36Sopenharmony_ci			nsfd = self->nsfds[i];
48262306a36Sopenharmony_ci		else
48362306a36Sopenharmony_ci			nsfd = self->child_nsfds1[i];
48462306a36Sopenharmony_ci		ASSERT_EQ(in_same_namespace(nsfd, pid, info->name), 1) {
48562306a36Sopenharmony_ci			TH_LOG("setns failed to place us correctly into %s namespace of %d",
48662306a36Sopenharmony_ci			       info->name, self->child_pid1);
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci		TH_LOG("Managed to correctly setns to %s namespace of %d",
48962306a36Sopenharmony_ci		       info->name, self->child_pid1);
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ciTEST_F(current_nsset, no_foul_play)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	unsigned flags = 0;
49662306a36Sopenharmony_ci	int i;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
49962306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		if (self->child_nsfds1[i] < 0)
50262306a36Sopenharmony_ci			continue;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		flags |= info->flag;
50562306a36Sopenharmony_ci		if (info->flag) /* No use logging pid_for_children. */
50662306a36Sopenharmony_ci			TH_LOG("Adding %s namespace of %d to list of namespaces to attach to",
50762306a36Sopenharmony_ci			       info->name, self->child_pid1);
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	ASSERT_EQ(setns(self->child_pidfd1, flags), 0) {
51162306a36Sopenharmony_ci		TH_LOG("%m - Failed to setns to namespaces of %d vid pidfd %d",
51262306a36Sopenharmony_ci		       self->child_pid1, self->child_pidfd1);
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/*
51662306a36Sopenharmony_ci	 * Can't setns to a user namespace outside of our hierarchy since we
51762306a36Sopenharmony_ci	 * don't have caps in there and didn't create it. That means that under
51862306a36Sopenharmony_ci	 * no circumstances should we be able to setns to any of the other
51962306a36Sopenharmony_ci	 * ones since they aren't owned by our user namespace.
52062306a36Sopenharmony_ci	 */
52162306a36Sopenharmony_ci	for (i = 0; i < PIDFD_NS_MAX; i++) {
52262306a36Sopenharmony_ci		const struct ns_info *info = &ns_info[i];
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		if (self->child_nsfds2[i] < 0 || !info->flag)
52562306a36Sopenharmony_ci			continue;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		ASSERT_NE(setns(self->child_pidfd2, info->flag), 0) {
52862306a36Sopenharmony_ci			TH_LOG("Managed to setns to %s namespace of %d via pidfd %d",
52962306a36Sopenharmony_ci			       info->name, self->child_pid2,
53062306a36Sopenharmony_ci			       self->child_pidfd2);
53162306a36Sopenharmony_ci		}
53262306a36Sopenharmony_ci		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via pidfd %d",
53362306a36Sopenharmony_ci		       info->name, self->child_pid2,
53462306a36Sopenharmony_ci		       self->child_pidfd2);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		ASSERT_NE(setns(self->child_nsfds2[i], info->flag), 0) {
53762306a36Sopenharmony_ci			TH_LOG("Managed to setns to %s namespace of %d via nsfd %d",
53862306a36Sopenharmony_ci			       info->name, self->child_pid2,
53962306a36Sopenharmony_ci			       self->child_nsfds2[i]);
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci		TH_LOG("%m - Correctly failed to setns to %s namespace of %d via nsfd %d",
54262306a36Sopenharmony_ci		       info->name, self->child_pid2,
54362306a36Sopenharmony_ci		       self->child_nsfds2[i]);
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ciTEST(setns_einval)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	int fd;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	fd = sys_memfd_create("rostock", 0);
55262306a36Sopenharmony_ci	EXPECT_GT(fd, 0);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	ASSERT_NE(setns(fd, 0), 0);
55562306a36Sopenharmony_ci	EXPECT_EQ(errno, EINVAL);
55662306a36Sopenharmony_ci	close(fd);
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ciTEST_HARNESS_MAIN
560