We currently maintain a per-process list of stopped timer knotes, used
when the owning process receives SIGSTOP. Upon receiving SIGCONT,
queued timers are re-armed.
When detaching a timer knote, we drain the callout and remove it from
the queue, then check to see if the callout was re-armed by SIGCONT; if
so, then we loop. However, the callout timer may fire before this
check, and softclock_call_cc() clears the pending bit without the
associated callout lock held, in which case filt_timerdetach() fails to
observe that the callout is still running and doesn't drain.
The callout handler then races with a free of the knote, and the
resulting memory corruption can be exploited to obtain root privileges.
Fix the problem by using an explicit flag that prevents re-arming a
timer whose knote is in the process of being detached.
Reported by: OpenAI Security Research Team
Sponsored by: The FreeBSD Foundation