1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/sandbox_nt_util.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,602 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "sandbox/win/src/sandbox_nt_util.h" 1.9 + 1.10 +#include "base/win/pe_image.h" 1.11 +#include "sandbox/win/src/sandbox_factory.h" 1.12 +#include "sandbox/win/src/target_services.h" 1.13 + 1.14 +namespace sandbox { 1.15 + 1.16 +// This is the list of all imported symbols from ntdll.dll. 1.17 +SANDBOX_INTERCEPT NtExports g_nt = { NULL }; 1.18 + 1.19 +} // namespace sandbox 1.20 + 1.21 +namespace { 1.22 + 1.23 +#if defined(_WIN64) 1.24 +void* AllocateNearTo(void* source, size_t size) { 1.25 + using sandbox::g_nt; 1.26 + 1.27 + // Start with 1 GB above the source. 1.28 + const size_t kOneGB = 0x40000000; 1.29 + void* base = reinterpret_cast<char*>(source) + kOneGB; 1.30 + SIZE_T actual_size = size; 1.31 + ULONG_PTR zero_bits = 0; // Not the correct type if used. 1.32 + ULONG type = MEM_RESERVE; 1.33 + 1.34 + NTSTATUS ret; 1.35 + int attempts = 0; 1.36 + for (; attempts < 41; attempts++) { 1.37 + ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, 1.38 + &actual_size, type, PAGE_READWRITE); 1.39 + if (NT_SUCCESS(ret)) { 1.40 + if (base < source || 1.41 + base >= reinterpret_cast<char*>(source) + 4 * kOneGB) { 1.42 + // We won't be able to patch this dll. 1.43 + VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, 1.44 + MEM_RELEASE)); 1.45 + return NULL; 1.46 + } 1.47 + break; 1.48 + } 1.49 + 1.50 + if (attempts == 30) { 1.51 + // Try the first GB. 1.52 + base = reinterpret_cast<char*>(source); 1.53 + } else if (attempts == 40) { 1.54 + // Try the highest available address. 1.55 + base = NULL; 1.56 + type |= MEM_TOP_DOWN; 1.57 + } 1.58 + 1.59 + // Try 100 MB higher. 1.60 + base = reinterpret_cast<char*>(base) + 100 * 0x100000; 1.61 + }; 1.62 + 1.63 + if (attempts == 41) 1.64 + return NULL; 1.65 + 1.66 + ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, 1.67 + &actual_size, MEM_COMMIT, PAGE_READWRITE); 1.68 + 1.69 + if (!NT_SUCCESS(ret)) { 1.70 + VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, 1.71 + MEM_RELEASE)); 1.72 + base = NULL; 1.73 + } 1.74 + 1.75 + return base; 1.76 +} 1.77 +#else // defined(_WIN64). 1.78 +void* AllocateNearTo(void* source, size_t size) { 1.79 + using sandbox::g_nt; 1.80 + UNREFERENCED_PARAMETER(source); 1.81 + 1.82 + // In 32-bit processes allocations below 512k are predictable, so mark 1.83 + // anything in that range as reserved and retry until we get a good address. 1.84 + const void* const kMinAddress = reinterpret_cast<void*>(512 * 1024); 1.85 + NTSTATUS ret; 1.86 + SIZE_T actual_size; 1.87 + void* base; 1.88 + do { 1.89 + base = NULL; 1.90 + actual_size = 64 * 1024; 1.91 + ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size, 1.92 + MEM_RESERVE, PAGE_NOACCESS); 1.93 + if (!NT_SUCCESS(ret)) 1.94 + return NULL; 1.95 + } while (base < kMinAddress); 1.96 + 1.97 + actual_size = size; 1.98 + ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size, 1.99 + MEM_COMMIT, PAGE_READWRITE); 1.100 + if (!NT_SUCCESS(ret)) 1.101 + return NULL; 1.102 + return base; 1.103 +} 1.104 +#endif // defined(_WIN64). 1.105 + 1.106 +} // namespace. 1.107 + 1.108 +namespace sandbox { 1.109 + 1.110 +// Handle for our private heap. 1.111 +void* g_heap = NULL; 1.112 + 1.113 +SANDBOX_INTERCEPT HANDLE g_shared_section; 1.114 +SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0; 1.115 +SANDBOX_INTERCEPT size_t g_shared_policy_size = 0; 1.116 + 1.117 +void* volatile g_shared_policy_memory = NULL; 1.118 +void* volatile g_shared_IPC_memory = NULL; 1.119 + 1.120 +// Both the IPC and the policy share a single region of memory in which the IPC 1.121 +// memory is first and the policy memory is last. 1.122 +bool MapGlobalMemory() { 1.123 + if (NULL == g_shared_IPC_memory) { 1.124 + void* memory = NULL; 1.125 + SIZE_T size = 0; 1.126 + // Map the entire shared section from the start. 1.127 + NTSTATUS ret = g_nt.MapViewOfSection(g_shared_section, NtCurrentProcess, 1.128 + &memory, 0, 0, NULL, &size, ViewUnmap, 1.129 + 0, PAGE_READWRITE); 1.130 + 1.131 + if (!NT_SUCCESS(ret) || NULL == memory) { 1.132 + NOTREACHED_NT(); 1.133 + return false; 1.134 + } 1.135 + 1.136 + if (NULL != _InterlockedCompareExchangePointer(&g_shared_IPC_memory, 1.137 + memory, NULL)) { 1.138 + // Somebody beat us to the memory setup. 1.139 + ret = g_nt.UnmapViewOfSection(NtCurrentProcess, memory); 1.140 + VERIFY_SUCCESS(ret); 1.141 + } 1.142 + DCHECK_NT(g_shared_IPC_size > 0); 1.143 + g_shared_policy_memory = reinterpret_cast<char*>(g_shared_IPC_memory) 1.144 + + g_shared_IPC_size; 1.145 + } 1.146 + DCHECK_NT(g_shared_policy_memory); 1.147 + DCHECK_NT(g_shared_policy_size > 0); 1.148 + return true; 1.149 +} 1.150 + 1.151 +void* GetGlobalIPCMemory() { 1.152 + if (!MapGlobalMemory()) 1.153 + return NULL; 1.154 + return g_shared_IPC_memory; 1.155 +} 1.156 + 1.157 +void* GetGlobalPolicyMemory() { 1.158 + if (!MapGlobalMemory()) 1.159 + return NULL; 1.160 + return g_shared_policy_memory; 1.161 +} 1.162 + 1.163 +bool InitHeap() { 1.164 + if (!g_heap) { 1.165 + // Create a new heap using default values for everything. 1.166 + void* heap = g_nt.RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL); 1.167 + if (!heap) 1.168 + return false; 1.169 + 1.170 + if (NULL != _InterlockedCompareExchangePointer(&g_heap, heap, NULL)) { 1.171 + // Somebody beat us to the memory setup. 1.172 + g_nt.RtlDestroyHeap(heap); 1.173 + } 1.174 + } 1.175 + return (g_heap != NULL); 1.176 +} 1.177 + 1.178 +// Physically reads or writes from memory to verify that (at this time), it is 1.179 +// valid. Returns a dummy value. 1.180 +int TouchMemory(void* buffer, size_t size_bytes, RequiredAccess intent) { 1.181 + const int kPageSize = 4096; 1.182 + int dummy = 0; 1.183 + char* start = reinterpret_cast<char*>(buffer); 1.184 + char* end = start + size_bytes - 1; 1.185 + 1.186 + if (WRITE == intent) { 1.187 + for (; start < end; start += kPageSize) { 1.188 + *start = 0; 1.189 + } 1.190 + *end = 0; 1.191 + } else { 1.192 + for (; start < end; start += kPageSize) { 1.193 + dummy += *start; 1.194 + } 1.195 + dummy += *end; 1.196 + } 1.197 + 1.198 + return dummy; 1.199 +} 1.200 + 1.201 +bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) { 1.202 + DCHECK_NT(size); 1.203 + __try { 1.204 + TouchMemory(buffer, size, intent); 1.205 + } __except(EXCEPTION_EXECUTE_HANDLER) { 1.206 + return false; 1.207 + } 1.208 + return true; 1.209 +} 1.210 + 1.211 +NTSTATUS CopyData(void* destination, const void* source, size_t bytes) { 1.212 + NTSTATUS ret = STATUS_SUCCESS; 1.213 + __try { 1.214 + if (SandboxFactory::GetTargetServices()->GetState()->InitCalled()) { 1.215 + memcpy(destination, source, bytes); 1.216 + } else { 1.217 + const char* from = reinterpret_cast<const char*>(source); 1.218 + char* to = reinterpret_cast<char*>(destination); 1.219 + for (size_t i = 0; i < bytes; i++) { 1.220 + to[i] = from[i]; 1.221 + } 1.222 + } 1.223 + } __except(EXCEPTION_EXECUTE_HANDLER) { 1.224 + ret = GetExceptionCode(); 1.225 + } 1.226 + return ret; 1.227 +} 1.228 + 1.229 +// Hacky code... replace with AllocAndCopyObjectAttributes. 1.230 +NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object, 1.231 + wchar_t** out_name, uint32* attributes, 1.232 + HANDLE* root) { 1.233 + if (!InitHeap()) 1.234 + return STATUS_NO_MEMORY; 1.235 + 1.236 + DCHECK_NT(out_name); 1.237 + *out_name = NULL; 1.238 + NTSTATUS ret = STATUS_UNSUCCESSFUL; 1.239 + __try { 1.240 + do { 1.241 + if (in_object->RootDirectory != static_cast<HANDLE>(0) && !root) 1.242 + break; 1.243 + if (NULL == in_object->ObjectName) 1.244 + break; 1.245 + if (NULL == in_object->ObjectName->Buffer) 1.246 + break; 1.247 + 1.248 + size_t size = in_object->ObjectName->Length + sizeof(wchar_t); 1.249 + *out_name = new(NT_ALLOC) wchar_t[size/sizeof(wchar_t)]; 1.250 + if (NULL == *out_name) 1.251 + break; 1.252 + 1.253 + ret = CopyData(*out_name, in_object->ObjectName->Buffer, 1.254 + size - sizeof(wchar_t)); 1.255 + if (!NT_SUCCESS(ret)) 1.256 + break; 1.257 + 1.258 + (*out_name)[size / sizeof(wchar_t) - 1] = L'\0'; 1.259 + 1.260 + if (attributes) 1.261 + *attributes = in_object->Attributes; 1.262 + 1.263 + if (root) 1.264 + *root = in_object->RootDirectory; 1.265 + ret = STATUS_SUCCESS; 1.266 + } while (false); 1.267 + } __except(EXCEPTION_EXECUTE_HANDLER) { 1.268 + ret = GetExceptionCode(); 1.269 + } 1.270 + 1.271 + if (!NT_SUCCESS(ret) && *out_name) { 1.272 + operator delete(*out_name, NT_ALLOC); 1.273 + *out_name = NULL; 1.274 + } 1.275 + 1.276 + return ret; 1.277 +} 1.278 + 1.279 +NTSTATUS GetProcessId(HANDLE process, ULONG *process_id) { 1.280 + PROCESS_BASIC_INFORMATION proc_info; 1.281 + ULONG bytes_returned; 1.282 + 1.283 + NTSTATUS ret = g_nt.QueryInformationProcess(process, ProcessBasicInformation, 1.284 + &proc_info, sizeof(proc_info), 1.285 + &bytes_returned); 1.286 + if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned) 1.287 + return ret; 1.288 + 1.289 + *process_id = proc_info.UniqueProcessId; 1.290 + return STATUS_SUCCESS; 1.291 +} 1.292 + 1.293 +bool IsSameProcess(HANDLE process) { 1.294 + if (NtCurrentProcess == process) 1.295 + return true; 1.296 + 1.297 + static ULONG s_process_id = 0; 1.298 + 1.299 + if (!s_process_id) { 1.300 + NTSTATUS ret = GetProcessId(NtCurrentProcess, &s_process_id); 1.301 + if (!NT_SUCCESS(ret)) 1.302 + return false; 1.303 + } 1.304 + 1.305 + ULONG process_id; 1.306 + NTSTATUS ret = GetProcessId(process, &process_id); 1.307 + if (!NT_SUCCESS(ret)) 1.308 + return false; 1.309 + 1.310 + return (process_id == s_process_id); 1.311 +} 1.312 + 1.313 +bool IsValidImageSection(HANDLE section, PVOID *base, PLARGE_INTEGER offset, 1.314 + PSIZE_T view_size) { 1.315 + if (!section || !base || !view_size || offset) 1.316 + return false; 1.317 + 1.318 + HANDLE query_section; 1.319 + 1.320 + NTSTATUS ret = g_nt.DuplicateObject(NtCurrentProcess, section, 1.321 + NtCurrentProcess, &query_section, 1.322 + SECTION_QUERY, 0, 0); 1.323 + if (!NT_SUCCESS(ret)) 1.324 + return false; 1.325 + 1.326 + SECTION_BASIC_INFORMATION basic_info; 1.327 + SIZE_T bytes_returned; 1.328 + ret = g_nt.QuerySection(query_section, SectionBasicInformation, &basic_info, 1.329 + sizeof(basic_info), &bytes_returned); 1.330 + 1.331 + VERIFY_SUCCESS(g_nt.Close(query_section)); 1.332 + 1.333 + if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned) 1.334 + return false; 1.335 + 1.336 + if (!(basic_info.Attributes & SEC_IMAGE)) 1.337 + return false; 1.338 + 1.339 + return true; 1.340 +} 1.341 + 1.342 +UNICODE_STRING* AnsiToUnicode(const char* string) { 1.343 + ANSI_STRING ansi_string; 1.344 + ansi_string.Length = static_cast<USHORT>(g_nt.strlen(string)); 1.345 + ansi_string.MaximumLength = ansi_string.Length + 1; 1.346 + ansi_string.Buffer = const_cast<char*>(string); 1.347 + 1.348 + if (ansi_string.Length > ansi_string.MaximumLength) 1.349 + return NULL; 1.350 + 1.351 + size_t name_bytes = ansi_string.MaximumLength * sizeof(wchar_t) + 1.352 + sizeof(UNICODE_STRING); 1.353 + 1.354 + UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>( 1.355 + new(NT_ALLOC) char[name_bytes]); 1.356 + if (!out_string) 1.357 + return NULL; 1.358 + 1.359 + out_string->MaximumLength = ansi_string.MaximumLength * sizeof(wchar_t); 1.360 + out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]); 1.361 + 1.362 + BOOLEAN alloc_destination = FALSE; 1.363 + NTSTATUS ret = g_nt.RtlAnsiStringToUnicodeString(out_string, &ansi_string, 1.364 + alloc_destination); 1.365 + DCHECK_NT(STATUS_BUFFER_OVERFLOW != ret); 1.366 + if (!NT_SUCCESS(ret)) { 1.367 + operator delete(out_string, NT_ALLOC); 1.368 + return NULL; 1.369 + } 1.370 + 1.371 + return out_string; 1.372 +} 1.373 + 1.374 +UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32* flags) { 1.375 + UNICODE_STRING* out_name = NULL; 1.376 + __try { 1.377 + do { 1.378 + *flags = 0; 1.379 + base::win::PEImage pe(module); 1.380 + 1.381 + if (!pe.VerifyMagic()) 1.382 + break; 1.383 + *flags |= MODULE_IS_PE_IMAGE; 1.384 + 1.385 + PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory(); 1.386 + if (exports) { 1.387 + char* name = reinterpret_cast<char*>(pe.RVAToAddr(exports->Name)); 1.388 + out_name = AnsiToUnicode(name); 1.389 + } 1.390 + 1.391 + PIMAGE_NT_HEADERS headers = pe.GetNTHeaders(); 1.392 + if (headers) { 1.393 + if (headers->OptionalHeader.AddressOfEntryPoint) 1.394 + *flags |= MODULE_HAS_ENTRY_POINT; 1.395 + if (headers->OptionalHeader.SizeOfCode) 1.396 + *flags |= MODULE_HAS_CODE; 1.397 + } 1.398 + } while (false); 1.399 + } __except(EXCEPTION_EXECUTE_HANDLER) { 1.400 + } 1.401 + 1.402 + return out_name; 1.403 +} 1.404 + 1.405 +UNICODE_STRING* GetBackingFilePath(PVOID address) { 1.406 + // We'll start with something close to max_path charactes for the name. 1.407 + ULONG buffer_bytes = MAX_PATH * 2; 1.408 + 1.409 + for (;;) { 1.410 + MEMORY_SECTION_NAME* section_name = reinterpret_cast<MEMORY_SECTION_NAME*>( 1.411 + new(NT_ALLOC) char[buffer_bytes]); 1.412 + 1.413 + if (!section_name) 1.414 + return NULL; 1.415 + 1.416 + ULONG returned_bytes; 1.417 + NTSTATUS ret = g_nt.QueryVirtualMemory(NtCurrentProcess, address, 1.418 + MemorySectionName, section_name, 1.419 + buffer_bytes, &returned_bytes); 1.420 + 1.421 + if (STATUS_BUFFER_OVERFLOW == ret) { 1.422 + // Retry the call with the given buffer size. 1.423 + operator delete(section_name, NT_ALLOC); 1.424 + section_name = NULL; 1.425 + buffer_bytes = returned_bytes; 1.426 + continue; 1.427 + } 1.428 + if (!NT_SUCCESS(ret)) { 1.429 + operator delete(section_name, NT_ALLOC); 1.430 + return NULL; 1.431 + } 1.432 + 1.433 + return reinterpret_cast<UNICODE_STRING*>(section_name); 1.434 + } 1.435 +} 1.436 + 1.437 +UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path) { 1.438 + if ((!module_path) || (!module_path->Buffer)) 1.439 + return NULL; 1.440 + 1.441 + wchar_t* sep = NULL; 1.442 + int start_pos = module_path->Length / sizeof(wchar_t) - 1; 1.443 + int ix = start_pos; 1.444 + 1.445 + for (; ix >= 0; --ix) { 1.446 + if (module_path->Buffer[ix] == L'\\') { 1.447 + sep = &module_path->Buffer[ix]; 1.448 + break; 1.449 + } 1.450 + } 1.451 + 1.452 + // Ends with path separator. Not a valid module name. 1.453 + if ((ix == start_pos) && sep) 1.454 + return NULL; 1.455 + 1.456 + // No path separator found. Use the entire name. 1.457 + if (!sep) { 1.458 + sep = &module_path->Buffer[-1]; 1.459 + } 1.460 + 1.461 + // Add one to the size so we can null terminate the string. 1.462 + size_t size_bytes = (start_pos - ix + 1) * sizeof(wchar_t); 1.463 + 1.464 + // Based on the code above, size_bytes should always be small enough 1.465 + // to make the static_cast below safe. 1.466 + DCHECK_NT(kuint16max > size_bytes); 1.467 + char* str_buffer = new(NT_ALLOC) char[size_bytes + sizeof(UNICODE_STRING)]; 1.468 + if (!str_buffer) 1.469 + return NULL; 1.470 + 1.471 + UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(str_buffer); 1.472 + out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]); 1.473 + out_string->Length = static_cast<USHORT>(size_bytes - sizeof(wchar_t)); 1.474 + out_string->MaximumLength = static_cast<USHORT>(size_bytes); 1.475 + 1.476 + NTSTATUS ret = CopyData(out_string->Buffer, &sep[1], out_string->Length); 1.477 + if (!NT_SUCCESS(ret)) { 1.478 + operator delete(out_string, NT_ALLOC); 1.479 + return NULL; 1.480 + } 1.481 + 1.482 + out_string->Buffer[out_string->Length / sizeof(wchar_t)] = L'\0'; 1.483 + return out_string; 1.484 +} 1.485 + 1.486 +NTSTATUS AutoProtectMemory::ChangeProtection(void* address, size_t bytes, 1.487 + ULONG protect) { 1.488 + DCHECK_NT(!changed_); 1.489 + SIZE_T new_bytes = bytes; 1.490 + NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address, 1.491 + &new_bytes, protect, &old_protect_); 1.492 + if (NT_SUCCESS(ret)) { 1.493 + changed_ = true; 1.494 + address_ = address; 1.495 + bytes_ = new_bytes; 1.496 + } 1.497 + 1.498 + return ret; 1.499 +} 1.500 + 1.501 +NTSTATUS AutoProtectMemory::RevertProtection() { 1.502 + if (!changed_) 1.503 + return STATUS_SUCCESS; 1.504 + 1.505 + DCHECK_NT(address_); 1.506 + DCHECK_NT(bytes_); 1.507 + 1.508 + SIZE_T new_bytes = bytes_; 1.509 + NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address_, 1.510 + &new_bytes, old_protect_, 1.511 + &old_protect_); 1.512 + DCHECK_NT(NT_SUCCESS(ret)); 1.513 + 1.514 + changed_ = false; 1.515 + address_ = NULL; 1.516 + bytes_ = 0; 1.517 + old_protect_ = 0; 1.518 + 1.519 + return ret; 1.520 +} 1.521 + 1.522 +bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info, DWORD length, 1.523 + uint32 file_info_class) { 1.524 + if (FileRenameInformation != file_info_class) 1.525 + return false; 1.526 + 1.527 + if (length < sizeof(FILE_RENAME_INFORMATION)) 1.528 + return false; 1.529 + 1.530 + // Make sure file name length doesn't exceed the message length 1.531 + if (length - offsetof(FILE_RENAME_INFORMATION, FileName) < 1.532 + file_info->FileNameLength) 1.533 + return false; 1.534 + 1.535 + // We don't support a root directory. 1.536 + if (file_info->RootDirectory) 1.537 + return false; 1.538 + 1.539 + // Check if it starts with \\??\\. We don't support relative paths. 1.540 + if (file_info->FileNameLength < 4 || file_info->FileNameLength > kuint16max) 1.541 + return false; 1.542 + 1.543 + if (file_info->FileName[0] != L'\\' || 1.544 + file_info->FileName[1] != L'?' || 1.545 + file_info->FileName[2] != L'?' || 1.546 + file_info->FileName[3] != L'\\') 1.547 + return false; 1.548 + 1.549 + return true; 1.550 +} 1.551 + 1.552 +} // namespace sandbox 1.553 + 1.554 +void* operator new(size_t size, sandbox::AllocationType type, 1.555 + void* near_to) { 1.556 + using namespace sandbox; 1.557 + 1.558 + if (NT_ALLOC == type) { 1.559 + if (!InitHeap()) 1.560 + return NULL; 1.561 + 1.562 + // Use default flags for the allocation. 1.563 + return g_nt.RtlAllocateHeap(sandbox::g_heap, 0, size); 1.564 + } else if (NT_PAGE == type) { 1.565 + return AllocateNearTo(near_to, size); 1.566 + } 1.567 + NOTREACHED_NT(); 1.568 + return NULL; 1.569 +} 1.570 + 1.571 +void operator delete(void* memory, sandbox::AllocationType type) { 1.572 + using namespace sandbox; 1.573 + 1.574 + if (NT_ALLOC == type) { 1.575 + // Use default flags. 1.576 + VERIFY(g_nt.RtlFreeHeap(sandbox::g_heap, 0, memory)); 1.577 + } else if (NT_PAGE == type) { 1.578 + void* base = memory; 1.579 + SIZE_T size = 0; 1.580 + VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, 1.581 + MEM_RELEASE)); 1.582 + } else { 1.583 + NOTREACHED_NT(); 1.584 + } 1.585 +} 1.586 + 1.587 +void operator delete(void* memory, sandbox::AllocationType type, 1.588 + void* near_to) { 1.589 + UNREFERENCED_PARAMETER(near_to); 1.590 + operator delete(memory, type); 1.591 +} 1.592 + 1.593 +void* __cdecl operator new(size_t size, void* buffer, 1.594 + sandbox::AllocationType type) { 1.595 + UNREFERENCED_PARAMETER(size); 1.596 + UNREFERENCED_PARAMETER(type); 1.597 + return buffer; 1.598 +} 1.599 + 1.600 +void __cdecl operator delete(void* memory, void* buffer, 1.601 + sandbox::AllocationType type) { 1.602 + UNREFERENCED_PARAMETER(memory); 1.603 + UNREFERENCED_PARAMETER(buffer); 1.604 + UNREFERENCED_PARAMETER(type); 1.605 +}