1 // SPDX-License-Identifier: GPL-2.0-or-later 2 // Copyright (c) 2024 Christian Brauner <brauner@kernel.org> 3 4 #define _GNU_SOURCE 5 #include <fcntl.h> 6 #include <limits.h> 7 #include <sched.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <linux/fs.h> 11 #include <sys/ioctl.h> 12 #include <sys/stat.h> 13 #include <sys/mount.h> 14 #include <unistd.h> 15 16 #include "pidfd.h" 17 #include "../kselftest_harness.h" 18 #include "../filesystems/wrappers.h" 19 20 FIXTURE(pidfd_bind_mount) { 21 char template[PATH_MAX]; 22 int fd_tmp; 23 int pidfd; 24 struct stat st1; 25 struct stat st2; 26 __u32 gen1; 27 __u32 gen2; 28 bool must_unmount; 29 }; 30 31 FIXTURE_SETUP(pidfd_bind_mount) 32 { 33 self->fd_tmp = -EBADF; 34 self->must_unmount = false; 35 ASSERT_EQ(unshare(CLONE_NEWNS), 0); 36 ASSERT_LE(snprintf(self->template, PATH_MAX, "%s", P_tmpdir "/pidfd_bind_mount_XXXXXX"), PATH_MAX); 37 self->fd_tmp = mkstemp(self->template); 38 ASSERT_GE(self->fd_tmp, 0); 39 self->pidfd = sys_pidfd_open(getpid(), 0); 40 ASSERT_GE(self->pidfd, 0); 41 ASSERT_GE(fstat(self->pidfd, &self->st1), 0); 42 ASSERT_EQ(ioctl(self->pidfd, FS_IOC_GETVERSION, &self->gen1), 0); 43 } 44 45 FIXTURE_TEARDOWN(pidfd_bind_mount) 46 { 47 ASSERT_EQ(close(self->fd_tmp), 0); 48 if (self->must_unmount) 49 ASSERT_EQ(umount2(self->template, 0), 0); 50 ASSERT_EQ(unlink(self->template), 0); 51 } 52 53 /* 54 * Test that a detached mount can be created for a pidfd and then 55 * attached to the filesystem hierarchy. 56 */ 57 TEST_F(pidfd_bind_mount, bind_mount) 58 { 59 int fd_tree; 60 61 fd_tree = sys_open_tree(self->pidfd, "", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | AT_EMPTY_PATH); 62 ASSERT_GE(fd_tree, 0); 63 64 ASSERT_EQ(move_mount(fd_tree, "", self->fd_tmp, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 65 self->must_unmount = true; 66 67 ASSERT_EQ(close(fd_tree), 0); 68 } 69 70 /* Test that a pidfd can be reopened through procfs. */ 71 TEST_F(pidfd_bind_mount, reopen) 72 { 73 int pidfd; 74 char proc_path[PATH_MAX]; 75 76 sprintf(proc_path, "/proc/self/fd/%d", self->pidfd); 77 pidfd = open(proc_path, O_RDONLY | O_NOCTTY | O_CLOEXEC); 78 ASSERT_GE(pidfd, 0); 79 80 ASSERT_GE(fstat(self->pidfd, &self->st2), 0); 81 ASSERT_EQ(ioctl(self->pidfd, FS_IOC_GETVERSION, &self->gen2), 0); 82 83 ASSERT_TRUE(self->st1.st_dev == self->st2.st_dev && self->st1.st_ino == self->st2.st_ino); 84 ASSERT_TRUE(self->gen1 == self->gen2); 85 86 ASSERT_EQ(close(pidfd), 0); 87 } 88 89 /* 90 * Test that a detached mount can be created for a pidfd and then 91 * attached to the filesystem hierarchy and reopened. 92 */ 93 TEST_F(pidfd_bind_mount, bind_mount_reopen) 94 { 95 int fd_tree, fd_pidfd_mnt; 96 97 fd_tree = sys_open_tree(self->pidfd, "", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | AT_EMPTY_PATH); 98 ASSERT_GE(fd_tree, 0); 99 100 ASSERT_EQ(move_mount(fd_tree, "", self->fd_tmp, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0); 101 self->must_unmount = true; 102 103 fd_pidfd_mnt = openat(-EBADF, self->template, O_RDONLY | O_NOCTTY | O_CLOEXEC); 104 ASSERT_GE(fd_pidfd_mnt, 0); 105 106 ASSERT_GE(fstat(fd_tree, &self->st2), 0); 107 ASSERT_EQ(ioctl(fd_pidfd_mnt, FS_IOC_GETVERSION, &self->gen2), 0); 108 109 ASSERT_TRUE(self->st1.st_dev == self->st2.st_dev && self->st1.st_ino == self->st2.st_ino); 110 ASSERT_TRUE(self->gen1 == self->gen2); 111 112 ASSERT_EQ(close(fd_tree), 0); 113 ASSERT_EQ(close(fd_pidfd_mnt), 0); 114 } 115 116 TEST_HARNESS_MAIN 117