diff options
author | Greg Kurz <groug@kaod.org> | 2021-06-04 18:11:50 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-07-14 16:55:47 +0200 |
commit | 91c2aa2c64b8d7a973407e6e3e1d012b1a352ad0 (patch) | |
tree | 39cce56b9539f555e4ed538ecbadd0adfdb52094 /fs/fuse/dir.c | |
parent | 53124265fca84159ac4b411f1ea43eba010f974e (diff) | |
download | kernel_replicant_linux-91c2aa2c64b8d7a973407e6e3e1d012b1a352ad0.tar.gz kernel_replicant_linux-91c2aa2c64b8d7a973407e6e3e1d012b1a352ad0.tar.bz2 kernel_replicant_linux-91c2aa2c64b8d7a973407e6e3e1d012b1a352ad0.zip |
fuse: Fix crash in fuse_dentry_automount() error path
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>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index ffa031fe5293..d99bf6207b16 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -340,8 +340,12 @@ static struct vfsmount *fuse_dentry_automount(struct path *path) /* 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); |