Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Side by Side Diff: sandbox/win/src/sandbox_nt_util.cc

Issue 2258583002: Reimplement AllocateNearTo for 64bit. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Better comments and used standard types Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | sandbox/win/src/sandbox_nt_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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) {}
OLDNEW
« no previous file with comments | « no previous file | sandbox/win/src/sandbox_nt_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698