Patchwork [3.5.y.z,extended,stable] Patch "jbd2: fix use after free in jbd2_journal_dirty_metadata()" has been added to staging queue

mail settings
Submitter Luis Henriques
Date March 25, 2013, 6 p.m.
Message ID <>
Download mbox | patch
Permalink /patch/230863/
State New
Headers show


Luis Henriques - March 25, 2013, 6 p.m.
This is a note to let you know that I have just added a patch titled

    jbd2: fix use after free in jbd2_journal_dirty_metadata()

to the linux-3.5.y-queue branch of the 3.5.y.z extended stable tree 
which can be found at:;a=shortlog;h=refs/heads/linux-3.5.y-queue

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.5.y.z tree, see



From 8907b72dd40afbaf99a9ad56d640e9ffd0718084 Mon Sep 17 00:00:00 2001
From: Jan Kara <>
Date: Mon, 11 Mar 2013 13:24:56 -0400
Subject: [PATCH] jbd2: fix use after free in jbd2_journal_dirty_metadata()

commit ad56edad089b56300fd13bb9eeb7d0424d978239 upstream.

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 <>
Signed-off-by: Jan Kara <>
Signed-off-by: "Theodore Ts'o" <>
Luis Henriques <>
 fs/jbd2/transaction.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)



diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 2fb20f5..399e4ee 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1047,9 +1047,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,
@@ -1101,17 +1104,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");


@@ -1202,6 +1206,7 @@  int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
+	jbd2_journal_put_journal_head(jh);
 	JBUFFER_TRACE(jh, "exit");
 	WARN_ON(ret);	/* All errors are bugs, so dump the stack */