lkml.org 
[lkml]   [2022]   [Oct]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.14 7/8] 9p/trans_fd: always use O_NONBLOCK read/write
    Date
    From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>

    [ Upstream commit ef575281b21e9a34dfae544a187c6aac2ae424a9 ]

    syzbot is reporting hung task at p9_fd_close() [1], for p9_mux_poll_stop()
    from p9_conn_destroy() from p9_fd_close() is failing to interrupt already
    started kernel_read() from p9_fd_read() from p9_read_work() and/or
    kernel_write() from p9_fd_write() from p9_write_work() requests.

    Since p9_socket_open() sets O_NONBLOCK flag, p9_mux_poll_stop() does not
    need to interrupt kernel_read()/kernel_write(). However, since p9_fd_open()
    does not set O_NONBLOCK flag, but pipe blocks unless signal is pending,
    p9_mux_poll_stop() needs to interrupt kernel_read()/kernel_write() 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 kernel_read()/kernel_write() on pipes.

    A minimal change, which this patch is doing, is to set O_NONBLOCK flag
    from p9_fd_open(), for O_NONBLOCK flag does not affect reading/writing
    of regular files. But this approach changes O_NONBLOCK flag on userspace-
    supplied file descriptors (which might break userspace programs), and
    O_NONBLOCK flag could be changed by userspace. It would be possible to set
    O_NONBLOCK flag every time p9_fd_read()/p9_fd_write() is invoked, but still
    remains small race window for clearing O_NONBLOCK flag.

    If we don't want to manipulate O_NONBLOCK flag, we might be able to
    surround kernel_read()/kernel_write() with set_thread_flag(TIF_SIGPENDING)
    and recalc_sigpending(). Since p9_read_work()/p9_write_work() works are
    processed by kernel threads which process global system_wq workqueue,
    signals could not be delivered from remote threads when p9_mux_poll_stop()
    from p9_conn_destroy() from p9_fd_close() is called. Therefore, calling
    set_thread_flag(TIF_SIGPENDING)/recalc_sigpending() every time would be
    needed if we count on signals for making kernel_read()/kernel_write()
    non-blocking.

    Link: https://lkml.kernel.org/r/345de429-a88b-7097-d177-adecf9fed342@I-love.SAKURA.ne.jp
    Link: https://syzkaller.appspot.com/bug?extid=8b41a1365f1106fd0f33 [1]
    Reported-by: syzbot <syzbot+8b41a1365f1106fd0f33@syzkaller.appspotmail.com>
    Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    Tested-by: syzbot <syzbot+8b41a1365f1106fd0f33@syzkaller.appspotmail.com>
    Reviewed-by: Christian Schoenebeck <linux_oss@crudebyte.com>
    [Dominique: add comment at Christian's suggestion]
    Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/9p/trans_fd.c | 3 +++
    1 file changed, 3 insertions(+)

    diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
    index acb5b5f15a33..9b23bf0e278c 100644
    --- a/net/9p/trans_fd.c
    +++ b/net/9p/trans_fd.c
    @@ -834,11 +834,14 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
    goto out_free_ts;
    if (!(ts->rd->f_mode & FMODE_READ))
    goto out_put_rd;
    + /* prevent workers from hanging on IO when fd is a pipe */
    + ts->rd->f_flags |= O_NONBLOCK;
    ts->wr = fget(wfd);
    if (!ts->wr)
    goto out_put_rd;
    if (!(ts->wr->f_mode & FMODE_WRITE))
    goto out_put_wr;
    + ts->wr->f_flags |= O_NONBLOCK;

    client->trans = ts;
    client->status = Connected;
    --
    2.35.1
    \
     
     \ /
      Last update: 2022-10-18 02:52    [W:2.422 / U:0.156 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site