git: 78df5deaf5f1 - releng/15.1 - kqueue: Fix handling of marker knotes during fork

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 29 Sep 2026 16:00:03 UTC
The branch releng/15.1 has been updated by markj:

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

commit 78df5deaf5f120221cf2965346bb5f23d1d1ab72
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-09-28 13:40:45 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-09-29 01:01:48 +0000

    kqueue: Fix handling of marker knotes during fork
    
    Commit d8bdcb08d0eb fixed a problem in kqueue_fork_copy_knote() where we
    did not skip over marker knotes when copying.  However, that fix was not
    sufficient: we bump the influx counter and check for a marker after
    dropping the kqueue lock.  So, if multiple threads in a process are
    forking concurrently, kqueue_fork_copy_list() may mark a marker as
    in-flux and drop the lock; if the marker owner then frees the marker,
    the first thread will decrement the in-flux counter of a freed knotes.
    This use-after-free can be exploited, at least prior to commit
    d8bdcb08d0eb, which makes exploitation more challenging.
    
    Approved by:    so
    Security:       FreeBSD-SA-26:65.kqueue
    Security:       CVE-2026-58099
    Reported by:    Reo Shiseki
    Reviewed by:    kib
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D59522
---
 sys/kern/kern_event.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 706f0e6d658e..ec9036bd30de 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -3085,9 +3085,9 @@ kqueue_fork_copy_knote(struct kqueue *kq, struct kqueue *kq1, struct knote *kn,
 	    ("%s: knote %p not in flux", __func__, kn));
 	KASSERT((kn->kn_status & KN_DETACHED) == 0,
 	    ("%s: knote %p not detached", __func__, kn));
+	KASSERT((kn->kn_status & KN_MARKER) == 0,
+	    ("%s: knote %p not detached", __func__, kn));
 
-	if ((kn->kn_status & KN_MARKER) != 0)
-		return;
 	if ((kn->kn_status & KN_KQUEUE) != 0) {
 		/*
 		 * We cannot hold references to a kqueue outside of the process
@@ -3153,7 +3153,7 @@ kqueue_fork_copy_list(struct klist *knlist, struct knote *marker,
 	kn = SLIST_FIRST(knlist);
 	while (kn != NULL) {
 		MPASS(kn->kn_kq == kq);
-		if ((kn->kn_status & KN_DETACHED) != 0 ||
+		if ((kn->kn_status & (KN_DETACHED | KN_MARKER)) != 0 ||
 		    (kn_in_flux(kn) && (kn->kn_status & KN_SCAN) == 0)) {
 			kn = SLIST_NEXT(kn, kn_link);
 			continue;