jbd2: Fix oops in jbd2_journal_init_inode() on corrupted fs
On 32-bit system with CONFIG_LBD getblk can fail because provided block number is too big. Add error checks so we fail gracefully if getblk() returns NULL (which can also happen on memory allocation failures). Thanks to David Maciejak from Fortinet's FortiGuard Global Security Research Team for reporting this bug. http://bugzilla.kernel.org/show_bug.cgi?id=12370 Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> cc: stable@kernel.org
This commit is contained in:
parent
83982b6f47
commit
4b905671d2
|
@ -632,6 +632,8 @@ struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
|
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
|
||||||
|
if (!bh)
|
||||||
|
return NULL;
|
||||||
lock_buffer(bh);
|
lock_buffer(bh);
|
||||||
memset(bh->b_data, 0, journal->j_blocksize);
|
memset(bh->b_data, 0, journal->j_blocksize);
|
||||||
set_buffer_uptodate(bh);
|
set_buffer_uptodate(bh);
|
||||||
|
@ -1021,15 +1023,14 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
|
||||||
|
|
||||||
/* journal descriptor can store up to n blocks -bzzz */
|
/* journal descriptor can store up to n blocks -bzzz */
|
||||||
journal->j_blocksize = blocksize;
|
journal->j_blocksize = blocksize;
|
||||||
|
jbd2_stats_proc_init(journal);
|
||||||
n = journal->j_blocksize / sizeof(journal_block_tag_t);
|
n = journal->j_blocksize / sizeof(journal_block_tag_t);
|
||||||
journal->j_wbufsize = n;
|
journal->j_wbufsize = n;
|
||||||
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
|
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
|
||||||
if (!journal->j_wbuf) {
|
if (!journal->j_wbuf) {
|
||||||
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
|
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
|
||||||
__func__);
|
__func__);
|
||||||
kfree(journal);
|
goto out_err;
|
||||||
journal = NULL;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
journal->j_dev = bdev;
|
journal->j_dev = bdev;
|
||||||
journal->j_fs_dev = fs_dev;
|
journal->j_fs_dev = fs_dev;
|
||||||
|
@ -1039,14 +1040,22 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
|
||||||
p = journal->j_devname;
|
p = journal->j_devname;
|
||||||
while ((p = strchr(p, '/')))
|
while ((p = strchr(p, '/')))
|
||||||
*p = '!';
|
*p = '!';
|
||||||
jbd2_stats_proc_init(journal);
|
|
||||||
|
|
||||||
bh = __getblk(journal->j_dev, start, journal->j_blocksize);
|
bh = __getblk(journal->j_dev, start, journal->j_blocksize);
|
||||||
J_ASSERT(bh != NULL);
|
if (!bh) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"%s: Cannot get buffer for journal superblock\n",
|
||||||
|
__func__);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
journal->j_sb_buffer = bh;
|
journal->j_sb_buffer = bh;
|
||||||
journal->j_superblock = (journal_superblock_t *)bh->b_data;
|
journal->j_superblock = (journal_superblock_t *)bh->b_data;
|
||||||
out:
|
|
||||||
return journal;
|
return journal;
|
||||||
|
out_err:
|
||||||
|
jbd2_stats_proc_exit(journal);
|
||||||
|
kfree(journal);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1094,9 +1103,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
|
||||||
if (!journal->j_wbuf) {
|
if (!journal->j_wbuf) {
|
||||||
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
|
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
|
||||||
__func__);
|
__func__);
|
||||||
jbd2_stats_proc_exit(journal);
|
goto out_err;
|
||||||
kfree(journal);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = jbd2_journal_bmap(journal, 0, &blocknr);
|
err = jbd2_journal_bmap(journal, 0, &blocknr);
|
||||||
|
@ -1104,17 +1111,24 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
|
printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
|
||||||
__func__);
|
__func__);
|
||||||
jbd2_stats_proc_exit(journal);
|
goto out_err;
|
||||||
kfree(journal);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
|
bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
|
||||||
J_ASSERT(bh != NULL);
|
if (!bh) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"%s: Cannot get buffer for journal superblock\n",
|
||||||
|
__func__);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
journal->j_sb_buffer = bh;
|
journal->j_sb_buffer = bh;
|
||||||
journal->j_superblock = (journal_superblock_t *)bh->b_data;
|
journal->j_superblock = (journal_superblock_t *)bh->b_data;
|
||||||
|
|
||||||
return journal;
|
return journal;
|
||||||
|
out_err:
|
||||||
|
jbd2_stats_proc_exit(journal);
|
||||||
|
kfree(journal);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue