jbd2: fix use after free in kjournald2()
authorSahitya Tummala <stummala@codeaurora.org>
Thu, 2 Feb 2017 01:49:35 +0000 (20:49 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 2 Feb 2017 01:49:35 +0000 (20:49 -0500)
commitdbfcef6b0f4012c57bc0b6e0e660d5ed12a5eaed
tree950d1f2d0e4293122c0c78564aee3dc44ff43daf
parent3b136499e906460919f0d21a49db1aaccf0ae963
jbd2: fix use after free in kjournald2()

Below is the synchronization issue between unmount and kjournald2
contexts, which results into use after free issue in kjournald2().
Fix this issue by using journal->j_state_lock to synchronize the
wait_event() done in journal_kill_thread() and the wake_up() done
in kjournald2().

TASK 1:
umount cmd:
   |--jbd2_journal_destroy() {
       |--journal_kill_thread() {
            write_lock(&journal->j_state_lock);
    journal->j_flags |= JBD2_UNMOUNT;
    ...
    write_unlock(&journal->j_state_lock);
    wake_up(&journal->j_wait_commit);    TASK 2 wakes up here:
        kjournald2() {
     ...
     checks JBD2_UNMOUNT flag and calls goto end-loop;
     ...
     end_loop:
       write_unlock(&journal->j_state_lock);
       journal->j_task = NULL; --> If this thread gets
       pre-empted here, then TASK 1 wait_event will
       exit even before this thread is completely
       done.
    wait_event(journal->j_wait_done_commit, journal->j_task == NULL);
    ...
    write_lock(&journal->j_state_lock);
    write_unlock(&journal->j_state_lock);
  }
       |--kfree(journal);
     }
}
       wake_up(&journal->j_wait_done_commit); --> this step
       now results into use after free issue.
   }

Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/jbd2/journal.c