diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index 9469bce4..59fbd48a 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -31,6 +31,8 @@ using NTSTATUS = std::uint32_t; #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) #define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) +#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L) +#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L) #define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) #define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) #define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index cc99ac0d..87b5045d 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -354,6 +354,8 @@ constexpr auto BASE_NAMED_OBJECTS_DIRECTORY = make_pseudo_handle(0x2, handle_typ constexpr auto KNOWN_DLLS_SYMLINK = make_pseudo_handle(0x1, handle_types::symlink); constexpr auto SHARED_SECTION = make_pseudo_handle(0x1, handle_types::section); +constexpr auto WER_PORT_READY = make_pseudo_handle(0x1, handle_types::event); + constexpr auto CONSOLE_HANDLE = make_pseudo_handle(0x1, handle_types::file); constexpr auto STDOUT_HANDLE = make_pseudo_handle(0x2, handle_types::file); constexpr auto STDIN_HANDLE = make_pseudo_handle(0x3, handle_types::file); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 52002de2..ac236691 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -108,17 +108,17 @@ struct mutant : ref_counted_object return true; } - uint32_t release() + std::pair release(const uint32_t thread_id) { const auto old_count = this->locked_count; - if (this->locked_count <= 0) + if (this->locked_count <= 0 || this->owning_thread_id != thread_id) { - return old_count; + return {old_count, false}; } --this->locked_count; - return old_count; + return {old_count, true}; } void serialize(utils::buffer_serializer& buffer) const @@ -239,9 +239,34 @@ struct section struct semaphore : ref_counted_object { std::u16string name{}; - volatile uint32_t current_count{}; + uint32_t current_count{}; uint32_t max_count{}; + bool try_lock() + { + if (this->current_count > 0) + { + --this->current_count; + return true; + } + + return false; + } + + std::pair release(const uint32_t release_count) + { + const auto old_count = this->current_count; + + if (this->current_count + release_count > this->max_count) + { + return {old_count, false}; + } + + this->current_count += release_count; + + return {old_count, true}; + } + void serialize(utils::buffer_serializer& buffer) const { buffer.write(this->name); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index c4c5d4e5..a171cc7e 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -449,14 +449,14 @@ namespace return STATUS_INVALID_HANDLE; } - const auto old_count = mutant->release(); + const auto [old_count, succeeded] = mutant->release(c.proc.current_thread_id); if (previous_count) { previous_count.write(static_cast(old_count)); } - return STATUS_SUCCESS; + return succeeded ? STATUS_SUCCESS : STATUS_MUTANT_NOT_OWNED; } NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object mutant_handle, @@ -553,6 +553,12 @@ namespace const auto name = read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + if (name == u"\\KernelObjects\\SystemErrorPortReady") + { + event_handle.write(WER_PORT_READY.bits); + return STATUS_SUCCESS; + } + for (auto& entry : c.proc.events) { if (entry.second.name == name) @@ -3020,6 +3026,32 @@ namespace return STATUS_OBJECT_NAME_NOT_FOUND; } + NTSTATUS handle_NtReleaseSemaphore(const syscall_context& c, const handle semaphore_handle, + const ULONG release_count, const emulator_object previous_count) + { + if (semaphore_handle.value.type != handle_types::semaphore) + { + c.win_emu.log.error("Bad handle type for NtReleaseSemaphore\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto* mutant = c.proc.semaphores.get(semaphore_handle); + if (!mutant) + { + return STATUS_INVALID_HANDLE; + } + + const auto [old_count, succeeded] = mutant->release(release_count); + + if (previous_count) + { + previous_count.write(static_cast(old_count)); + } + + return succeeded ? STATUS_SUCCESS : STATUS_SEMAPHORE_LIMIT_EXCEEDED; + } + NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object semaphore_handle, const ACCESS_MASK /*desired_access*/, const emulator_object>> object_attributes, @@ -3222,8 +3254,9 @@ namespace bool is_awaitable_object_type(const handle h) { - return h.value.type == handle_types::thread // - || h.value.type == handle_types::mutant // + return h.value.type == handle_types::thread // + || h.value.type == handle_types::mutant // + || h.value.type == handle_types::semaphore // || h.value.type == handle_types::event; } @@ -3537,6 +3570,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserModifyUserStartupInfoFlags); add_handler(NtUserGetDCEx); add_handler(NtUserGetDpiForCurrentProcess); + add_handler(NtReleaseSemaphore); #undef add_handler } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index e7f7500c..8de08a77 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -634,6 +634,11 @@ namespace break; case handle_types::event: { + if (h.value.is_pseudo) + { + return true; + } + auto* e = c.events.get(h); if (e) { @@ -653,6 +658,16 @@ namespace break; } + case handle_types::semaphore: { + auto* s = c.semaphores.get(h); + if (s) + { + return s->try_lock(); + } + + break; + } + case handle_types::thread: { const auto* t = c.threads.get(h); if (t)