From d12e6085a00f517d7f3b796f03675f01e3e2966a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 9 Jan 2021 16:14:52 +0100 Subject: [PATCH] kernel/thread: handle invalid user_thread pointer in user_[un]block_thread should help with #16736 Change-Id: I103488679b8c352855fbd19405bb30c978cf4457 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3613 Reviewed-by: waddlesplash --- src/system/kernel/thread.cpp | 44 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 1f10548ff9..fdab209879 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -2969,10 +2969,16 @@ user_unblock_thread(thread_id threadID, status_t status) InterruptsSpinLocker locker(thread->scheduler_lock); - set_ac(); - if (thread->user_thread->wait_status > 0) { - thread->user_thread->wait_status = status; - clear_ac(); + status_t waitStatus; + if (user_memcpy(&waitStatus, &thread->user_thread->wait_status, + sizeof(waitStatus)) < B_OK) { + return B_BAD_ADDRESS; + } + if (waitStatus > 0) { + if (user_memcpy(&thread->user_thread->wait_status, &status, + sizeof(status)) < B_OK) { + return B_BAD_ADDRESS; + } // Even if the user_thread->wait_status was > 0, it may be the // case that this thread is actually blocked on something else. @@ -2980,9 +2986,7 @@ user_unblock_thread(thread_id threadID, status_t status) && thread->wait.type == THREAD_BLOCK_TYPE_USER) { thread_unblock_locked(thread, status); } - } else - clear_ac(); - + } return B_OK; } @@ -3709,13 +3713,13 @@ _user_block_thread(uint32 flags, bigtime_t timeout) ThreadLocker threadLocker(thread); // check, if already done - set_ac(); - if (thread->user_thread->wait_status <= 0) { - status_t status = thread->user_thread->wait_status; - clear_ac(); - return status; + status_t waitStatus; + if (user_memcpy(&waitStatus, &thread->user_thread->wait_status, + sizeof(waitStatus)) < B_OK) { + return B_BAD_ADDRESS; } - clear_ac(); + if (waitStatus <= 0) + return waitStatus; // nope, so wait thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_USER, NULL); @@ -3729,13 +3733,17 @@ _user_block_thread(uint32 flags, bigtime_t timeout) // Interruptions or timeouts can race with other threads unblocking us. // Favor a wake-up by another thread, i.e. if someone changed the wait // status, use that. - set_ac(); - status_t oldStatus = thread->user_thread->wait_status; + status_t oldStatus; + if (user_memcpy(&oldStatus, &thread->user_thread->wait_status, + sizeof(oldStatus)) < B_OK) { + return B_BAD_ADDRESS; + } if (oldStatus > 0) { - thread->user_thread->wait_status = status; - clear_ac(); + if (user_memcpy(&thread->user_thread->wait_status, &status, + sizeof(status)) < B_OK) { + return B_BAD_ADDRESS; + } } else { - clear_ac(); status = oldStatus; }