The CLONE_AUTOREAP tests poll for POLLIN and then immediately call PIDFD_GET_INFO with PIDFD_INFO_EXIT. PIDFD_INFO_EXIT is only published from release_task() -> pidfs_exit(), which runs after the pidfd already reported POLLIN for the exited task. A poller woken by do_notify_pidfd() can therefore read a mask without PIDFD_INFO_EXIT; under KASAN the autoreap_multithreaded case fails this way. POLLHUP is returned once the task linkage has been removed from struct pid, which happens after pidfs_exit() has published the exit information. Wait for POLLHUP and check it in revents. With this change all tests pass ten consecutive runs on an unpatched kernel. Signed-off-by: fujo --- .../selftests/pidfd/pidfd_autoreap_test.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/pidfd/pidfd_autoreap_test.c b/tools/testing/selftests/pidfd/pidfd_autoreap_test.c index 1c586482f..b4f3699ef 100644 --- a/tools/testing/selftests/pidfd/pidfd_autoreap_test.c +++ b/tools/testing/selftests/pidfd/pidfd_autoreap_test.c @@ -149,7 +149,7 @@ TEST(autoreap_rejects_thread) /* * Basic test: create an autoreap child, let it exit, verify: - * - pidfd becomes readable (poll returns POLLIN) + * - pidfd becomes readable (poll returns POLLHUP) * - PIDFD_GET_INFO returns the correct exit code * - waitpid() returns -1/ECHILD (no zombie) */ @@ -172,10 +172,10 @@ TEST(autoreap_basic) /* Wait for the child to exit via pidfd poll. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); - ASSERT_TRUE(pfd.revents & POLLIN); + ASSERT_TRUE(pfd.revents & POLLHUP); /* Verify exit info via PIDFD_GET_INFO. */ ret = ioctl(pidfd, PIDFD_GET_INFO, &info); @@ -225,10 +225,10 @@ TEST(autoreap_signaled) /* Wait for exit via pidfd. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); - ASSERT_TRUE(pfd.revents & POLLIN); + ASSERT_TRUE(pfd.revents & POLLHUP); /* Verify signal info. */ ret = ioctl(pidfd, PIDFD_GET_INFO, &info); @@ -334,10 +334,10 @@ TEST(autoreap_reparent) /* Wait for it to exit via pidfd poll. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); - ASSERT_TRUE(pfd.revents & POLLIN); + ASSERT_TRUE(pfd.revents & POLLHUP); /* * The grandchild should have been autoreaped even though @@ -421,10 +421,10 @@ TEST(autoreap_multithreaded) /* Wait for the process to fully exit via pidfd poll. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); - ASSERT_TRUE(pfd.revents & POLLIN); + ASSERT_TRUE(pfd.revents & POLLHUP); /* Verify exit info. */ ret = ioctl(pidfd, PIDFD_GET_INFO, &info); @@ -512,7 +512,7 @@ TEST(autoreap_no_inherit) /* Wait for the autoreap child to exit. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); @@ -571,7 +571,7 @@ TEST(nnp_sets_no_new_privs) /* Wait for child to exit. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); @@ -631,7 +631,7 @@ TEST(autoreap_no_new_privs_unset) ASSERT_GE(pidfd, 0); pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); @@ -695,10 +695,10 @@ TEST(autokill_basic) /* Wait for the child to die via the pidfd_open'd fd. */ pfd.fd = pollfd_fd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); - ASSERT_TRUE(pfd.revents & POLLIN); + ASSERT_TRUE(pfd.revents & POLLHUP); /* Child should be autoreaped — no zombie. */ usleep(100000); @@ -799,7 +799,7 @@ TEST(autokill_pidfd_open_no_effect) /* Verify child is still alive by polling the clone3 pidfd. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 0); ASSERT_EQ(ret, 0) { TH_LOG("Child died after closing pidfd_open fd — should still be alive"); @@ -813,10 +813,10 @@ TEST(autokill_pidfd_open_no_effect) close(pidfd); pfd.fd = open_fd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); - ASSERT_TRUE(pfd.revents & POLLIN); + ASSERT_TRUE(pfd.revents & POLLHUP); /* Child should be autoreaped — no zombie. */ usleep(100000); @@ -884,7 +884,7 @@ TEST(autokill_without_nnp_with_cap) /* Wait for child to exit. */ pfd.fd = pidfd; - pfd.events = POLLIN; + pfd.events = POLLHUP; ret = poll(&pfd, 1, 5000); ASSERT_EQ(ret, 1); -- 2.53.0