summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSahitya Tummala <stummala@codeaurora.org>2017-02-01 20:49:35 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-29 07:50:02 +0200
commit87dfe99e129679c23bebda36b83cb223285afc2a (patch)
tree72fee29b357f526893a4fc240a48580cf3d8c753
parent9441c6de4d4af57c8f160b9f7f688bf0983ddd7f (diff)
jbd2: fix use after free in kjournald2()
commit dbfcef6b0f4012c57bc0b6e0e660d5ed12a5eaed upstream. 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> Cc: Amit Pundir <amit.pundir@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/jbd2/journal.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 4759df4eb8ce..9398d1b70545 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -275,11 +275,11 @@ loop:
goto loop;
end_loop:
- write_unlock(&journal->j_state_lock);
del_timer_sync(&journal->j_commit_timer);
journal->j_task = NULL;
wake_up(&journal->j_wait_done_commit);
jbd_debug(1, "Journal thread exiting.\n");
+ write_unlock(&journal->j_state_lock);
return 0;
}