From 5122b55661aa93b12d2aa502c68cd41ef0850a1c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 22 Dec 2024 16:12:54 +0100 Subject: [PATCH] Support recursive mutants --- src/windows-emulator/process_context.hpp | 46 +++++++++++-- src/windows-emulator/syscalls.cpp | 78 ++++++++++++++++++++++- src/windows-emulator/windows_emulator.cpp | 12 +--- 3 files changed, 122 insertions(+), 14 deletions(-) diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 1f2691ce..97269c94 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -86,12 +86,45 @@ struct event : ref_counted_object struct mutant : ref_counted_object { - bool locked{false}; + uint32_t locked_count{0}; + uint32_t owning_thread_id{}; std::wstring name{}; + bool try_lock(const uint32_t thread_id) + { + if (this->locked_count == 0) + { + ++this->locked_count; + this->owning_thread_id = thread_id; + return true; + } + + if (this->owning_thread_id != thread_id) + { + return false; + } + + ++this->locked_count; + return true; + } + + uint32_t release() + { + const auto old_count = this->locked_count; + + if (this->locked_count <= 0) + { + return old_count; + } + + --this->locked_count; + return old_count; + } + void serialize(utils::buffer_serializer& buffer) const { - buffer.write(this->locked); + buffer.write(this->locked_count); + buffer.write(this->owning_thread_id); buffer.write(this->name); ref_counted_object::serialize(buffer); @@ -99,7 +132,8 @@ struct mutant : ref_counted_object void deserialize(utils::buffer_deserializer& buffer) { - buffer.read(this->locked); + buffer.read(this->locked_count); + buffer.read(this->owning_thread_id); buffer.read(this->name); ref_counted_object::deserialize(buffer); @@ -156,7 +190,7 @@ struct section } }; -struct semaphore +struct semaphore : ref_counted_object { std::wstring name{}; volatile uint32_t current_count{}; @@ -167,6 +201,8 @@ struct semaphore buffer.write(this->name); buffer.write(this->current_count); buffer.write(this->max_count); + + ref_counted_object::serialize(buffer); } void deserialize(utils::buffer_deserializer& buffer) @@ -174,6 +210,8 @@ struct semaphore buffer.read(this->name); buffer.read(this->current_count); buffer.read(this->max_count); + + ref_counted_object::deserialize(buffer); } }; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 48072a5a..17c6fd83 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -399,6 +399,32 @@ namespace return STATUS_SUCCESS; } + NTSTATUS handle_NtReleaseMutant(const syscall_context& c, const handle mutant_handle, + const emulator_object previous_count) + { + if (mutant_handle.value.type != handle_types::mutant) + { + c.win_emu.logger.error("Bad handle type for NtReleaseMutant\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto* mutant = c.proc.mutants.get(mutant_handle); + if (!mutant) + { + return STATUS_INVALID_HANDLE; + } + + const auto old_count = mutant->release(); + + if (previous_count) + { + previous_count.write(old_count); + } + + return STATUS_SUCCESS; + } + NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object mutant_handle, const ACCESS_MASK /*desired_access*/, const emulator_object object_attributes, @@ -426,9 +452,13 @@ namespace } mutant e{}; - e.locked = initial_owner != FALSE; e.name = std::move(name); + if (initial_owner) + { + e.try_lock(c.win_emu.current_thread().id); + } + const auto handle = c.proc.mutants.store(std::move(e)); mutant_handle.write(handle); @@ -2632,6 +2662,39 @@ namespace return STATUS_SUCCESS; } + NTSTATUS handle_NtOpenSemaphore(const syscall_context& c, const emulator_object semaphore_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object object_attributes) + { + if (!object_attributes) + { + return STATUS_INVALID_PARAMETER; + } + + const auto attributes = object_attributes.read(); + if (!attributes.ObjectName) + { + return STATUS_INVALID_PARAMETER; + } + + const auto name = read_unicode_string(c.emu, attributes.ObjectName); + if (name.empty()) + { + return STATUS_INVALID_PARAMETER; + } + + for (const auto& semaphore : c.proc.semaphores) + { + if (semaphore.second.name == name) + { + semaphore_handle.write(c.proc.semaphores.make_handle(semaphore.first)); + return STATUS_SUCCESS; + } + } + + return STATUS_OBJECT_NAME_NOT_FOUND; + } + NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object semaphore_handle, const ACCESS_MASK /*desired_access*/, const emulator_object object_attributes, @@ -2650,6 +2713,17 @@ namespace } } + if (!s.name.empty()) + { + for (const auto& semaphore : c.proc.semaphores) + { + if (semaphore.second.name == s.name) + { + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + const auto handle = c.proc.semaphores.store(std::move(s)); semaphore_handle.write(handle); @@ -3014,6 +3088,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtWriteFile); add_handler(NtRaiseHardError); add_handler(NtCreateSemaphore); + add_handler(NtOpenSemaphore); add_handler(NtReadVirtualMemory); add_handler(NtQueryInformationToken); add_handler(NtDxgkIsFeatureEnabled); @@ -3059,6 +3134,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtQueryAttributesFile); add_handler(NtWaitForMultipleObjects); add_handler(NtCreateMutant); + add_handler(NtReleaseMutant); #undef add_handler } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 5eb27e15..524d38f7 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -519,7 +519,7 @@ namespace return false; } - bool is_object_signaled(process_context& c, const handle h) + bool is_object_signaled(process_context& c, const handle h, uint32_t current_thread_id) { const auto type = h.value.type; @@ -544,13 +544,7 @@ namespace auto* e = c.mutants.get(h); if (e) { - if (e->locked) - { - return false; - } - - e->locked = true; - return true; + return e->try_lock(current_thread_id); } break; @@ -649,7 +643,7 @@ bool emulator_thread::is_thread_ready(windows_emulator& win_emu) { const auto& obj = this->await_objects[i]; - const auto signaled = is_object_signaled(win_emu.process(), obj); + const auto signaled = is_object_signaled(win_emu.process(), obj, this->id); all_signaled &= signaled; if (signaled && this->await_any)