regression_pidfd_setns_test.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <errno.h>
  4. #include <sched.h>
  5. #include <signal.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/socket.h>
  10. #include <unistd.h>
  11. #include "../pidfd/pidfd.h"
  12. #include "../kselftest_harness.h"
  13. /*
  14. * Regression tests for the setns(pidfd) active reference counting bug.
  15. *
  16. * These tests are based on the reproducers that triggered the race condition
  17. * fixed by commit 1c465d0518dc ("ns: handle setns(pidfd, ...) cleanly").
  18. *
  19. * The bug: When using setns() with a pidfd, if the target task exits between
  20. * prepare_nsset() and commit_nsset(), the namespaces would become inactive.
  21. * Then ns_ref_active_get() would increment from 0 without properly resurrecting
  22. * the owner chain, causing active reference count underflows.
  23. */
  24. /*
  25. * Simple pidfd setns test using create_child()+unshare().
  26. *
  27. * Without the fix, this would trigger active refcount warnings when the
  28. * parent exits after doing setns(pidfd) on a child that has already exited.
  29. */
  30. TEST(simple_pidfd_setns)
  31. {
  32. pid_t child_pid;
  33. int pidfd = -1;
  34. int ret;
  35. int sv[2];
  36. char c;
  37. /* Ignore SIGCHLD for autoreap */
  38. ASSERT_NE(signal(SIGCHLD, SIG_IGN), SIG_ERR);
  39. ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
  40. /* Create a child process without namespaces initially */
  41. child_pid = create_child(&pidfd, 0);
  42. ASSERT_GE(child_pid, 0);
  43. if (child_pid == 0) {
  44. close(sv[0]);
  45. if (unshare(CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWNET | CLONE_NEWUSER) < 0) {
  46. close(sv[1]);
  47. _exit(1);
  48. }
  49. /* Signal parent that namespaces are ready */
  50. if (write_nointr(sv[1], "1", 1) < 0) {
  51. close(sv[1]);
  52. _exit(1);
  53. }
  54. close(sv[1]);
  55. _exit(0);
  56. }
  57. ASSERT_GE(pidfd, 0);
  58. EXPECT_EQ(close(sv[1]), 0);
  59. ret = read_nointr(sv[0], &c, 1);
  60. ASSERT_EQ(ret, 1);
  61. EXPECT_EQ(close(sv[0]), 0);
  62. /* Set to child's namespaces via pidfd */
  63. ret = setns(pidfd, CLONE_NEWUTS | CLONE_NEWIPC);
  64. TH_LOG("setns() returned %d", ret);
  65. close(pidfd);
  66. }
  67. /*
  68. * Simple pidfd setns test using create_child().
  69. *
  70. * This variation uses create_child() with namespace flags directly.
  71. * Namespaces are created immediately at clone time.
  72. */
  73. TEST(simple_pidfd_setns_clone)
  74. {
  75. pid_t child_pid;
  76. int pidfd = -1;
  77. int ret;
  78. /* Ignore SIGCHLD for autoreap */
  79. ASSERT_NE(signal(SIGCHLD, SIG_IGN), SIG_ERR);
  80. /* Create a child process with new namespaces using create_child() */
  81. child_pid = create_child(&pidfd, CLONE_NEWUSER | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWNET);
  82. ASSERT_GE(child_pid, 0);
  83. if (child_pid == 0) {
  84. /* Child: sleep for a while so parent can setns to us */
  85. sleep(2);
  86. _exit(0);
  87. }
  88. /* Parent: pidfd was already created by create_child() */
  89. ASSERT_GE(pidfd, 0);
  90. /* Set to child's namespaces via pidfd */
  91. ret = setns(pidfd, CLONE_NEWUTS | CLONE_NEWIPC);
  92. close(pidfd);
  93. TH_LOG("setns() returned %d", ret);
  94. }
  95. TEST_HARNESS_MAIN