lkml.org 
[lkml]   [2021]   [Jul]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.13 120/800] fuse: Fix crash in fuse_dentry_automount() error path
    Date
    From: Greg Kurz <groug@kaod.org>

    commit d92d88f0568e97c437eeb79d9c9609bd8277406f upstream.

    If fuse_fill_super_submount() returns an error, the error path
    triggers a crash:

    [ 26.206673] BUG: kernel NULL pointer dereference, address: 0000000000000000
    [...]
    [ 26.226362] RIP: 0010:__list_del_entry_valid+0x25/0x90
    [...]
    [ 26.247938] Call Trace:
    [ 26.248300] fuse_mount_remove+0x2c/0x70 [fuse]
    [ 26.248892] virtio_kill_sb+0x22/0x160 [virtiofs]
    [ 26.249487] deactivate_locked_super+0x36/0xa0
    [ 26.250077] fuse_dentry_automount+0x178/0x1a0 [fuse]

    The crash happens because fuse_mount_remove() assumes that the FUSE
    mount was already added to list under the FUSE connection, but this
    only done after fuse_fill_super_submount() has returned success.

    This means that until fuse_fill_super_submount() has returned success,
    the FUSE mount isn't actually owned by the superblock. We should thus
    reclaim ownership by clearing sb->s_fs_info, which will skip the call
    to fuse_mount_remove(), and perform rollback, like virtio_fs_get_tree()
    already does for the root sb.

    Fixes: bf109c64040f ("fuse: implement crossmounts")
    Cc: stable@vger.kernel.org # v5.10+
    Signed-off-by: Greg Kurz <groug@kaod.org>
    Reviewed-by: Max Reitz <mreitz@redhat.com>
    Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/fuse/dir.c | 6 +++++-
    1 file changed, 5 insertions(+), 1 deletion(-)

    --- a/fs/fuse/dir.c
    +++ b/fs/fuse/dir.c
    @@ -339,8 +339,12 @@ static struct vfsmount *fuse_dentry_auto

    /* Initialize superblock, making @mp_fi its root */
    err = fuse_fill_super_submount(sb, mp_fi);
    - if (err)
    + if (err) {
    + fuse_conn_put(fc);
    + kfree(fm);
    + sb->s_fs_info = NULL;
    goto out_put_sb;
    + }

    sb->s_flags |= SB_ACTIVE;
    fsc->root = dget(sb->s_root);

    \
     
     \ /
      Last update: 2021-07-12 10:40    [W:3.910 / U:0.048 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site