Skip to content

Commit 5ab2ed0

Browse files
committed
Merge tag 'fuse-fixes-5.15-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse fixes from Miklos Szeredi: "Syzbot discovered a race in case of reusing the fuse sb (introduced in this cycle). Fix it by doing the s_fs_info initialization at the proper place" * tag 'fuse-fixes-5.15-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: clean up error exits in fuse_fill_super() fuse: always initialize sb->s_fs_info fuse: clean up fuse_mount destruction fuse: get rid of fuse_put_super() fuse: check s_root when destroying sb
2 parents 477b4e8 + 964d32e commit 5ab2ed0

File tree

3 files changed

+46
-56
lines changed

3 files changed

+46
-56
lines changed

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,9 @@ int fuse_init_fs_context_submount(struct fs_context *fsc);
11211121
*/
11221122
void fuse_conn_destroy(struct fuse_mount *fm);
11231123

1124+
/* Drop the connection and free the fuse mount */
1125+
void fuse_mount_destroy(struct fuse_mount *fm);
1126+
11241127
/**
11251128
* Add connection to control filesystem
11261129
*/

fs/fuse/inode.c

Lines changed: 39 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -457,14 +457,6 @@ static void fuse_send_destroy(struct fuse_mount *fm)
457457
}
458458
}
459459

460-
static void fuse_put_super(struct super_block *sb)
461-
{
462-
struct fuse_mount *fm = get_fuse_mount_super(sb);
463-
464-
fuse_conn_put(fm->fc);
465-
kfree(fm);
466-
}
467-
468460
static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
469461
{
470462
stbuf->f_type = FUSE_SUPER_MAGIC;
@@ -1003,7 +995,6 @@ static const struct super_operations fuse_super_operations = {
1003995
.evict_inode = fuse_evict_inode,
1004996
.write_inode = fuse_write_inode,
1005997
.drop_inode = generic_delete_inode,
1006-
.put_super = fuse_put_super,
1007998
.umount_begin = fuse_umount_begin,
1008999
.statfs = fuse_statfs,
10091000
.sync_fs = fuse_sync_fs,
@@ -1424,20 +1415,17 @@ static int fuse_get_tree_submount(struct fs_context *fsc)
14241415
if (!fm)
14251416
return -ENOMEM;
14261417

1418+
fm->fc = fuse_conn_get(fc);
14271419
fsc->s_fs_info = fm;
14281420
sb = sget_fc(fsc, NULL, set_anon_super_fc);
1429-
if (IS_ERR(sb)) {
1430-
kfree(fm);
1421+
if (fsc->s_fs_info)
1422+
fuse_mount_destroy(fm);
1423+
if (IS_ERR(sb))
14311424
return PTR_ERR(sb);
1432-
}
1433-
fm->fc = fuse_conn_get(fc);
14341425

14351426
/* Initialize superblock, making @mp_fi its root */
14361427
err = fuse_fill_super_submount(sb, mp_fi);
14371428
if (err) {
1438-
fuse_conn_put(fc);
1439-
kfree(fm);
1440-
sb->s_fs_info = NULL;
14411429
deactivate_locked_super(sb);
14421430
return err;
14431431
}
@@ -1569,8 +1557,6 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
15691557
{
15701558
struct fuse_fs_context *ctx = fsc->fs_private;
15711559
int err;
1572-
struct fuse_conn *fc;
1573-
struct fuse_mount *fm;
15741560

15751561
if (!ctx->file || !ctx->rootmode_present ||
15761562
!ctx->user_id_present || !ctx->group_id_present)
@@ -1580,42 +1566,18 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
15801566
* Require mount to happen from the same user namespace which
15811567
* opened /dev/fuse to prevent potential attacks.
15821568
*/
1583-
err = -EINVAL;
15841569
if ((ctx->file->f_op != &fuse_dev_operations) ||
15851570
(ctx->file->f_cred->user_ns != sb->s_user_ns))
1586-
goto err;
1571+
return -EINVAL;
15871572
ctx->fudptr = &ctx->file->private_data;
15881573

1589-
fc = kmalloc(sizeof(*fc), GFP_KERNEL);
1590-
err = -ENOMEM;
1591-
if (!fc)
1592-
goto err;
1593-
1594-
fm = kzalloc(sizeof(*fm), GFP_KERNEL);
1595-
if (!fm) {
1596-
kfree(fc);
1597-
goto err;
1598-
}
1599-
1600-
fuse_conn_init(fc, fm, sb->s_user_ns, &fuse_dev_fiq_ops, NULL);
1601-
fc->release = fuse_free_conn;
1602-
1603-
sb->s_fs_info = fm;
1604-
16051574
err = fuse_fill_super_common(sb, ctx);
16061575
if (err)
1607-
goto err_put_conn;
1576+
return err;
16081577
/* file->private_data shall be visible on all CPUs after this */
16091578
smp_mb();
16101579
fuse_send_init(get_fuse_mount_super(sb));
16111580
return 0;
1612-
1613-
err_put_conn:
1614-
fuse_conn_put(fc);
1615-
kfree(fm);
1616-
sb->s_fs_info = NULL;
1617-
err:
1618-
return err;
16191581
}
16201582

16211583
/*
@@ -1637,22 +1599,40 @@ static int fuse_get_tree(struct fs_context *fsc)
16371599
{
16381600
struct fuse_fs_context *ctx = fsc->fs_private;
16391601
struct fuse_dev *fud;
1602+
struct fuse_conn *fc;
1603+
struct fuse_mount *fm;
16401604
struct super_block *sb;
16411605
int err;
16421606

1607+
fc = kmalloc(sizeof(*fc), GFP_KERNEL);
1608+
if (!fc)
1609+
return -ENOMEM;
1610+
1611+
fm = kzalloc(sizeof(*fm), GFP_KERNEL);
1612+
if (!fm) {
1613+
kfree(fc);
1614+
return -ENOMEM;
1615+
}
1616+
1617+
fuse_conn_init(fc, fm, fsc->user_ns, &fuse_dev_fiq_ops, NULL);
1618+
fc->release = fuse_free_conn;
1619+
1620+
fsc->s_fs_info = fm;
1621+
16431622
if (ctx->fd_present)
16441623
ctx->file = fget(ctx->fd);
16451624

16461625
if (IS_ENABLED(CONFIG_BLOCK) && ctx->is_bdev) {
16471626
err = get_tree_bdev(fsc, fuse_fill_super);
1648-
goto out_fput;
1627+
goto out;
16491628
}
16501629
/*
16511630
* While block dev mount can be initialized with a dummy device fd
16521631
* (found by device name), normal fuse mounts can't
16531632
*/
1633+
err = -EINVAL;
16541634
if (!ctx->file)
1655-
return -EINVAL;
1635+
goto out;
16561636

16571637
/*
16581638
* Allow creating a fuse mount with an already initialized fuse
@@ -1668,7 +1648,9 @@ static int fuse_get_tree(struct fs_context *fsc)
16681648
} else {
16691649
err = get_tree_nodev(fsc, fuse_fill_super);
16701650
}
1671-
out_fput:
1651+
out:
1652+
if (fsc->s_fs_info)
1653+
fuse_mount_destroy(fm);
16721654
if (ctx->file)
16731655
fput(ctx->file);
16741656
return err;
@@ -1747,17 +1729,25 @@ static void fuse_sb_destroy(struct super_block *sb)
17471729
struct fuse_mount *fm = get_fuse_mount_super(sb);
17481730
bool last;
17491731

1750-
if (fm) {
1732+
if (sb->s_root) {
17511733
last = fuse_mount_remove(fm);
17521734
if (last)
17531735
fuse_conn_destroy(fm);
17541736
}
17551737
}
17561738

1739+
void fuse_mount_destroy(struct fuse_mount *fm)
1740+
{
1741+
fuse_conn_put(fm->fc);
1742+
kfree(fm);
1743+
}
1744+
EXPORT_SYMBOL(fuse_mount_destroy);
1745+
17571746
static void fuse_kill_sb_anon(struct super_block *sb)
17581747
{
17591748
fuse_sb_destroy(sb);
17601749
kill_anon_super(sb);
1750+
fuse_mount_destroy(get_fuse_mount_super(sb));
17611751
}
17621752

17631753
static struct file_system_type fuse_fs_type = {
@@ -1775,6 +1765,7 @@ static void fuse_kill_sb_blk(struct super_block *sb)
17751765
{
17761766
fuse_sb_destroy(sb);
17771767
kill_block_super(sb);
1768+
fuse_mount_destroy(get_fuse_mount_super(sb));
17781769
}
17791770

17801771
static struct file_system_type fuseblk_fs_type = {

fs/fuse/virtio_fs.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,12 +1394,13 @@ static void virtio_kill_sb(struct super_block *sb)
13941394
bool last;
13951395

13961396
/* If mount failed, we can still be called without any fc */
1397-
if (fm) {
1397+
if (sb->s_root) {
13981398
last = fuse_mount_remove(fm);
13991399
if (last)
14001400
virtio_fs_conn_destroy(fm);
14011401
}
14021402
kill_anon_super(sb);
1403+
fuse_mount_destroy(fm);
14031404
}
14041405

14051406
static int virtio_fs_test_super(struct super_block *sb,
@@ -1455,19 +1456,14 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
14551456

14561457
fsc->s_fs_info = fm;
14571458
sb = sget_fc(fsc, virtio_fs_test_super, set_anon_super_fc);
1458-
if (fsc->s_fs_info) {
1459-
fuse_conn_put(fc);
1460-
kfree(fm);
1461-
}
1459+
if (fsc->s_fs_info)
1460+
fuse_mount_destroy(fm);
14621461
if (IS_ERR(sb))
14631462
return PTR_ERR(sb);
14641463

14651464
if (!sb->s_root) {
14661465
err = virtio_fs_fill_super(sb, fsc);
14671466
if (err) {
1468-
fuse_conn_put(fc);
1469-
kfree(fm);
1470-
sb->s_fs_info = NULL;
14711467
deactivate_locked_super(sb);
14721468
return err;
14731469
}

0 commit comments

Comments
 (0)