lkml.org 
[lkml]   [2018]   [Jul]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 023/101] fuse: fix control dir setup and teardown
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Miklos Szeredi <mszeredi@redhat.com>

    commit 6becdb601bae2a043d7fb9762c4d48699528ea6e upstream.

    syzbot is reporting NULL pointer dereference at fuse_ctl_remove_conn() [1].
    Since fc->ctl_ndents is incremented by fuse_ctl_add_conn() when new_inode()
    failed, fuse_ctl_remove_conn() reaches an inode-less dentry and tries to
    clear d_inode(dentry)->i_private field.

    Fix by only adding the dentry to the array after being fully set up.

    When tearing down the control directory, do d_invalidate() on it to get rid
    of any mounts that might have been added.

    [1] https://syzkaller.appspot.com/bug?id=f396d863067238959c91c0b7cfc10b163638cac6
    Reported-by: syzbot <syzbot+32c236387d66c4516827@syzkaller.appspotmail.com>
    Fixes: bafa96541b25 ("[PATCH] fuse: add control filesystem")
    Cc: <stable@vger.kernel.org> # v2.6.18
    Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/fuse/control.c | 13 ++++++++++---
    1 file changed, 10 insertions(+), 3 deletions(-)

    --- a/fs/fuse/control.c
    +++ b/fs/fuse/control.c
    @@ -211,10 +211,11 @@ static struct dentry *fuse_ctl_add_dentr
    if (!dentry)
    return NULL;

    - fc->ctl_dentry[fc->ctl_ndents++] = dentry;
    inode = new_inode(fuse_control_sb);
    - if (!inode)
    + if (!inode) {
    + dput(dentry);
    return NULL;
    + }

    inode->i_ino = get_next_ino();
    inode->i_mode = mode;
    @@ -228,6 +229,9 @@ static struct dentry *fuse_ctl_add_dentr
    set_nlink(inode, nlink);
    inode->i_private = fc;
    d_add(dentry, inode);
    +
    + fc->ctl_dentry[fc->ctl_ndents++] = dentry;
    +
    return dentry;
    }

    @@ -284,7 +288,10 @@ void fuse_ctl_remove_conn(struct fuse_co
    for (i = fc->ctl_ndents - 1; i >= 0; i--) {
    struct dentry *dentry = fc->ctl_dentry[i];
    d_inode(dentry)->i_private = NULL;
    - d_drop(dentry);
    + if (!i) {
    + /* Get rid of submounts: */
    + d_invalidate(dentry);
    + }
    dput(dentry);
    }
    drop_nlink(d_inode(fuse_control_sb->s_root));

    \
     
     \ /
      Last update: 2018-07-01 20:21    [W:5.212 / U:0.072 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site