diff --git a/ipc/app/moz.build b/ipc/app/moz.build index 4bcae9684924..2dbc8084ca61 100644 --- a/ipc/app/moz.build +++ b/ipc/app/moz.build @@ -48,6 +48,10 @@ if CONFIG['OS_ARCH'] == 'WINNT': 'winmm.dll', 'user32.dll', ] + + OS_LIBS += [ + 'ntdll', + ] DELAYLOAD_DLLS += [ 'xul.dll', diff --git a/js/xpconnect/shell/moz.build b/js/xpconnect/shell/moz.build index 499b74ad1f59..04e007c58dbe 100644 --- a/js/xpconnect/shell/moz.build +++ b/js/xpconnect/shell/moz.build @@ -50,6 +50,10 @@ if CONFIG['OS_ARCH'] == 'WINNT': 'user32.dll', ] + OS_LIBS += [ + 'ntdll', + ] + DELAYLOAD_DLLS += [ 'xul.dll', ] diff --git a/mozglue/misc/NativeNt.h b/mozglue/misc/NativeNt.h index ae79e17d6736..501adc949e6b 100644 --- a/mozglue/misc/NativeNt.h +++ b/mozglue/misc/NativeNt.h @@ -89,6 +89,9 @@ VOID NTAPI RtlAcquireSRWLockShared(PSRWLOCK aLock); VOID NTAPI RtlReleaseSRWLockExclusive(PSRWLOCK aLock); VOID NTAPI RtlReleaseSRWLockShared(PSRWLOCK aLock); +ULONG NTAPI RtlNtStatusToDosError(NTSTATUS aStatus); +VOID NTAPI RtlSetLastWin32Error(DWORD aError); + NTSTATUS NTAPI NtReadVirtualMemory(HANDLE aProcessHandle, PVOID aBaseAddress, PVOID aBuffer, SIZE_T aNumBytesToRead, PSIZE_T aNumBytesRead); @@ -1099,6 +1102,8 @@ inline DWORD RtlGetCurrentThreadId() { 0xFFFFFFFFUL); } +const HANDLE kCurrentProcess = reinterpret_cast(-1); + inline LauncherResult GetParentProcessId() { struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; @@ -1109,7 +1114,6 @@ inline LauncherResult GetParentProcessId() { ULONG_PTR InheritedFromUniqueProcessId; }; - const HANDLE kCurrentProcess = reinterpret_cast(-1); ULONG returnLength; PROCESS_BASIC_INFORMATION pbi = {}; NTSTATUS status = @@ -1122,6 +1126,30 @@ inline LauncherResult GetParentProcessId() { return static_cast(pbi.InheritedFromUniqueProcessId & 0xFFFFFFFF); } +inline SIZE_T WINAPI VirtualQueryEx(HANDLE aProcess, LPCVOID aAddress, + PMEMORY_BASIC_INFORMATION aMemInfo, + SIZE_T aMemInfoLen) { +#if defined(MOZILLA_INTERNAL_API) + return ::VirtualQueryEx(aProcess, aAddress, aMemInfo, aMemInfoLen); +#else + SIZE_T returnedLength; + NTSTATUS status = ::NtQueryVirtualMemory( + aProcess, const_cast(aAddress), MemoryBasicInformation, aMemInfo, + aMemInfoLen, &returnedLength); + if (!NT_SUCCESS(status)) { + ::RtlSetLastWin32Error(::RtlNtStatusToDosError(status)); + returnedLength = 0; + } + return returnedLength; +#endif // defined(MOZILLA_INTERNAL_API) +} + +inline SIZE_T WINAPI VirtualQuery(LPCVOID aAddress, + PMEMORY_BASIC_INFORMATION aMemInfo, + SIZE_T aMemInfoLen) { + return nt::VirtualQueryEx(kCurrentProcess, aAddress, aMemInfo, aMemInfoLen); +} + struct DataDirectoryEntry : public _IMAGE_DATA_DIRECTORY { DataDirectoryEntry() : _IMAGE_DATA_DIRECTORY() {} diff --git a/mozglue/misc/interceptor/MMPolicies.h b/mozglue/misc/interceptor/MMPolicies.h index a86bbc907155..cebb8e5bdcf8 100644 --- a/mozglue/misc/interceptor/MMPolicies.h +++ b/mozglue/misc/interceptor/MMPolicies.h @@ -74,6 +74,19 @@ PVOID WINAPI MapViewOfFile3(HANDLE FileMapping, HANDLE Process, extern "C" errno_t rand_s(unsigned int* randomValue); #endif // !defined(_CRT_RAND_S) +// Declaring only the functions we need in NativeNt.h. To include the entire +// NativeNt.h causes circular dependency. +namespace mozilla { +namespace nt { +SIZE_T WINAPI VirtualQueryEx(HANDLE aProcess, LPCVOID aAddress, + PMEMORY_BASIC_INFORMATION aMemInfo, + SIZE_T aMemInfoLen); + +SIZE_T WINAPI VirtualQuery(LPCVOID aAddress, PMEMORY_BASIC_INFORMATION aMemInfo, + SIZE_T aMemInfoLen); +} // namespace nt +} // namespace mozilla + namespace mozilla { namespace interceptor { @@ -276,7 +289,7 @@ class MOZ_TRIVIAL_CTOR_DTOR MMPolicyBase { // Scan the range for a free chunk that is at least as large as // aDesiredBytesLen while (address <= kMaxPtr && - ::VirtualQueryEx(aProcess, address, &mbi, len)) { + nt::VirtualQueryEx(aProcess, address, &mbi, len)) { if (mbi.State == MEM_FREE && mbi.RegionSize >= aDesiredBytesLen) { return mbi.BaseAddress; } @@ -424,7 +437,7 @@ class MOZ_TRIVIAL_CTOR_DTOR MMPolicyInProcess : public MMPolicyBase { */ bool IsPageAccessible(void* aVAddress) const { MEMORY_BASIC_INFORMATION mbi; - SIZE_T result = ::VirtualQuery(aVAddress, &mbi, sizeof(mbi)); + SIZE_T result = nt::VirtualQuery(aVAddress, &mbi, sizeof(mbi)); return result && mbi.AllocationProtect && (mbi.Type & MEM_IMAGE) && mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS; @@ -696,7 +709,7 @@ class MMPolicyOutOfProcess : public MMPolicyBase { */ bool IsPageAccessible(void* aVAddress) const { MEMORY_BASIC_INFORMATION mbi; - SIZE_T result = ::VirtualQueryEx(mProcess, aVAddress, &mbi, sizeof(mbi)); + SIZE_T result = nt::VirtualQueryEx(mProcess, aVAddress, &mbi, sizeof(mbi)); return result && mbi.AllocationProtect && (mbi.Type & MEM_IMAGE) && mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS; diff --git a/mozglue/tests/TestNativeNt.cpp b/mozglue/tests/TestNativeNt.cpp index bab7e28af421..01ed03da66de 100644 --- a/mozglue/tests/TestNativeNt.cpp +++ b/mozglue/tests/TestNativeNt.cpp @@ -41,6 +41,29 @@ const char kFailFmt[] = using namespace mozilla; using namespace mozilla::nt; +bool TestVirtualQuery(HANDLE aProcess, LPCVOID aAddress) { + MEMORY_BASIC_INFORMATION info1 = {}, info2 = {}; + SIZE_T result1 = ::VirtualQueryEx(aProcess, aAddress, &info1, sizeof(info1)), + result2 = mozilla::nt::VirtualQueryEx(aProcess, aAddress, &info2, + sizeof(info2)); + if (result1 != result2) { + printf("TEST-FAILED | NativeNt | The returned values mismatch\n"); + return false; + } + + if (!result1) { + // Both APIs failed. + return true; + } + + if (memcmp(&info1, &info2, result1) != 0) { + printf("TEST-FAILED | NativeNt | The returned structures mismatch\n"); + return false; + } + + return true; +} + // Need a non-inline function to bypass compiler optimization that the thread // local storage pointer is cached in a register before accessing a thread-local // variable. @@ -226,6 +249,23 @@ int wmain(int argc, wchar_t* argv[]) { return 1; } + // To test the Ex version of API, we purposely get a real handle + // instead of a pseudo handle. + nsAutoHandle process( + ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId())); + if (!process) { + printf("TEST-FAILED | NativeNt | OpenProcess() failed - %08lx\n", + ::GetLastError()); + return 1; + } + + // Test Null page, Heap, Mapped image, and Invalid handle + if (!TestVirtualQuery(process, nullptr) || !TestVirtualQuery(process, argv) || + !TestVirtualQuery(process, kNormal) || + !TestVirtualQuery(nullptr, kNormal)) { + return 1; + } + printf("TEST-PASS | NativeNt | All tests ran successfully\n"); return 0; }