From 715db9d67ba37ce7fc5743a27870b51982740725 Mon Sep 17 00:00:00 2001 From: visa Date: Wed, 27 Jan 2021 02:58:03 +0000 Subject: [PATCH] kqueue: Fix termination assert When a kqueue file is closed, the kqueue can still have threads scanning it. Consequently, kqueue_terminate() can see scan markers in the event queue. These markers are removed when the scanning threads leave the kqueue. Take this into account when checking the queue's state, to avoid a panic when kqueue is closed from under a thread. OK anton@ Reported-by: syzbot+757c60a2aa1125137cce@syzkaller.appspotmail.com --- sys/kern/kern_event.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index c5d47d33bdc..5471b2913d6 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_event.c,v 1.159 2021/01/17 05:56:32 visa Exp $ */ +/* $OpenBSD: kern_event.c,v 1.160 2021/01/27 02:58:03 visa Exp $ */ /*- * Copyright (c) 1999,2000,2001 Jonathan Lemon @@ -206,6 +206,8 @@ KQRELE(struct kqueue *kq) fdpunlock(fdp); } + KASSERT(TAILQ_EMPTY(&kq->kq_head)); + free(kq->kq_knlist, M_KEVENT, kq->kq_knlistsize * sizeof(struct knlist)); hashfree(kq->kq_knhash, KN_HASHSIZE, M_KEVENT); @@ -1265,7 +1267,15 @@ kqueue_purge(struct proc *p, struct kqueue *kq) void kqueue_terminate(struct proc *p, struct kqueue *kq) { - KASSERT(TAILQ_EMPTY(&kq->kq_head)); + struct knote *kn; + + /* + * Any remaining entries should be scan markers. + * They are removed when the ongoing scans finish. + */ + KASSERT(kq->kq_count == 0); + TAILQ_FOREACH(kn, &kq->kq_head, kn_tqe) + KASSERT(kn->kn_filter == EVFILT_MARKER); kq->kq_state |= KQ_DYING; kqueue_wakeup(kq); -- 2.20.1