Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 01 Aug 2026 12:19:30 +0000
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 77d6c45afdca - main - tests/sys/capsicum: adjust tests for the new reaping behavior
Message-ID:  <6a6de452.1d6b8.b073cf4@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=77d6c45afdca8a524a88edfb3097d4d9dc90b583

commit 77d6c45afdca8a524a88edfb3097d4d9dc90b583
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-07-31 06:55:17 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-08-01 10:42:04 +0000

    tests/sys/capsicum: adjust tests for the new reaping behavior
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D58569
---
 tests/sys/capsicum/procdesc.cc | 90 ++++++++++++++++++------------------------
 tests/sys/capsicum/syscalls.h  |  1 +
 2 files changed, 40 insertions(+), 51 deletions(-)

diff --git a/tests/sys/capsicum/procdesc.cc b/tests/sys/capsicum/procdesc.cc
index aabc0446553b..f25324e4efc7 100644
--- a/tests/sys/capsicum/procdesc.cc
+++ b/tests/sys/capsicum/procdesc.cc
@@ -26,6 +26,21 @@
 static pid_t pdwait4_(int pd, int *status, int options, struct rusage *ru) {
 #ifdef HAVE_PDWAIT4
   return pdwait4(pd, status, options, ru);
+#elif defined(HAVE_PDWAIT)
+  struct __wrusage wr;
+  int rc;
+  pid_t pid = -1;
+
+  options |= WEXITED | WTRAPPED;
+  rc = pdwait(pd, status, options, &wr, NULL);
+  if (rc == 0) {
+    if (ru != NULL)
+      *ru = wr.wru_self;
+    rc = pdgetpid(pd, &pid);
+    if (rc == 0)
+      return pid;
+  }
+  return -1;
 #else
   // Simulate pdwait4() with wait4(pdgetpid()); this won't work in capability mode.
   pid_t pid = -1;
@@ -140,14 +155,15 @@ TEST(Pdfork, Simple) {
     fprintf(stderr, "For pd %d pid %d:\n", pd, pid);
     print_rusage(stderr, &ru);
   }
-  EXPECT_PID_GONE(pid);
 
-  // Can only pdwait4(pd) once (as initial call reaps zombie).
+  // Can pdwait4(pd) as much as wanted.
   memset(&ru, 0, sizeof(ru));
-  EXPECT_EQ(-1, pdwait4_(pd, &status, 0, &ru));
-  EXPECT_EQ(ECHILD, errno);
+  EXPECT_EQ(pid, pdwait4_(pd, &status, 0, &ru));
 
+  /* Reap */
+  EXPECT_EQ(pid, waitpid(pid, &status, WEXITED));
   EXPECT_OK(close(pd));
+  EXPECT_PID_GONE(pid);
 }
 
 TEST(Pdfork, InvalidFlag) {
@@ -326,7 +342,7 @@ class PipePdforkBase : public ::testing::Test {
       waitpid(pid_, NULL, WNOHANG);
     }
     // Check signal expectations.
-    EXPECT_FALSE(had_signal[SIGCHLD]);
+    //EXPECT_FALSE(had_signal[SIGCHLD]);
   }
   int TerminateChild() {
     // Tell the child to exit.
@@ -456,15 +472,15 @@ TEST_F(PipePdfork, MultipleRetrieveExitStatus) {
     fprintf(stderr, "For pd %d -> pid %d:\n", pd_, pid_);
     print_rusage(stderr, &ru);
   }
-  EXPECT_PID_GONE(pid_);
 
-#ifdef NOTYET
   // Child has been reaped, so original process descriptor dangles but
   // still has access to rusage information.
   memset(&ru, 0, sizeof(ru));
-  EXPECT_EQ(0, pdwait4_(pd_, &status, 0, &ru));
-#endif
+  EXPECT_EQ(pid_, pdwait4_(pd_, &status, 0, &ru));
   close(pd_copy);
+  close(pd_);
+  waitpid(pid_, &status, 0);
+  EXPECT_PID_GONE(pid_);
 }
 
 TEST_F(PipePdfork, ChildExit) {
@@ -492,8 +508,7 @@ TEST_F(PipePdfork, Close) {
   EXPECT_PID_DEAD(pid_);
 
 #ifdef __FreeBSD__
-  EXPECT_EQ(-1, waitpid(pid_, NULL, 0));
-  EXPECT_EQ(errno, ECHILD);
+  EXPECT_EQ(pid_, waitpid(pid_, NULL, 0));
 #else
   // Having closed the process descriptor means that pdwait4(pd) now doesn't work.
   int rc = pdwait4_(pd_, &status, 0, NULL);
@@ -524,13 +539,15 @@ TEST_F(PipePdfork, CloseLast) {
   EXPECT_EQ(EBADF, errno);
   // ...but can pdwait4() the still-open process descriptor.
   errno = 0;
-  EXPECT_EQ(0, pdwait4_(pd_other, &status, WNOHANG, NULL));
-  EXPECT_EQ(0, errno);
+  EXPECT_EQ(-1, pdwait4_(pd_other, &status, WNOHANG, NULL));
+  // process not yet exited
+  EXPECT_EQ(EWOULDBLOCK, errno);
 
   EXPECT_OK(close(pd_other));
+  EXPECT_EQ(0, waitpid(pid_, &status, WNOHANG));
   EXPECT_PID_DEAD(pid_);
 
-  EXPECT_FALSE(had_signal[SIGCHLD]);
+  EXPECT_TRUE(had_signal[SIGCHLD]);
   signal(SIGCHLD, original);
 }
 
@@ -560,27 +577,13 @@ FORK_TEST(Pdfork, OtherUserIfRoot) {
 
   // Ideally, we should be able to send signals via a process descriptor even
   // if it's owned by another user, but this is not implementated on FreeBSD.
-#ifdef __FreeBSD__
-  // On FreeBSD, pdkill() still performs all the same checks that kill() does
-  // and therefore cannot be used to send a signal to a process with another
-  // UID unless we are root.
-  EXPECT_SYSCALL_FAIL(EBADF, pdkill(pid, SIGKILL));
-  EXPECT_PID_ALIVE(pid);
-  // However, the process will be killed when we close the process descriptor.
-  EXPECT_OK(close(pd));
-  EXPECT_PID_GONE(pid);
-  // Can't pdwait4() after close() since close() reparents the child to a reaper (init)
-  EXPECT_SYSCALL_FAIL(EBADF, pdwait4_(pd, &status, WNOHANG, NULL));
-#else
   // Sending a signal with pdkill() should be permitted though.
-  EXPECT_OK(pdkill(pd, SIGKILL));
-  EXPECT_PID_ZOMBIE(pid);
+  EXPECT_EQ(-1, pdkill(pd, SIGKILL));
+  EXPECT_EQ(EPERM, errno);
 
   int rc = pdwait4_(pd, &status, WNOHANG, NULL);
-  EXPECT_OK(rc);
-  EXPECT_EQ(pid, rc);
-  EXPECT_TRUE(WIFSIGNALED(status));
-#endif
+  EXPECT_EQ(-1, rc);
+  EXPECT_EQ(EWOULDBLOCK, errno);
 }
 
 TEST_F(PipePdfork, WaitPidThenPd) {
@@ -605,9 +608,7 @@ TEST_F(PipePdfork, WaitPdThenPid) {
   EXPECT_OK(rc);
   EXPECT_EQ(pid_, rc);
 
-  // ...the zombie is reaped and cannot subsequently waitpid(pid).
-  EXPECT_EQ(-1, waitpid(pid_, &status, 0));
-  EXPECT_EQ(ECHILD, errno);
+  EXPECT_EQ(pid_, waitpid(pid_, &status, 0));
 }
 
 // Setting PD_DAEMON prevents close() from killing the child.
@@ -637,11 +638,6 @@ static void TestPdkill(pid_t pid, int pd) {
   errno = 0;
   EXPECT_EQ(0, pdkill(pd, SIGINT));
   EXPECT_EQ(0, errno);
-
-  // pdkill() on reaped process gives -ESRCH.
-  CheckChildFinished(pid, true);
-  EXPECT_EQ(-1, pdkill(pd, SIGINT));
-  EXPECT_EQ(ESRCH, errno);
 }
 
 TEST_F(PipePdfork, Pdkill) {
@@ -778,7 +774,7 @@ TEST_F(PipePdfork, NoSigchld) {
   // Can waitpid() for the specific pid of the pdfork()ed child.
   EXPECT_EQ(pid_, waitpid(pid_, &rc, 0));
   EXPECT_TRUE(WIFEXITED(rc)) << "0x" << std::hex << rc;
-  EXPECT_FALSE(had_signal[SIGCHLD]);
+  EXPECT_TRUE(had_signal[SIGCHLD]);
   signal(SIGCHLD, original);
 }
 
@@ -791,16 +787,11 @@ TEST_F(PipePdforkDaemon, NoPDSigchld) {
 
   EXPECT_OK(close(pd_));
   TerminateChild();
-#ifdef __FreeBSD__
-  EXPECT_EQ(-1, waitpid(pid_, NULL, 0));
-  EXPECT_EQ(errno, ECHILD);
-#else
   int rc = 0;
   // Can waitpid() for the specific pid of the pdfork()ed child.
   EXPECT_EQ(pid_, waitpid(pid_, &rc, 0));
   EXPECT_TRUE(WIFEXITED(rc)) << "0x" << std::hex << rc;
-#endif
-  EXPECT_FALSE(had_signal[SIGCHLD]);
+  EXPECT_TRUE(had_signal[SIGCHLD]);
   signal(SIGCHLD, original);
 }
 
@@ -825,11 +816,8 @@ TEST_F(PipePdfork, WildcardWait) {
   TerminateChild();
   EXPECT_PID_ZOMBIE(pid_);  // Ensure child is truly dead.
 
-  // Wildcard waitpid(-1) should not see the pdfork()ed child because
-  // there is still a process descriptor for it.
   int rc;
-  EXPECT_EQ(-1, waitpid(-1, &rc, WNOHANG));
-  EXPECT_EQ(ECHILD, errno);
+  EXPECT_EQ(pid_, waitpid(-1, &rc, WNOHANG));
 
   EXPECT_OK(close(pd_));
   pd_ = -1;
diff --git a/tests/sys/capsicum/syscalls.h b/tests/sys/capsicum/syscalls.h
index 70b49056f11c..2c97d576fc6e 100644
--- a/tests/sys/capsicum/syscalls.h
+++ b/tests/sys/capsicum/syscalls.h
@@ -119,6 +119,7 @@ inline long ptrace_(int request, pid_t pid, void *addr, void *data) {
 #define HAVE_F_DUP2FD
 #define HAVE_PSELECT
 #define HAVE_SCTP
+#define	HAVE_PDWAIT
 
 /* FreeBSD only allows root to call mlock[all]/munlock[all] */
 #define MLOCK_REQUIRES_ROOT 1


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a6de452.1d6b8.b073cf4>