In the Linux kernel, the following vulnerability has been resolved:
9p/transfd: always use ONONBLOCK read/write
syzbot is reporting hung task at p9fdclose() [1], for p9muxpollstop() from p9conndestroy() from p9fdclose() is failing to interrupt already started kernelread() from p9fdread() from p9readwork() and/or kernelwrite() from p9fdwrite() from p9write_work() requests.
Since p9socketopen() sets ONONBLOCK flag, p9muxpollstop() does not need to interrupt kernelread()/kernelwrite(). However, since p9fdopen() does not set ONONBLOCK flag, but pipe blocks unless signal is pending, p9muxpollstop() needs to interrupt kernelread()/kernelwrite() when the file descriptor refers to a pipe. In other words, pipe file descriptor needs to be handled as if socket file descriptor.
We somehow need to interrupt kernelread()/kernelwrite() on pipes.
A minimal change, which this patch is doing, is to set ONONBLOCK flag from p9fdopen(), for ONONBLOCK flag does not affect reading/writing of regular files. But this approach changes ONONBLOCK flag on userspace- supplied file descriptors (which might break userspace programs), and ONONBLOCK flag could be changed by userspace. It would be possible to set ONONBLOCK flag every time p9fdread()/p9fdwrite() is invoked, but still remains small race window for clearing ONONBLOCK flag.
If we don't want to manipulate ONONBLOCK flag, we might be able to surround kernelread()/kernelwrite() with setthreadflag(TIFSIGPENDING) and recalcsigpending(). Since p9readwork()/p9writework() works are processed by kernel threads which process global systemwq workqueue, signals could not be delivered from remote threads when p9muxpollstop() from p9conndestroy() from p9fdclose() is called. Therefore, calling setthreadflag(TIFSIGPENDING)/recalcsigpending() every time would be needed if we count on signals for making kernelread()/kernel_write() non-blocking.
[Dominique: add comment at Christian's suggestion]