Skip to content

Commit dde194a

Browse files
author
Al Viro
committed
afs: fix sget() races, close leak on umount
* set ->s_fs_info in set() callback passed to sget() * allocate the thing and set it up enough for afs_test_super() before making it visible * have it freed in ->kill_sb() (current tree simply leaks it) * have ->put_super() leave ->s_fs_info->volume alone; it's too early for dropping it; do that from ->kill_sb() after having called kill_anon_super(). Signed-off-by: Al Viro <[email protected]>
1 parent d251ed2 commit dde194a

File tree

1 file changed

+32
-41
lines changed

1 file changed

+32
-41
lines changed

fs/afs/super.c

+32-41
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@
3131
static void afs_i_init_once(void *foo);
3232
static struct dentry *afs_mount(struct file_system_type *fs_type,
3333
int flags, const char *dev_name, void *data);
34+
static void afs_kill_super(struct super_block *sb);
3435
static struct inode *afs_alloc_inode(struct super_block *sb);
35-
static void afs_put_super(struct super_block *sb);
3636
static void afs_destroy_inode(struct inode *inode);
3737
static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
3838

3939
struct file_system_type afs_fs_type = {
4040
.owner = THIS_MODULE,
4141
.name = "afs",
4242
.mount = afs_mount,
43-
.kill_sb = kill_anon_super,
43+
.kill_sb = afs_kill_super,
4444
.fs_flags = 0,
4545
};
4646

@@ -50,7 +50,6 @@ static const struct super_operations afs_super_ops = {
5050
.drop_inode = afs_drop_inode,
5151
.destroy_inode = afs_destroy_inode,
5252
.evict_inode = afs_evict_inode,
53-
.put_super = afs_put_super,
5453
.show_options = generic_show_options,
5554
};
5655

@@ -282,42 +281,37 @@ static int afs_parse_device_name(struct afs_mount_params *params,
282281
*/
283282
static int afs_test_super(struct super_block *sb, void *data)
284283
{
285-
struct afs_mount_params *params = data;
284+
struct afs_super_info *as1 = data;
286285
struct afs_super_info *as = sb->s_fs_info;
287286

288-
return as->volume == params->volume;
287+
return as->volume == as1->volume;
288+
}
289+
290+
static int afs_set_super(struct super_block *sb, void *data)
291+
{
292+
sb->s_fs_info = data;
293+
return set_anon_super(sb, NULL);
289294
}
290295

291296
/*
292297
* fill in the superblock
293298
*/
294-
static int afs_fill_super(struct super_block *sb, void *data)
299+
static int afs_fill_super(struct super_block *sb,
300+
struct afs_mount_params *params)
295301
{
296-
struct afs_mount_params *params = data;
297-
struct afs_super_info *as = NULL;
302+
struct afs_super_info *as = sb->s_fs_info;
298303
struct afs_fid fid;
299304
struct dentry *root = NULL;
300305
struct inode *inode = NULL;
301306
int ret;
302307

303308
_enter("");
304309

305-
/* allocate a superblock info record */
306-
as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
307-
if (!as) {
308-
_leave(" = -ENOMEM");
309-
return -ENOMEM;
310-
}
311-
312-
afs_get_volume(params->volume);
313-
as->volume = params->volume;
314-
315310
/* fill in the superblock */
316311
sb->s_blocksize = PAGE_CACHE_SIZE;
317312
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
318313
sb->s_magic = AFS_FS_MAGIC;
319314
sb->s_op = &afs_super_ops;
320-
sb->s_fs_info = as;
321315
sb->s_bdi = &as->volume->bdi;
322316

323317
/* allocate the root inode and dentry */
@@ -326,7 +320,7 @@ static int afs_fill_super(struct super_block *sb, void *data)
326320
fid.unique = 1;
327321
inode = afs_iget(sb, params->key, &fid, NULL, NULL);
328322
if (IS_ERR(inode))
329-
goto error_inode;
323+
return PTR_ERR(inode);
330324

331325
if (params->autocell)
332326
set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
@@ -342,16 +336,8 @@ static int afs_fill_super(struct super_block *sb, void *data)
342336
_leave(" = 0");
343337
return 0;
344338

345-
error_inode:
346-
ret = PTR_ERR(inode);
347-
inode = NULL;
348339
error:
349340
iput(inode);
350-
afs_put_volume(as->volume);
351-
kfree(as);
352-
353-
sb->s_fs_info = NULL;
354-
355341
_leave(" = %d", ret);
356342
return ret;
357343
}
@@ -367,6 +353,7 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
367353
struct afs_volume *vol;
368354
struct key *key;
369355
char *new_opts = kstrdup(options, GFP_KERNEL);
356+
struct afs_super_info *as;
370357
int ret;
371358

372359
_enter(",,%s,%p", dev_name, options);
@@ -399,12 +386,22 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
399386
ret = PTR_ERR(vol);
400387
goto error;
401388
}
402-
params.volume = vol;
389+
390+
/* allocate a superblock info record */
391+
as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
392+
if (!as) {
393+
ret = -ENOMEM;
394+
afs_put_volume(vol);
395+
goto error;
396+
}
397+
as->volume = vol;
403398

404399
/* allocate a deviceless superblock */
405-
sb = sget(fs_type, afs_test_super, set_anon_super, &params);
400+
sb = sget(fs_type, afs_test_super, afs_set_super, as);
406401
if (IS_ERR(sb)) {
407402
ret = PTR_ERR(sb);
403+
afs_put_volume(vol);
404+
kfree(as);
408405
goto error;
409406
}
410407

@@ -422,35 +419,29 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
422419
} else {
423420
_debug("reuse");
424421
ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
422+
afs_put_volume(vol);
423+
kfree(as);
425424
}
426425

427-
afs_put_volume(params.volume);
428426
afs_put_cell(params.cell);
429427
kfree(new_opts);
430428
_leave(" = 0 [%p]", sb);
431429
return dget(sb->s_root);
432430

433431
error:
434-
afs_put_volume(params.volume);
435432
afs_put_cell(params.cell);
436433
key_put(params.key);
437434
kfree(new_opts);
438435
_leave(" = %d", ret);
439436
return ERR_PTR(ret);
440437
}
441438

442-
/*
443-
* finish the unmounting process on the superblock
444-
*/
445-
static void afs_put_super(struct super_block *sb)
439+
static void afs_kill_super(struct super_block *sb)
446440
{
447441
struct afs_super_info *as = sb->s_fs_info;
448-
449-
_enter("");
450-
442+
kill_anon_super(sb);
451443
afs_put_volume(as->volume);
452-
453-
_leave("");
444+
kfree(as);
454445
}
455446

456447
/*

0 commit comments

Comments
 (0)