Skip to content

Commit 0d51521

Browse files
AstralBobswhiteho
authored andcommitted
GFS2: Add kobject release method
This patch adds a kobject release function that properly maintains the kobject use count, so that accesses to the sysfs files do not cause an access to freed kernel memory after an unmount. Signed-off-by: Bob Peterson <[email protected]> Signed-off-by: Steven Whitehouse <[email protected]>
1 parent 0fe2f1e commit 0d51521

File tree

2 files changed

+42
-15
lines changed

2 files changed

+42
-15
lines changed

fs/gfs2/ops_fstype.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,20 +1118,33 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
11181118
}
11191119

11201120
error = init_names(sdp, silent);
1121-
if (error)
1122-
goto fail;
1121+
if (error) {
1122+
/* In this case, we haven't initialized sysfs, so we have to
1123+
manually free the sdp. */
1124+
free_percpu(sdp->sd_lkstats);
1125+
kfree(sdp);
1126+
sb->s_fs_info = NULL;
1127+
return error;
1128+
}
11231129

11241130
snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name);
11251131

1126-
gfs2_create_debugfs_file(sdp);
1127-
11281132
error = gfs2_sys_fs_add(sdp);
1133+
/*
1134+
* If we hit an error here, gfs2_sys_fs_add will have called function
1135+
* kobject_put which causes the sysfs usage count to go to zero, which
1136+
* causes sysfs to call function gfs2_sbd_release, which frees sdp.
1137+
* Subsequent error paths here will call gfs2_sys_fs_del, which also
1138+
* kobject_put to free sdp.
1139+
*/
11291140
if (error)
1130-
goto fail;
1141+
return error;
1142+
1143+
gfs2_create_debugfs_file(sdp);
11311144

11321145
error = gfs2_lm_mount(sdp, silent);
11331146
if (error)
1134-
goto fail_sys;
1147+
goto fail_debug;
11351148

11361149
error = init_locking(sdp, &mount_gh, DO);
11371150
if (error)
@@ -1215,12 +1228,12 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
12151228
fail_lm:
12161229
gfs2_gl_hash_clear(sdp);
12171230
gfs2_lm_unmount(sdp);
1218-
fail_sys:
1219-
gfs2_sys_fs_del(sdp);
1220-
fail:
1231+
fail_debug:
12211232
gfs2_delete_debugfs_file(sdp);
12221233
free_percpu(sdp->sd_lkstats);
1223-
kfree(sdp);
1234+
/* gfs2_sys_fs_del must be the last thing we do, since it causes
1235+
* sysfs to call function gfs2_sbd_release, which frees sdp. */
1236+
gfs2_sys_fs_del(sdp);
12241237
sb->s_fs_info = NULL;
12251238
return error;
12261239
}
@@ -1390,10 +1403,9 @@ static void gfs2_kill_sb(struct super_block *sb)
13901403
sdp->sd_root_dir = NULL;
13911404
sdp->sd_master_dir = NULL;
13921405
shrink_dcache_sb(sb);
1393-
kill_block_super(sb);
13941406
gfs2_delete_debugfs_file(sdp);
13951407
free_percpu(sdp->sd_lkstats);
1396-
kfree(sdp);
1408+
kill_block_super(sb);
13971409
}
13981410

13991411
struct file_system_type gfs2_fs_type = {

fs/gfs2/sys.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,15 @@ static struct attribute *gfs2_attrs[] = {
276276
NULL,
277277
};
278278

279+
static void gfs2_sbd_release(struct kobject *kobj)
280+
{
281+
struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
282+
283+
kfree(sdp);
284+
}
285+
279286
static struct kobj_type gfs2_ktype = {
287+
.release = gfs2_sbd_release,
280288
.default_attrs = gfs2_attrs,
281289
.sysfs_ops = &gfs2_attr_ops,
282290
};
@@ -583,6 +591,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
583591
char ro[20];
584592
char spectator[20];
585593
char *envp[] = { ro, spectator, NULL };
594+
int sysfs_frees_sdp = 0;
586595

587596
sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);
588597
sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0);
@@ -591,8 +600,10 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
591600
error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
592601
"%s", sdp->sd_table_name);
593602
if (error)
594-
goto fail;
603+
goto fail_reg;
595604

605+
sysfs_frees_sdp = 1; /* Freeing sdp is now done by sysfs calling
606+
function gfs2_sbd_release. */
596607
error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
597608
if (error)
598609
goto fail_reg;
@@ -615,9 +626,13 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
615626
fail_tune:
616627
sysfs_remove_group(&sdp->sd_kobj, &tune_group);
617628
fail_reg:
618-
kobject_put(&sdp->sd_kobj);
619-
fail:
629+
free_percpu(sdp->sd_lkstats);
620630
fs_err(sdp, "error %d adding sysfs files", error);
631+
if (sysfs_frees_sdp)
632+
kobject_put(&sdp->sd_kobj);
633+
else
634+
kfree(sdp);
635+
sb->s_fs_info = NULL;
621636
return error;
622637
}
623638

0 commit comments

Comments
 (0)