OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sandbox/win/src/sandbox_nt_util.h" | 5 #include "sandbox/win/src/sandbox_nt_util.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <string> | 10 #include <string> |
11 | 11 |
12 #include "base/win/pe_image.h" | 12 #include "base/win/pe_image.h" |
13 #include "sandbox/win/src/sandbox_factory.h" | 13 #include "sandbox/win/src/sandbox_factory.h" |
14 #include "sandbox/win/src/target_services.h" | 14 #include "sandbox/win/src/target_services.h" |
15 | 15 |
16 namespace sandbox { | 16 namespace sandbox { |
17 | 17 |
18 // This is the list of all imported symbols from ntdll.dll. | 18 // This is the list of all imported symbols from ntdll.dll. |
19 SANDBOX_INTERCEPT NtExports g_nt; | 19 SANDBOX_INTERCEPT NtExports g_nt; |
20 | 20 |
21 } // namespace sandbox | 21 } // namespace sandbox |
22 | 22 |
23 namespace { | 23 namespace { |
24 | 24 |
25 #if defined(_WIN64) | 25 #if defined(_WIN64) |
| 26 // Align a pointer to the next allocation granularity boundary. |
| 27 inline char* AlignToBoundary(void* ptr, size_t increment) { |
| 28 const size_t kAllocationGranularity = (64 * 1024) - 1; |
| 29 uintptr_t ptr_int = reinterpret_cast<uintptr_t>(ptr); |
| 30 uintptr_t ret_ptr = |
| 31 (ptr_int + increment + kAllocationGranularity) & ~kAllocationGranularity; |
| 32 // Check for overflow. |
| 33 if (ret_ptr < ptr_int) |
| 34 return nullptr; |
| 35 return reinterpret_cast<char*>(ret_ptr); |
| 36 } |
| 37 |
| 38 // Allocate a memory block somewhere within 2GiB of a specified base address. |
| 39 // This is used for the DLL hooking code to get a valid trampoline location |
| 40 // which must be within +/- 2GiB of the base. We only consider +2GiB for now. |
26 void* AllocateNearTo(void* source, size_t size) { | 41 void* AllocateNearTo(void* source, size_t size) { |
27 using sandbox::g_nt; | 42 using sandbox::g_nt; |
| 43 // 2GiB, maximum upper bound the allocation address must be within. |
| 44 const size_t kMaxSize = 0x80000000ULL; |
| 45 // We don't support null as a base as this would just pick an arbitrary |
| 46 // address when passed to NtAllocateVirtualMemory. |
| 47 if (source == nullptr) |
| 48 return nullptr; |
| 49 // Ignore an allocation which is larger than the maximum. |
| 50 if (size > kMaxSize) |
| 51 return nullptr; |
28 | 52 |
29 // Start with 1 GB above the source. | 53 // Ensure base address is aligned to the allocation granularity boundary. |
30 const size_t kOneGB = 0x40000000; | 54 char* base = AlignToBoundary(source, 0); |
31 void* base = reinterpret_cast<char*>(source) + kOneGB; | 55 if (base == nullptr) |
32 SIZE_T actual_size = size; | 56 return nullptr; |
33 ULONG_PTR zero_bits = 0; // Not the correct type if used. | 57 // Set top address to be base + 2GiB. |
34 ULONG type = MEM_RESERVE; | 58 const char* top_address = base + kMaxSize; |
35 | 59 |
36 NTSTATUS ret; | 60 while (base < top_address) { |
37 int attempts = 0; | 61 MEMORY_BASIC_INFORMATION mem_info; |
38 for (; attempts < 41; attempts++) { | 62 NTSTATUS status = |
39 ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, | 63 g_nt.QueryVirtualMemory(NtCurrentProcess, base, MemoryBasicInformation, |
40 &actual_size, type, PAGE_READWRITE); | 64 &mem_info, sizeof(mem_info), nullptr); |
41 if (NT_SUCCESS(ret)) { | 65 if (!NT_SUCCESS(status)) |
42 if (base < source || | |
43 base >= reinterpret_cast<char*>(source) + 4 * kOneGB) { | |
44 // We won't be able to patch this dll. | |
45 VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, | |
46 MEM_RELEASE)); | |
47 return NULL; | |
48 } | |
49 break; | 66 break; |
| 67 |
| 68 if ((mem_info.State == MEM_FREE) && (mem_info.RegionSize >= size)) { |
| 69 // We've found a valid free block, try and allocate it for use. |
| 70 // Note that we need to both commit and reserve the block for the |
| 71 // allocation to succeed as per Windows virtual memory requirements. |
| 72 void* ret_base = mem_info.BaseAddress; |
| 73 status = |
| 74 g_nt.AllocateVirtualMemory(NtCurrentProcess, &ret_base, 0, &size, |
| 75 MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); |
| 76 // Shouldn't fail, but if it does we'll just continue and try next block. |
| 77 if (NT_SUCCESS(status)) |
| 78 return ret_base; |
50 } | 79 } |
51 | 80 |
52 if (attempts == 30) { | 81 // Update base past current allocation region. |
53 // Try the first GB. | 82 base = AlignToBoundary(mem_info.BaseAddress, mem_info.RegionSize); |
54 base = reinterpret_cast<char*>(source); | 83 if (base == nullptr) |
55 } else if (attempts == 40) { | 84 break; |
56 // Try the highest available address. | |
57 base = NULL; | |
58 type |= MEM_TOP_DOWN; | |
59 } | |
60 | |
61 // Try 100 MB higher. | |
62 base = reinterpret_cast<char*>(base) + 100 * 0x100000; | |
63 } | 85 } |
64 | 86 return nullptr; |
65 if (attempts == 41) | |
66 return NULL; | |
67 | |
68 ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, | |
69 &actual_size, MEM_COMMIT, PAGE_READWRITE); | |
70 | |
71 if (!NT_SUCCESS(ret)) { | |
72 VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, | |
73 MEM_RELEASE)); | |
74 base = NULL; | |
75 } | |
76 | |
77 return base; | |
78 } | 87 } |
79 #else // defined(_WIN64). | 88 #else // defined(_WIN64). |
80 void* AllocateNearTo(void* source, size_t size) { | 89 void* AllocateNearTo(void* source, size_t size) { |
81 using sandbox::g_nt; | 90 using sandbox::g_nt; |
82 | 91 |
83 // In 32-bit processes allocations below 512k are predictable, so mark | 92 // In 32-bit processes allocations below 512k are predictable, so mark |
84 // anything in that range as reserved and retry until we get a good address. | 93 // anything in that range as reserved and retry until we get a good address. |
85 const void* const kMinAddress = reinterpret_cast<void*>(512 * 1024); | 94 const void* const kMinAddress = reinterpret_cast<void*>(512 * 1024); |
86 NTSTATUS ret; | 95 NTSTATUS ret; |
87 SIZE_T actual_size; | 96 SIZE_T actual_size; |
(...skipping 579 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 | 676 |
668 void* __cdecl operator new(size_t size, | 677 void* __cdecl operator new(size_t size, |
669 void* buffer, | 678 void* buffer, |
670 sandbox::AllocationType type) { | 679 sandbox::AllocationType type) { |
671 return buffer; | 680 return buffer; |
672 } | 681 } |
673 | 682 |
674 void __cdecl operator delete(void* memory, | 683 void __cdecl operator delete(void* memory, |
675 void* buffer, | 684 void* buffer, |
676 sandbox::AllocationType type) {} | 685 sandbox::AllocationType type) {} |
OLD | NEW |