aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2023-05-12 22:36:52 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2023-06-05 08:35:01 +0000
commitbb75966eaa3125aa22884663768068a173cda408 (patch)
treecc53575e6e49254d2df62eee76738601f21ac9f9
parent135bc1d49de598a8c1c0b679e70265e01d08beea (diff)
downloadsrc-bb75966eaa3125aa22884663768068a173cda408.tar.gz
src-bb75966eaa3125aa22884663768068a173cda408.zip
reapkill: handle possible pid reuse after the pid was recorded as signalled
(cherry picked from commit 8164032a495b53b9176814f7b08e093961fabdca)
-rw-r--r--sys/kern/kern_procctl.c36
-rw-r--r--sys/sys/proc.h1
2 files changed, 36 insertions, 1 deletions
diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
index a4f675c2938e..16bd9ac702e8 100644
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -416,8 +416,22 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
continue;
if ((p2->p_treeflag & P_TREE_REAPER) != 0)
reap_kill_sched(&tracker, p2);
- if (alloc_unr_specific(pids, p2->p_pid) != p2->p_pid)
+
+ /*
+ * Handle possible pid reuse. If we recorded
+ * p2 as killed but its p_flag2 does not
+ * confirm it, that means that the process
+ * terminated and its id was reused by other
+ * process in the reaper subtree.
+ *
+ * Unlocked read of p2->p_flag2 is fine, it is
+ * our thread that set the tested flag.
+ */
+ if (alloc_unr_specific(pids, p2->p_pid) != p2->p_pid &&
+ (atomic_load_int(&p2->p_flag2) &
+ (P2_REAPKILLED | P2_WEXIT)) != 0)
continue;
+
if (p2 == td->td_proc) {
if ((p2->p_flag & P_HADTHREADS) != 0 &&
(p2->p_flag2 & P2_WEXIT) == 0) {
@@ -428,6 +442,11 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
st = false;
}
PROC_LOCK(p2);
+ /*
+ * sapblk ensures that only one thread
+ * in the system sets this flag.
+ */
+ p2->p_flag2 |= P2_REAPKILLED;
if (st)
r = thread_single(p2, SINGLE_NO_EXIT);
(void)pksignal(p2, w->rk->rk_sig, w->ksi);
@@ -445,6 +464,7 @@ reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
PROC_LOCK(p2);
if ((p2->p_flag2 & P2_WEXIT) == 0) {
_PHOLD_LITE(p2);
+ p2->p_flag2 |= P2_REAPKILLED;
PROC_UNLOCK(p2);
w->target = p2;
taskqueue_enqueue(taskqueue_thread,
@@ -471,6 +491,9 @@ reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper,
struct reap_kill_proc_work *w)
{
struct unrhdr pids;
+ void *ihandle;
+ struct proc *p2;
+ int pid;
/*
* pids records processes which were already signalled, to
@@ -486,6 +509,17 @@ reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper,
PROC_UNLOCK(td->td_proc);
while (reap_kill_subtree_once(td, p, reaper, &pids, w))
;
+
+ ihandle = create_iter_unr(&pids);
+ while ((pid = next_iter_unr(ihandle)) != -1) {
+ p2 = pfind(pid);
+ if (p2 != NULL) {
+ p2->p_flag2 &= ~P2_REAPKILLED;
+ PROC_UNLOCK(p2);
+ }
+ }
+ free_iter_unr(ihandle);
+
out:
clean_unrhdr(&pids);
clear_unrhdr(&pids);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 0f04921fffe6..997ff110bcdc 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -836,6 +836,7 @@ struct proc {
#define P2_WEXIT 0x00040000 /* exit just started, no
external thread_single() is
permitted */
+#define P2_REAPKILLED 0x00080000
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */