Index: sandbox/src/interception.cc |
=================================================================== |
--- sandbox/src/interception.cc (revision 143815) |
+++ sandbox/src/interception.cc (working copy) |
@@ -27,6 +27,28 @@ |
const char kMapViewOfSectionName[] = "NtMapViewOfSection"; |
const char kUnmapViewOfSectionName[] = "NtUnmapViewOfSection"; |
+// Standard allocation granularity and page size for Windows. |
+const size_t kAllocGranularity = 65536; |
+const size_t kPageSize = 4096; |
+ |
+// Find a random offset within 64k and aligned to ceil(log2(size)). |
+size_t GetGranularAlignedRandomOffset(size_t size) { |
+ CHECK_LE(size, kAllocGranularity); |
+ unsigned int offset; |
+ |
+ do { |
+ rand_s(&offset); |
+ offset &= (kAllocGranularity - 1); |
+ } while (offset > (kAllocGranularity - size)); |
+ |
+ // Find an alignment between 64 and the page size (4096). |
+ size_t align_size = kPageSize; |
+ for (size_t new_size = align_size / 2; new_size >= size; new_size /= 2) { |
+ align_size = new_size; |
+ } |
+ return offset & ~(align_size - 1); |
+} |
+ |
} // namespace |
namespace sandbox { |
@@ -360,15 +382,29 @@ |
ADD_NT_INTERCEPTION(NtUnmapViewOfSection, UNMAP_VIEW_OF_SECTION_ID, 12); |
} |
+ // Reserve a full 64k memory range in the child process. |
+ HANDLE child = child_->Process(); |
+ BYTE* thunk_base = reinterpret_cast<BYTE*>( |
+ ::VirtualAllocEx(child, NULL, kAllocGranularity, |
+ MEM_RESERVE, PAGE_NOACCESS)); |
+ |
+ // Find an aligned, random location within the reserved range. |
size_t thunk_bytes = interceptions_.size() * sizeof(ThunkData) + |
sizeof(DllInterceptionData); |
+ size_t thunk_offset = GetGranularAlignedRandomOffset(thunk_bytes); |
- // Allocate memory on the child, without specifying the desired address |
- HANDLE child = child_->Process(); |
+ // Split the base and offset along page boundaries. |
+ thunk_base += thunk_offset & ~(kPageSize - 1); |
+ thunk_offset &= kPageSize - 1; |
+ |
+ // Make an aligned, padded allocation, and move the pointer to our chunk. |
+ size_t thunk_bytes_padded = (thunk_bytes + kPageSize - 1) & kPageSize; |
+ thunk_base = reinterpret_cast<BYTE*>( |
+ ::VirtualAllocEx(child, thunk_base, thunk_bytes_padded, |
+ MEM_COMMIT, PAGE_EXECUTE_READWRITE)); |
+ CHECK(thunk_base); // If this fails we'd crash anyway on an invalid access. |
DllInterceptionData* thunks = reinterpret_cast<DllInterceptionData*>( |
- ::VirtualAllocEx(child, NULL, thunk_bytes, |
- MEM_COMMIT, |
- PAGE_EXECUTE_READWRITE)); |
+ thunk_base + thunk_offset); |
DllInterceptionData dll_data; |
dll_data.data_bytes = thunk_bytes; |