Skip to content

Commit d251ed2

Browse files
author
Al Viro
committed
ubifs: fix sget races
* allocate ubifs_info in ->mount(), fill it enough for sb_test() and set ->s_fs_info to it in set() callback passed to sget(). * do *not* free it in ->put_super(); do that in ->kill_sb() after we'd done kill_anon_super(). * don't free it in ubifs_fill_super() either - deactivate_locked_super() done by caller when ubifs_fill_super() returns an error will take care of that sucker. * get rid of kludge with passing ubi to ubifs_fill_super() in ->s_fs_info; we only need it in alloc_ubifs_info(), so ubifs_fill_super() will need only ubifs_info. Which it will find in ->s_fs_info just fine, no need to reassign anything... As the result, sb_test() becomes safe to apply to all superblocks that can be found by sget() (and a kludge with temporary use of ->s_fs_info to store a pointer to very different structure goes away). Signed-off-by: Al Viro <[email protected]>
1 parent b1c27ab commit d251ed2

File tree

1 file changed

+30
-24
lines changed

1 file changed

+30
-24
lines changed

fs/ubifs/super.c

+30-24
Original file line numberDiff line numberDiff line change
@@ -1848,7 +1848,6 @@ static void ubifs_put_super(struct super_block *sb)
18481848
bdi_destroy(&c->bdi);
18491849
ubi_close_volume(c->ubi);
18501850
mutex_unlock(&c->umount_mutex);
1851-
kfree(c);
18521851
}
18531852

18541853
static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -2020,21 +2019,16 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
20202019

20212020
static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
20222021
{
2023-
struct ubi_volume_desc *ubi = sb->s_fs_info;
2024-
struct ubifs_info *c;
2022+
struct ubifs_info *c = sb->s_fs_info;
20252023
struct inode *root;
20262024
int err;
20272025

2028-
c = alloc_ubifs_info(ubi);
2029-
if (!c)
2030-
return -ENOMEM;
2031-
20322026
c->vfs_sb = sb;
20332027
/* Re-open the UBI device in read-write mode */
20342028
c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE);
20352029
if (IS_ERR(c->ubi)) {
20362030
err = PTR_ERR(c->ubi);
2037-
goto out_free;
2031+
goto out;
20382032
}
20392033

20402034
/*
@@ -2100,24 +2094,29 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
21002094
bdi_destroy(&c->bdi);
21012095
out_close:
21022096
ubi_close_volume(c->ubi);
2103-
out_free:
2104-
kfree(c);
2097+
out:
21052098
return err;
21062099
}
21072100

21082101
static int sb_test(struct super_block *sb, void *data)
21092102
{
2110-
dev_t *dev = data;
2103+
struct ubifs_info *c1 = data;
21112104
struct ubifs_info *c = sb->s_fs_info;
21122105

2113-
return c->vi.cdev == *dev;
2106+
return c->vi.cdev == c1->vi.cdev;
2107+
}
2108+
2109+
static int sb_set(struct super_block *sb, void *data)
2110+
{
2111+
sb->s_fs_info = data;
2112+
return set_anon_super(sb, NULL);
21142113
}
21152114

21162115
static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
21172116
const char *name, void *data)
21182117
{
21192118
struct ubi_volume_desc *ubi;
2120-
struct ubi_volume_info vi;
2119+
struct ubifs_info *c;
21212120
struct super_block *sb;
21222121
int err;
21232122

@@ -2134,19 +2133,24 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
21342133
name, (int)PTR_ERR(ubi));
21352134
return ERR_CAST(ubi);
21362135
}
2137-
ubi_get_volume_info(ubi, &vi);
21382136

2139-
dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id);
2137+
c = alloc_ubifs_info(ubi);
2138+
if (!c) {
2139+
err = -ENOMEM;
2140+
goto out_close;
2141+
}
2142+
2143+
dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
21402144

2141-
sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev);
2145+
sb = sget(fs_type, sb_test, sb_set, c);
21422146
if (IS_ERR(sb)) {
21432147
err = PTR_ERR(sb);
2144-
goto out_close;
2148+
kfree(c);
21452149
}
21462150

21472151
if (sb->s_root) {
21482152
struct ubifs_info *c1 = sb->s_fs_info;
2149-
2153+
kfree(c);
21502154
/* A new mount point for already mounted UBIFS */
21512155
dbg_gen("this ubi volume is already mounted");
21522156
if (!!(flags & MS_RDONLY) != c1->ro_mount) {
@@ -2155,11 +2159,6 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
21552159
}
21562160
} else {
21572161
sb->s_flags = flags;
2158-
/*
2159-
* Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is
2160-
* replaced by 'c'.
2161-
*/
2162-
sb->s_fs_info = ubi;
21632162
err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
21642163
if (err)
21652164
goto out_deact;
@@ -2179,11 +2178,18 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
21792178
return ERR_PTR(err);
21802179
}
21812180

2181+
static void kill_ubifs_super(struct super_block *s)
2182+
{
2183+
struct ubifs_info *c = s->s_fs_info;
2184+
kill_anon_super(s);
2185+
kfree(c);
2186+
}
2187+
21822188
static struct file_system_type ubifs_fs_type = {
21832189
.name = "ubifs",
21842190
.owner = THIS_MODULE,
21852191
.mount = ubifs_mount,
2186-
.kill_sb = kill_anon_super,
2192+
.kill_sb = kill_ubifs_super,
21872193
};
21882194

21892195
/*

0 commit comments

Comments
 (0)