lkml.org 
[lkml]   [2021]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.14 039/334] fcntl: fix potential deadlock for &fasync_struct.fa_lock
    Date
    From: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>

    [ Upstream commit 2f488f698fda820f8e6fa0407630154eceb145d6 ]

    There is an existing lock hierarchy of
    &dev->event_lock --> &fasync_struct.fa_lock --> &f->f_owner.lock
    from the following call chain:

    input_inject_event():
    spin_lock_irqsave(&dev->event_lock,...);
    input_handle_event():
    input_pass_values():
    input_to_handler():
    evdev_events():
    evdev_pass_values():
    spin_lock(&client->buffer_lock);
    __pass_event():
    kill_fasync():
    kill_fasync_rcu():
    read_lock(&fa->fa_lock);
    send_sigio():
    read_lock_irqsave(&fown->lock,...);

    &dev->event_lock is HARDIRQ-safe, so interrupts have to be disabled
    while grabbing &fasync_struct.fa_lock, otherwise we invert the lock
    hierarchy. However, since kill_fasync which calls kill_fasync_rcu is
    an exported symbol, it may not necessarily be called with interrupts
    disabled.

    As kill_fasync_rcu may be called with interrupts disabled (for
    example, in the call chain above), we replace calls to
    read_lock/read_unlock on &fasync_struct.fa_lock in kill_fasync_rcu
    with read_lock_irqsave/read_unlock_irqrestore.

    Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
    Signed-off-by: Jeff Layton <jlayton@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/fcntl.c | 5 +++--
    1 file changed, 3 insertions(+), 2 deletions(-)

    diff --git a/fs/fcntl.c b/fs/fcntl.c
    index 932ec1e9f5bf..68added37c15 100644
    --- a/fs/fcntl.c
    +++ b/fs/fcntl.c
    @@ -1004,13 +1004,14 @@ static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
    {
    while (fa) {
    struct fown_struct *fown;
    + unsigned long flags;

    if (fa->magic != FASYNC_MAGIC) {
    printk(KERN_ERR "kill_fasync: bad magic number in "
    "fasync_struct!\n");
    return;
    }
    - read_lock(&fa->fa_lock);
    + read_lock_irqsave(&fa->fa_lock, flags);
    if (fa->fa_file) {
    fown = &fa->fa_file->f_owner;
    /* Don't send SIGURG to processes which have not set a
    @@ -1019,7 +1020,7 @@ static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
    if (!(sig == SIGURG && fown->signum == 0))
    send_sigio(fown, fa->fa_fd, band);
    }
    - read_unlock(&fa->fa_lock);
    + read_unlock_irqrestore(&fa->fa_lock, flags);
    fa = rcu_dereference(fa->fa_next);
    }
    }
    --
    2.30.2


    \
     
     \ /
      Last update: 2021-09-13 16:25    [W:2.648 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site