Skip to content

Commit ccd3c43

Browse files
jankaratytso
authored andcommitted
jbd2: fix use after free in jbd2_log_do_checkpoint()
The code cleaning transaction's lists of checkpoint buffers has a bug where it increases bh refcount only after releasing journal->j_list_lock. Thus the following race is possible: CPU0 CPU1 jbd2_log_do_checkpoint() jbd2_journal_try_to_free_buffers() __journal_try_to_free_buffer(bh) ... while (transaction->t_checkpoint_io_list) ... if (buffer_locked(bh)) { <-- IO completes now, buffer gets unlocked --> spin_unlock(&journal->j_list_lock); spin_lock(&journal->j_list_lock); __jbd2_journal_remove_checkpoint(jh); spin_unlock(&journal->j_list_lock); try_to_free_buffers(page); get_bh(bh) <-- accesses freed bh Fix the problem by grabbing bh reference before unlocking journal->j_list_lock. Fixes: dc6e8d6 ("jbd2: don't call get_bh() before calling __jbd2_journal_remove_checkpoint()") Fixes: be1158c ("jbd2: fold __process_buffer() into jbd2_log_do_checkpoint()") Reported-by: syzbot+7f4a27091759e2fe7453@syzkaller.appspotmail.com CC: stable@vger.kernel.org Reviewed-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 182a79e commit ccd3c43

File tree

1 file changed

+2
-2
lines changed

1 file changed

+2
-2
lines changed

fs/jbd2/checkpoint.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,8 @@ int jbd2_log_do_checkpoint(journal_t *journal)
251251
bh = jh2bh(jh);
252252

253253
if (buffer_locked(bh)) {
254-
spin_unlock(&journal->j_list_lock);
255254
get_bh(bh);
255+
spin_unlock(&journal->j_list_lock);
256256
wait_on_buffer(bh);
257257
/* the journal_head may have gone by now */
258258
BUFFER_TRACE(bh, "brelse");
@@ -333,8 +333,8 @@ int jbd2_log_do_checkpoint(journal_t *journal)
333333
jh = transaction->t_checkpoint_io_list;
334334
bh = jh2bh(jh);
335335
if (buffer_locked(bh)) {
336-
spin_unlock(&journal->j_list_lock);
337336
get_bh(bh);
337+
spin_unlock(&journal->j_list_lock);
338338
wait_on_buffer(bh);
339339
/* the journal_head may have gone by now */
340340
BUFFER_TRACE(bh, "brelse");

0 commit comments

Comments
 (0)