poll/select: Fix panic in kqueue backend
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 28 Mar 2023 02:11:05 +0000 (19:11 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 28 Mar 2023 02:11:05 +0000 (19:11 -0700)
commite6bc4d0d50b6415dab7ca6c4726c6b0b236b1fca
tree1dbbed96fd2a09d3eaf844e2ea92ed549d1df96a
parentd5905ab47156e41e37740d9d19c3fa329cb57cd8
poll/select: Fix panic in kqueue backend

* The poll and select system calls use kqueue as a backend and
  attempt to cache active events from prior calls to improve
  performance.

  However, this makes a potential race more likely where in a
  high-concurrency application one thread close()es a descriptor
  that another thread had previously used in a poll/select operation
  and this close() races the later poll/select operation that is
  attempting to remove the kevent.

* The race can sometimes prevent the poll/select kevent copyout
  code from removing previously cached but no-longer-used
  events, because the removal references the events by their
  descriptor rather than directly and the descriptor is no longer
  valid.

  This causes kern_kevent() to loop infinite and hit a panic
  designed to check for that situation.

* Fix the problem by moving the removal of old events from the
  poll/select copyout code into kqueue_scan().  kqueue_scan()
  can detect old unused events using the sequence id that the
  poll/select kernel code stores in the kevent.
sys/kern/kern_event.c
sys/kern/sys_generic.c
sys/sys/event.h