• Jan Kara's avatar
    jbd2: fix use after free in jbd2_log_do_checkpoint() · ccd3c437
    Jan Kara authored
    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: dc6e8d66 ("jbd2: don't call get_bh() before calling __jbd2_journal_remove_checkpoint()")
    Fixes: be1158cc ("jbd2: fold __process_buffer() into jbd2_log_do_checkpoint()")
    Reported-by: syzbot+7f4a27091759e2fe7453@syzkaller.appspotmail.com
    CC: stable@vger.kernel.org
    Reviewed-by: default avatarLukas Czerner <lczerner@redhat.com>
    Signed-off-by: default avatarJan Kara <jack@suse.cz>
    Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
    ccd3c437
checkpoint.c 19 KB