When filt_proc() removes event from the knlist due to the process exiting (NOTE_EXIT->knlist_remove_inevent()), two things happen:
- knote kn_knlist pointer is reset
- INFLUX knote is removed from the process knlist.
And, there are two consequences:
- KN_LIST_UNLOCK() on such knote is nop
- there is nothing which would block exit1() from processing past the knlist_destroy() (and knlist_destroy() resets knlist lock pointers).
Both consequences result either in leaked process lock, or dereferencing NULL function pointers for locking.
The patch removes setting kn->kn_list to NULL on knlist_remove(), as well as setting lock functions to NULL on knlist_destroy(). This makes knlist unlocks in the kqueue_scan() functional even for knotes from _inevent(). I call it kludge because this change relies on the type-safety of the struct proc.
Alternate, non-kludge solution is to either remove _inevent() at all, or make some additional hold mechanism on the knlists to block knlist_cleardel/destroy, besides the presence of the INFLUX notes on list. E.g. knlist might also grow some reference count which must be waited for dropping to zero in knlist_destroy(). But this is much more fundamental rework of the code.
Diagnosed by: Eric Badger <eric@badgerio.us>
Tested by: pho, Eric Badger <eric@badgerio.us>