From b2b5ccf69c6c3ad8f0156ec77ca1d804cc4fa108 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Tue, 12 Aug 2025 00:41:14 +0100 Subject: [PATCH] Windows: Validate any user handle permissions for syscall callbacks In the terminate case, if we don't return early then we will delete the FEX thread object but the actual terminate call that follows will fail, leaving the thread in a bad state. --- Source/Windows/ARM64EC/Module.cpp | 5 +++++ Source/Windows/Common/Handle.h | 16 ++++++++++++++++ Source/Windows/WOW64/Module.cpp | 9 +++++++++ Source/Windows/include/winternl.h | 2 +- 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 Source/Windows/Common/Handle.h diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 3c5a2fbc7..800ec3ee8 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -39,6 +39,7 @@ $end_info$ #include "Common/Module.h" #include "Common/CRT/CRT.h" #include "Common/PortabilityInfo.h" +#include "Common/Handle.h" #include "DummyHandlers.h" #include "BTInterface.h" #include "Windows/Common/SHMStats.h" @@ -959,6 +960,10 @@ NTSTATUS ThreadInit() { } NTSTATUS ThreadTerm(HANDLE Thread, LONG ExitCode) { + if (!FEX::Windows::ValidateHandleAccess(Thread, THREAD_TERMINATE)) { + return STATUS_ACCESS_DENIED; + } + THREAD_BASIC_INFORMATION Info; if (auto Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); Err) { return Err; diff --git a/Source/Windows/Common/Handle.h b/Source/Windows/Common/Handle.h new file mode 100644 index 000000000..20a2c2d57 --- /dev/null +++ b/Source/Windows/Common/Handle.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +#pragma once + +#include + +namespace FEX::Windows { + bool ValidateHandleAccess(HANDLE Handle, ACCESS_MASK Access) { + OBJECT_BASIC_INFORMATION Info; + + if (NtQueryObject(Handle, ObjectBasicInformation, &Info, sizeof(Info), nullptr)) { + return false; + } + + return (Info.GrantedAccess & Access) == Access; + } +} diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index b5fea5f0e..35870a1e3 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -39,6 +39,7 @@ $end_info$ #include "Common/Module.h" #include "Common/CRT/CRT.h" #include "Common/PortabilityInfo.h" +#include "Common/Handle.h" #include "DummyHandlers.h" #include "BTInterface.h" #include "Windows/Common/SHMStats.h" @@ -576,6 +577,10 @@ void BTCpuThreadInit() { } void BTCpuThreadTerm(HANDLE Thread, LONG ExitCode) { + if (!FEX::Windows::ValidateHandleAccess(Thread, THREAD_TERMINATE)) { + return; + } + THREAD_BASIC_INFORMATION Info; if (auto Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); Err) { return; @@ -703,6 +708,10 @@ extern "C" void BTCpuSimulateImpl(CONTEXT *entry_context) { } NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG* Count) { + if (!FEX::Windows::ValidateHandleAccess(Thread, THREAD_SUSPEND_RESUME)) { + return STATUS_ACCESS_DENIED; + } + THREAD_BASIC_INFORMATION Info; if (NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); Err) { return Err; diff --git a/Source/Windows/include/winternl.h b/Source/Windows/include/winternl.h index 8d4c23e01..8bf0cd48c 100644 --- a/Source/Windows/include/winternl.h +++ b/Source/Windows/include/winternl.h @@ -537,7 +537,7 @@ NTSTATUS WINAPI RtlWow64GetThreadContext(HANDLE, WOW64_CONTEXT*); NTSTATUS WINAPI RtlWow64SetThreadContext(HANDLE, const WOW64_CONTEXT*); void WINAPI Wow64ProcessPendingCrossProcessItems(void); NTSTATUS WINAPI Wow64SystemServiceEx(UINT, UINT*); -NTSTATUS WINAPI RtlWow64SuspendThread(HANDLE,ULONG*); +NTSTATUS WINAPI RtlWow64SuspendThread(HANDLE, ULONG*); #ifdef __cplusplus }