diff options
Diffstat (limited to 'chromium/sandbox/win/src/sandbox_nt_util.cc')
-rw-r--r-- | chromium/sandbox/win/src/sandbox_nt_util.cc | 99 |
1 files changed, 54 insertions, 45 deletions
diff --git a/chromium/sandbox/win/src/sandbox_nt_util.cc b/chromium/sandbox/win/src/sandbox_nt_util.cc index 62f2422ca43..ac73fc11c3f 100644 --- a/chromium/sandbox/win/src/sandbox_nt_util.cc +++ b/chromium/sandbox/win/src/sandbox_nt_util.cc @@ -23,58 +23,67 @@ SANDBOX_INTERCEPT NtExports g_nt; namespace { #if defined(_WIN64) +// Align a pointer to the next allocation granularity boundary. +inline char* AlignToBoundary(void* ptr, size_t increment) { + const size_t kAllocationGranularity = (64 * 1024) - 1; + uintptr_t ptr_int = reinterpret_cast<uintptr_t>(ptr); + uintptr_t ret_ptr = + (ptr_int + increment + kAllocationGranularity) & ~kAllocationGranularity; + // Check for overflow. + if (ret_ptr < ptr_int) + return nullptr; + return reinterpret_cast<char*>(ret_ptr); +} + +// Allocate a memory block somewhere within 2GiB of a specified base address. +// This is used for the DLL hooking code to get a valid trampoline location +// which must be within +/- 2GiB of the base. We only consider +2GiB for now. void* AllocateNearTo(void* source, size_t size) { using sandbox::g_nt; - - // Start with 1 GB above the source. - const size_t kOneGB = 0x40000000; - void* base = reinterpret_cast<char*>(source) + kOneGB; - SIZE_T actual_size = size; - ULONG_PTR zero_bits = 0; // Not the correct type if used. - ULONG type = MEM_RESERVE; - - NTSTATUS ret; - int attempts = 0; - for (; attempts < 41; attempts++) { - ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, - &actual_size, type, PAGE_READWRITE); - if (NT_SUCCESS(ret)) { - if (base < source || - base >= reinterpret_cast<char*>(source) + 4 * kOneGB) { - // We won't be able to patch this dll. - VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, - MEM_RELEASE)); - return NULL; - } + // 2GiB, maximum upper bound the allocation address must be within. + const size_t kMaxSize = 0x80000000ULL; + // We don't support null as a base as this would just pick an arbitrary + // address when passed to NtAllocateVirtualMemory. + if (source == nullptr) + return nullptr; + // Ignore an allocation which is larger than the maximum. + if (size > kMaxSize) + return nullptr; + + // Ensure base address is aligned to the allocation granularity boundary. + char* base = AlignToBoundary(source, 0); + if (base == nullptr) + return nullptr; + // Set top address to be base + 2GiB. + const char* top_address = base + kMaxSize; + + while (base < top_address) { + MEMORY_BASIC_INFORMATION mem_info; + NTSTATUS status = + g_nt.QueryVirtualMemory(NtCurrentProcess, base, MemoryBasicInformation, + &mem_info, sizeof(mem_info), nullptr); + if (!NT_SUCCESS(status)) break; - } - if (attempts == 30) { - // Try the first GB. - base = reinterpret_cast<char*>(source); - } else if (attempts == 40) { - // Try the highest available address. - base = NULL; - type |= MEM_TOP_DOWN; + if ((mem_info.State == MEM_FREE) && (mem_info.RegionSize >= size)) { + // We've found a valid free block, try and allocate it for use. + // Note that we need to both commit and reserve the block for the + // allocation to succeed as per Windows virtual memory requirements. + void* ret_base = mem_info.BaseAddress; + status = + g_nt.AllocateVirtualMemory(NtCurrentProcess, &ret_base, 0, &size, + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + // Shouldn't fail, but if it does we'll just continue and try next block. + if (NT_SUCCESS(status)) + return ret_base; } - // Try 100 MB higher. - base = reinterpret_cast<char*>(base) + 100 * 0x100000; - } - - if (attempts == 41) - return NULL; - - ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, - &actual_size, MEM_COMMIT, PAGE_READWRITE); - - if (!NT_SUCCESS(ret)) { - VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, - MEM_RELEASE)); - base = NULL; + // Update base past current allocation region. + base = AlignToBoundary(mem_info.BaseAddress, mem_info.RegionSize); + if (base == nullptr) + break; } - - return base; + return nullptr; } #else // defined(_WIN64). void* AllocateNearTo(void* source, size_t size) { |