mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-11 07:39:47 +00:00
jbd2: fix use after free in jbd2_journal_dirty_metadata()
jbd2_journal_dirty_metadata() didn't get a reference to journal_head it was working with. This is OK in most of the cases since the journal head should be attached to a transaction but in rare occasions when we are journalling data, __ext4_journalled_writepage() can race with jbd2_journal_invalidatepage() stripping buffers from a page and thus journal head can be freed under hands of jbd2_journal_dirty_metadata(). Fix the problem by getting own journal head reference in jbd2_journal_dirty_metadata() (and also in jbd2_journal_set_triggers() which can possibly have the same issue). Reported-by: Zheng Liu <gnehzuil.liu@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: stable@vger.kernel.org
This commit is contained in:
parent
386ad67c9a
commit
ad56edad08
@ -1065,9 +1065,12 @@ out:
|
||||
void jbd2_journal_set_triggers(struct buffer_head *bh,
|
||||
struct jbd2_buffer_trigger_type *type)
|
||||
{
|
||||
struct journal_head *jh = bh2jh(bh);
|
||||
struct journal_head *jh = jbd2_journal_grab_journal_head(bh);
|
||||
|
||||
if (WARN_ON(!jh))
|
||||
return;
|
||||
jh->b_triggers = type;
|
||||
jbd2_journal_put_journal_head(jh);
|
||||
}
|
||||
|
||||
void jbd2_buffer_frozen_trigger(struct journal_head *jh, void *mapped_data,
|
||||
@ -1119,17 +1122,18 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
|
||||
{
|
||||
transaction_t *transaction = handle->h_transaction;
|
||||
journal_t *journal = transaction->t_journal;
|
||||
struct journal_head *jh = bh2jh(bh);
|
||||
struct journal_head *jh;
|
||||
int ret = 0;
|
||||
|
||||
jbd_debug(5, "journal_head %p\n", jh);
|
||||
JBUFFER_TRACE(jh, "entry");
|
||||
if (is_handle_aborted(handle))
|
||||
goto out;
|
||||
if (!buffer_jbd(bh)) {
|
||||
jh = jbd2_journal_grab_journal_head(bh);
|
||||
if (!jh) {
|
||||
ret = -EUCLEAN;
|
||||
goto out;
|
||||
}
|
||||
jbd_debug(5, "journal_head %p\n", jh);
|
||||
JBUFFER_TRACE(jh, "entry");
|
||||
|
||||
jbd_lock_bh_state(bh);
|
||||
|
||||
@ -1220,6 +1224,7 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
|
||||
spin_unlock(&journal->j_list_lock);
|
||||
out_unlock_bh:
|
||||
jbd_unlock_bh_state(bh);
|
||||
jbd2_journal_put_journal_head(jh);
|
||||
out:
|
||||
JBUFFER_TRACE(jh, "exit");
|
||||
WARN_ON(ret); /* All errors are bugs, so dump the stack */
|
||||
|
Loading…
x
Reference in New Issue
Block a user