pidfd_bind_mount.c 3.1 KB

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