The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=39794d80ad900915e5c4940e9917ba5cb59a8634

commit 39794d80ad900915e5c4940e9917ba5cb59a8634
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2022-04-20 21:33:51 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2022-04-27 23:27:35 +0000

    Fix a race between fork(2) and PROC_REAP_KILL subtree
    
    by repeating iteration over the subtree until there are no new processes
    to signal.
    
    Reported and tested by: pho
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D35014
---
 sys/kern/kern_procctl.c | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
index 1a9f17de2d7a..83fcc57f8f78 100644
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -31,6 +31,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/_unrhdr.h>
 #include <sys/systm.h>
 #include <sys/capsicum.h>
 #include <sys/lock.h>
@@ -293,14 +294,17 @@ reap_kill_children(struct thread *td, struct proc *reaper,
        }
 }
 
-static void
-reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper,
-    struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error)
+static bool
+reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
+    struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error,
+    struct unrhdr *pids)
 {
        struct reap_kill_tracker_head tracker;
        struct reap_kill_tracker *t;
        struct proc *p2;
+       bool res;
 
+       res = false;
        TAILQ_INIT(&tracker);
        reap_kill_sched(&tracker, reaper);
        while ((t = TAILQ_FIRST(&tracker)) != NULL) {
@@ -313,10 +317,32 @@ reap_kill_subtree(struct thread *td, struct proc *p, 
struct proc *reaper,
                                continue;
                        if ((p2->p_treeflag & P_TREE_REAPER) != 0)
                                reap_kill_sched(&tracker, p2);
-                       reap_kill_proc(td, p2, ksi, rk, error);
+                       if (alloc_unr_specific(pids, p2->p_pid) == p2->p_pid) {
+                               reap_kill_proc(td, p2, ksi, rk, error);
+                               res = true;
+                       }
                }
                free(t, M_TEMP);
        }
+       return (res);
+}
+
+static void
+reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper,
+    struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error)
+{
+       struct unrhdr pids;
+
+       /*
+        * pids records processes which were already signalled, to
+        * avoid doubling signals to them if iteration needs to be
+        * repeated.
+        */
+       init_unrhdr(&pids, 1, PID_MAX, UNR_NO_MTX);
+       while (reap_kill_subtree_once(td, p, reaper, rk, ksi, error, &pids))
+              ;
+       clean_unrhdr(&pids);
+       clear_unrhdr(&pids);
 }
 
 static bool

Reply via email to