Commit a61d90d75d0f9e86432c45b496b4b0fbf0fd03dc
Committed by
Linus Torvalds
1 parent
463aea1a1c
Exists in
master
and in
39 other branches
jbd: fix race in buffer processing in commit code
In commit code, we scan buffers attached to a transaction. During this scan, we sometimes have to drop j_list_lock and then we recheck whether the journal buffer head didn't get freed by journal_try_to_free_buffers(). But checking for buffer_jbd(bh) isn't enough because a new journal head could get attached to our buffer head. So add a check whether the journal head remained the same and whether it's still at the same transaction and list. This is a nasty bug and can cause problems like memory corruption (use after free) or trigger various assertions in JBD code (observed). Signed-off-by: Jan Kara <jack@suse.cz> Cc: <stable@kernel.org> Cc: <linux-ext4@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 4 additions and 2 deletions Side-by-side Diff
fs/jbd/commit.c
... | ... | @@ -241,7 +241,7 @@ |
241 | 241 | spin_lock(&journal->j_list_lock); |
242 | 242 | } |
243 | 243 | /* Someone already cleaned up the buffer? */ |
244 | - if (!buffer_jbd(bh) | |
244 | + if (!buffer_jbd(bh) || bh2jh(bh) != jh | |
245 | 245 | || jh->b_transaction != commit_transaction |
246 | 246 | || jh->b_jlist != BJ_SyncData) { |
247 | 247 | jbd_unlock_bh_state(bh); |
... | ... | @@ -478,7 +478,9 @@ |
478 | 478 | spin_lock(&journal->j_list_lock); |
479 | 479 | continue; |
480 | 480 | } |
481 | - if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) { | |
481 | + if (buffer_jbd(bh) && bh2jh(bh) == jh && | |
482 | + jh->b_transaction == commit_transaction && | |
483 | + jh->b_jlist == BJ_Locked) { | |
482 | 484 | __journal_unfile_buffer(jh); |
483 | 485 | jbd_unlock_bh_state(bh); |
484 | 486 | journal_remove_journal_head(bh); |