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