A handle created with just PROCESS_QUERY_LIMITED_INFORMATION should be returned when queried with PROCESS_QUERY_INFORMATION.
From: Bernhard Übelacker bernhardu@mailbox.org
A handle created with just PROCESS_QUERY_LIMITED_INFORMATION should be returned when queried with PROCESS_QUERY_INFORMATION.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56093 --- dlls/kernel32/tests/process.c | 26 ++++++++++++++++++++++++++ server/handle.c | 7 +++++++ 2 files changed, 33 insertions(+)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index e0f1d210e58..2c3b49dca41 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -2545,6 +2545,31 @@ static void test_DuplicateHandle(void) CloseHandle(out); }
+static void test_DuplicateHandle_limited(void) +{ + void *addr; + HANDLE h; + MEMORY_BASIC_INFORMATION info; + int ret; + + addr = VirtualAllocEx(GetCurrentProcess(), 0, 0xFFFC, MEM_RESERVE, PAGE_NOACCESS); + ok(addr != NULL, "VirtualAllocEx error %ld\n", GetLastError()); + + ret = DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &h, + SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_DUP_HANDLE | PROCESS_VM_READ |PROCESS_VM_OPERATION, + TRUE, 0); + ok(ret, "DuplicateHandle error %ld\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = VirtualQueryEx(h, addr, &info, sizeof(info)); + ok(ret == sizeof(info) || + broken(ret == 0 && GetLastError() == ERROR_ACCESS_DENIED) /* <= win8*/, + "VirtualQueryEx error ret=0x%x %ld\n", ret, GetLastError()); + + ok(CloseHandle(h), "CloseHandle error %ld\n", GetLastError()); + ok(VirtualFree(addr, 0, MEM_RELEASE), "VirtualFree error %ld\n", GetLastError()); +} + #define test_completion(a, b, c, d, e) _test_completion(__LINE__, a, b, c, d, e) static void _test_completion(int line, HANDLE port, DWORD ekey, ULONG_PTR evalue, ULONG_PTR eoverlapped, DWORD wait) { @@ -5458,6 +5483,7 @@ START_TEST(process) test_ProcessorCount(); test_RegistryQuota(); test_DuplicateHandle(); + test_DuplicateHandle_limited(); test_StdHandleInheritance(); test_GetNumaProcessorNode(); test_session_info(); diff --git a/server/handle.c b/server/handle.c index 0595fdb403b..7f20685351b 100644 --- a/server/handle.c +++ b/server/handle.c @@ -477,6 +477,13 @@ struct object *get_handle_obj( struct process *process, obj_handle_t handle, set_error( STATUS_OBJECT_TYPE_MISMATCH ); /* not the right type */ return NULL; } + if ((access & PROCESS_QUERY_INFORMATION) && + !(entry->access & PROCESS_QUERY_INFORMATION) && + (entry->access & PROCESS_QUERY_LIMITED_INFORMATION)) + { + access &= ~PROCESS_QUERY_INFORMATION; + access |= PROCESS_QUERY_LIMITED_INFORMATION; + } if ((entry->access & access) != access) { set_error( STATUS_ACCESS_DENIED );
the fix can't be in server/handle.c (the access bits meaning depends on the object you're considering...)
looking at server/process.c:process_map_access: setting PROCESS_QUERY_INFORMATION always set PROCESS_QUERY_LIMITED_INFORMATION (but not the other way around)
so you need to figure out where an access is tested against PROCESS_QUERY_INFORMATION while it should be against PROCESS_QUERY_LIMITED_INFORMATION
hint: VirtualQueryEx -> NtQueryVirtualMemory -> get_basic_memory_info -> which queues an APC (APC_VIRTUAL_QUERY)