mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-19 21:44:08 +00:00
ext4: fix memory leak in ext4_fill_super
static int kthread(void *_create) will return -ENOMEM or -EINTR in case of internal failure or kthread_stop() call happens before threadfn call. To prevent fancy error checking and make code more straightforward we moved all cleanup code out of kmmpd threadfn. Also, dropped struct mmpd_data at all. Now struct super_block is a threadfn data and struct buffer_head embedded into struct ext4_sb_info. Reported-by: syzbot+d9e482e303930fa4f6ff@syzkaller.appspotmail.com Signed-off-by: Pavel Skripkin <paskripkin@gmail.com> Link: https://lore.kernel.org/r/20210430185046.15742-1-paskripkin@gmail.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
1fc57ca5a2
commit
618f003199
3 changed files with 21 additions and 21 deletions
|
@ -1488,6 +1488,7 @@ struct ext4_sb_info {
|
||||||
struct kobject s_kobj;
|
struct kobject s_kobj;
|
||||||
struct completion s_kobj_unregister;
|
struct completion s_kobj_unregister;
|
||||||
struct super_block *s_sb;
|
struct super_block *s_sb;
|
||||||
|
struct buffer_head *s_mmp_bh;
|
||||||
|
|
||||||
/* Journaling */
|
/* Journaling */
|
||||||
struct journal_s *s_journal;
|
struct journal_s *s_journal;
|
||||||
|
@ -3720,6 +3721,9 @@ extern struct ext4_io_end_vec *ext4_last_io_end_vec(ext4_io_end_t *io_end);
|
||||||
/* mmp.c */
|
/* mmp.c */
|
||||||
extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
|
extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
|
||||||
|
|
||||||
|
/* mmp.c */
|
||||||
|
extern void ext4_stop_mmpd(struct ext4_sb_info *sbi);
|
||||||
|
|
||||||
/* verity.c */
|
/* verity.c */
|
||||||
extern const struct fsverity_operations ext4_verityops;
|
extern const struct fsverity_operations ext4_verityops;
|
||||||
|
|
||||||
|
|
|
@ -127,9 +127,9 @@ void __dump_mmp_msg(struct super_block *sb, struct mmp_struct *mmp,
|
||||||
*/
|
*/
|
||||||
static int kmmpd(void *data)
|
static int kmmpd(void *data)
|
||||||
{
|
{
|
||||||
struct super_block *sb = ((struct mmpd_data *) data)->sb;
|
struct super_block *sb = (struct super_block *) data;
|
||||||
struct buffer_head *bh = ((struct mmpd_data *) data)->bh;
|
|
||||||
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
|
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
|
||||||
|
struct buffer_head *bh = EXT4_SB(sb)->s_mmp_bh;
|
||||||
struct mmp_struct *mmp;
|
struct mmp_struct *mmp;
|
||||||
ext4_fsblk_t mmp_block;
|
ext4_fsblk_t mmp_block;
|
||||||
u32 seq = 0;
|
u32 seq = 0;
|
||||||
|
@ -245,12 +245,18 @@ static int kmmpd(void *data)
|
||||||
retval = write_mmp_block(sb, bh);
|
retval = write_mmp_block(sb, bh);
|
||||||
|
|
||||||
exit_thread:
|
exit_thread:
|
||||||
EXT4_SB(sb)->s_mmp_tsk = NULL;
|
|
||||||
kfree(data);
|
|
||||||
brelse(bh);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ext4_stop_mmpd(struct ext4_sb_info *sbi)
|
||||||
|
{
|
||||||
|
if (sbi->s_mmp_tsk) {
|
||||||
|
kthread_stop(sbi->s_mmp_tsk);
|
||||||
|
brelse(sbi->s_mmp_bh);
|
||||||
|
sbi->s_mmp_tsk = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a random new sequence number but make sure it is not greater than
|
* Get a random new sequence number but make sure it is not greater than
|
||||||
* EXT4_MMP_SEQ_MAX.
|
* EXT4_MMP_SEQ_MAX.
|
||||||
|
@ -275,7 +281,6 @@ int ext4_multi_mount_protect(struct super_block *sb,
|
||||||
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
|
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
|
||||||
struct buffer_head *bh = NULL;
|
struct buffer_head *bh = NULL;
|
||||||
struct mmp_struct *mmp = NULL;
|
struct mmp_struct *mmp = NULL;
|
||||||
struct mmpd_data *mmpd_data;
|
|
||||||
u32 seq;
|
u32 seq;
|
||||||
unsigned int mmp_check_interval = le16_to_cpu(es->s_mmp_update_interval);
|
unsigned int mmp_check_interval = le16_to_cpu(es->s_mmp_update_interval);
|
||||||
unsigned int wait_time = 0;
|
unsigned int wait_time = 0;
|
||||||
|
@ -364,24 +369,17 @@ skip:
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
mmpd_data = kmalloc(sizeof(*mmpd_data), GFP_KERNEL);
|
EXT4_SB(sb)->s_mmp_bh = bh;
|
||||||
if (!mmpd_data) {
|
|
||||||
ext4_warning(sb, "not enough memory for mmpd_data");
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
mmpd_data->sb = sb;
|
|
||||||
mmpd_data->bh = bh;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start a kernel thread to update the MMP block periodically.
|
* Start a kernel thread to update the MMP block periodically.
|
||||||
*/
|
*/
|
||||||
EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, mmpd_data, "kmmpd-%.*s",
|
EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, sb, "kmmpd-%.*s",
|
||||||
(int)sizeof(mmp->mmp_bdevname),
|
(int)sizeof(mmp->mmp_bdevname),
|
||||||
bdevname(bh->b_bdev,
|
bdevname(bh->b_bdev,
|
||||||
mmp->mmp_bdevname));
|
mmp->mmp_bdevname));
|
||||||
if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) {
|
if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) {
|
||||||
EXT4_SB(sb)->s_mmp_tsk = NULL;
|
EXT4_SB(sb)->s_mmp_tsk = NULL;
|
||||||
kfree(mmpd_data);
|
|
||||||
ext4_warning(sb, "Unable to create kmmpd thread for %s.",
|
ext4_warning(sb, "Unable to create kmmpd thread for %s.",
|
||||||
sb->s_id);
|
sb->s_id);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
|
@ -1245,8 +1245,8 @@ static void ext4_put_super(struct super_block *sb)
|
||||||
ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
|
ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
|
||||||
sbi->s_ea_block_cache = NULL;
|
sbi->s_ea_block_cache = NULL;
|
||||||
|
|
||||||
if (sbi->s_mmp_tsk)
|
ext4_stop_mmpd(sbi);
|
||||||
kthread_stop(sbi->s_mmp_tsk);
|
|
||||||
brelse(sbi->s_sbh);
|
brelse(sbi->s_sbh);
|
||||||
sb->s_fs_info = NULL;
|
sb->s_fs_info = NULL;
|
||||||
/*
|
/*
|
||||||
|
@ -5186,8 +5186,7 @@ failed_mount3a:
|
||||||
failed_mount3:
|
failed_mount3:
|
||||||
flush_work(&sbi->s_error_work);
|
flush_work(&sbi->s_error_work);
|
||||||
del_timer_sync(&sbi->s_err_report);
|
del_timer_sync(&sbi->s_err_report);
|
||||||
if (sbi->s_mmp_tsk)
|
ext4_stop_mmpd(sbi);
|
||||||
kthread_stop(sbi->s_mmp_tsk);
|
|
||||||
failed_mount2:
|
failed_mount2:
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
group_desc = rcu_dereference(sbi->s_group_desc);
|
group_desc = rcu_dereference(sbi->s_group_desc);
|
||||||
|
@ -5989,8 +5988,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||||
*/
|
*/
|
||||||
ext4_mark_recovery_complete(sb, es);
|
ext4_mark_recovery_complete(sb, es);
|
||||||
}
|
}
|
||||||
if (sbi->s_mmp_tsk)
|
ext4_stop_mmpd(sbi);
|
||||||
kthread_stop(sbi->s_mmp_tsk);
|
|
||||||
} else {
|
} else {
|
||||||
/* Make sure we can mount this feature set readwrite */
|
/* Make sure we can mount this feature set readwrite */
|
||||||
if (ext4_has_feature_readonly(sb) ||
|
if (ext4_has_feature_readonly(sb) ||
|
||||||
|
|
Loading…
Add table
Reference in a new issue