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