git: 78d5ef6505d7 - stable/13 - Fix a race between fork(2) and PROC_REAP_KILL subtree

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Fri, 24 Jun 2022 19:36:52 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=78d5ef6505d71f3c123f9ca645dc4b8690a95471

commit 78d5ef6505d71f3c123f9ca645dc4b8690a95471
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-04-20 21:33:51 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-06-24 14:45:45 +0000

    Fix a race between fork(2) and PROC_REAP_KILL subtree
    
    (cherry picked from commit 39794d80ad900915e5c4940e9917ba5cb59a8634)
---
 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