There is a slight inconsistency in klist_invalidate(). If the knote is
already in the event queue and has flag EV_ONESHOT, kqueue_scan() will
not invoke the newly set f_event. In this case, the kevent(2) system
call will return the knote's original event state that no longer
reflects the state that is reachable through the file descriptor
(the caller of klist_invalidate() has already revoked access to the
file or device).
I think a proper fix is to invoke f_event manually to force the state
update.
OK?
Index: kern/kern_event.c
===================================================================
RCS file: src/sys/kern/kern_event.c,v
retrieving revision 1.153
diff -u -p -r1.153 kern_event.c
--- kern/kern_event.c 20 Dec 2020 12:54:05 -0000 1.153
+++ kern/kern_event.c 21 Dec 2020 16:19:30 -0000
@@ -1618,6 +1618,7 @@ klist_invalidate(struct klist *list)
kn->kn_fop->f_detach(kn);
if (kn->kn_fop->f_flags & FILTEROP_ISFD) {
kn->kn_fop = &dead_filtops;
+ kn->kn_fop->f_event(kn, 0);
knote_activate(kn);
s = splhigh();
knote_release(kn);