First, funsetownlst() list looks at the first element of the list to see
whether it's processing a process or a process group list. Then it
acquires the global sigio lock and processes the list. However, nothing
prevents the first sigio structure from being freed by a concurrent
funsetown() before the sigio lock is acquired.
Fix this by acquiring the global sigio lock immediately after checking
whether the list is empty. Callers of funsetownlst() ensure that new
sigios cannot be added concurrently.
Second, fsetown() uses funsetown() to remove an existing sigio structure
from a file object (e.g., a pipe or TTY). However, funsetown() uses a
racy check to avoid the sigio lock, so two threads may call fsetown() on
the same file object, observe that no sigio structure is present, and
enqueue two sigio structures for the same file object. However, if the
file object is destroyed, funsetown() will only remove one sigio
structure, and funsetownlst() may later trigger a use-after-free when it
clears *sigio->sio_myref for each sigio list entry.
Fix this by introducing funsetown_locked(), which avoids the racy check.