security/sandbox/win/src/sandbox_nt_util.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "sandbox/win/src/sandbox_nt_util.h"
michael@0 6
michael@0 7 #include "base/win/pe_image.h"
michael@0 8 #include "sandbox/win/src/sandbox_factory.h"
michael@0 9 #include "sandbox/win/src/target_services.h"
michael@0 10
michael@0 11 namespace sandbox {
michael@0 12
michael@0 13 // This is the list of all imported symbols from ntdll.dll.
michael@0 14 SANDBOX_INTERCEPT NtExports g_nt = { NULL };
michael@0 15
michael@0 16 } // namespace sandbox
michael@0 17
michael@0 18 namespace {
michael@0 19
michael@0 20 #if defined(_WIN64)
michael@0 21 void* AllocateNearTo(void* source, size_t size) {
michael@0 22 using sandbox::g_nt;
michael@0 23
michael@0 24 // Start with 1 GB above the source.
michael@0 25 const size_t kOneGB = 0x40000000;
michael@0 26 void* base = reinterpret_cast<char*>(source) + kOneGB;
michael@0 27 SIZE_T actual_size = size;
michael@0 28 ULONG_PTR zero_bits = 0; // Not the correct type if used.
michael@0 29 ULONG type = MEM_RESERVE;
michael@0 30
michael@0 31 NTSTATUS ret;
michael@0 32 int attempts = 0;
michael@0 33 for (; attempts < 41; attempts++) {
michael@0 34 ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits,
michael@0 35 &actual_size, type, PAGE_READWRITE);
michael@0 36 if (NT_SUCCESS(ret)) {
michael@0 37 if (base < source ||
michael@0 38 base >= reinterpret_cast<char*>(source) + 4 * kOneGB) {
michael@0 39 // We won't be able to patch this dll.
michael@0 40 VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size,
michael@0 41 MEM_RELEASE));
michael@0 42 return NULL;
michael@0 43 }
michael@0 44 break;
michael@0 45 }
michael@0 46
michael@0 47 if (attempts == 30) {
michael@0 48 // Try the first GB.
michael@0 49 base = reinterpret_cast<char*>(source);
michael@0 50 } else if (attempts == 40) {
michael@0 51 // Try the highest available address.
michael@0 52 base = NULL;
michael@0 53 type |= MEM_TOP_DOWN;
michael@0 54 }
michael@0 55
michael@0 56 // Try 100 MB higher.
michael@0 57 base = reinterpret_cast<char*>(base) + 100 * 0x100000;
michael@0 58 };
michael@0 59
michael@0 60 if (attempts == 41)
michael@0 61 return NULL;
michael@0 62
michael@0 63 ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits,
michael@0 64 &actual_size, MEM_COMMIT, PAGE_READWRITE);
michael@0 65
michael@0 66 if (!NT_SUCCESS(ret)) {
michael@0 67 VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size,
michael@0 68 MEM_RELEASE));
michael@0 69 base = NULL;
michael@0 70 }
michael@0 71
michael@0 72 return base;
michael@0 73 }
michael@0 74 #else // defined(_WIN64).
michael@0 75 void* AllocateNearTo(void* source, size_t size) {
michael@0 76 using sandbox::g_nt;
michael@0 77 UNREFERENCED_PARAMETER(source);
michael@0 78
michael@0 79 // In 32-bit processes allocations below 512k are predictable, so mark
michael@0 80 // anything in that range as reserved and retry until we get a good address.
michael@0 81 const void* const kMinAddress = reinterpret_cast<void*>(512 * 1024);
michael@0 82 NTSTATUS ret;
michael@0 83 SIZE_T actual_size;
michael@0 84 void* base;
michael@0 85 do {
michael@0 86 base = NULL;
michael@0 87 actual_size = 64 * 1024;
michael@0 88 ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size,
michael@0 89 MEM_RESERVE, PAGE_NOACCESS);
michael@0 90 if (!NT_SUCCESS(ret))
michael@0 91 return NULL;
michael@0 92 } while (base < kMinAddress);
michael@0 93
michael@0 94 actual_size = size;
michael@0 95 ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size,
michael@0 96 MEM_COMMIT, PAGE_READWRITE);
michael@0 97 if (!NT_SUCCESS(ret))
michael@0 98 return NULL;
michael@0 99 return base;
michael@0 100 }
michael@0 101 #endif // defined(_WIN64).
michael@0 102
michael@0 103 } // namespace.
michael@0 104
michael@0 105 namespace sandbox {
michael@0 106
michael@0 107 // Handle for our private heap.
michael@0 108 void* g_heap = NULL;
michael@0 109
michael@0 110 SANDBOX_INTERCEPT HANDLE g_shared_section;
michael@0 111 SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0;
michael@0 112 SANDBOX_INTERCEPT size_t g_shared_policy_size = 0;
michael@0 113
michael@0 114 void* volatile g_shared_policy_memory = NULL;
michael@0 115 void* volatile g_shared_IPC_memory = NULL;
michael@0 116
michael@0 117 // Both the IPC and the policy share a single region of memory in which the IPC
michael@0 118 // memory is first and the policy memory is last.
michael@0 119 bool MapGlobalMemory() {
michael@0 120 if (NULL == g_shared_IPC_memory) {
michael@0 121 void* memory = NULL;
michael@0 122 SIZE_T size = 0;
michael@0 123 // Map the entire shared section from the start.
michael@0 124 NTSTATUS ret = g_nt.MapViewOfSection(g_shared_section, NtCurrentProcess,
michael@0 125 &memory, 0, 0, NULL, &size, ViewUnmap,
michael@0 126 0, PAGE_READWRITE);
michael@0 127
michael@0 128 if (!NT_SUCCESS(ret) || NULL == memory) {
michael@0 129 NOTREACHED_NT();
michael@0 130 return false;
michael@0 131 }
michael@0 132
michael@0 133 if (NULL != _InterlockedCompareExchangePointer(&g_shared_IPC_memory,
michael@0 134 memory, NULL)) {
michael@0 135 // Somebody beat us to the memory setup.
michael@0 136 ret = g_nt.UnmapViewOfSection(NtCurrentProcess, memory);
michael@0 137 VERIFY_SUCCESS(ret);
michael@0 138 }
michael@0 139 DCHECK_NT(g_shared_IPC_size > 0);
michael@0 140 g_shared_policy_memory = reinterpret_cast<char*>(g_shared_IPC_memory)
michael@0 141 + g_shared_IPC_size;
michael@0 142 }
michael@0 143 DCHECK_NT(g_shared_policy_memory);
michael@0 144 DCHECK_NT(g_shared_policy_size > 0);
michael@0 145 return true;
michael@0 146 }
michael@0 147
michael@0 148 void* GetGlobalIPCMemory() {
michael@0 149 if (!MapGlobalMemory())
michael@0 150 return NULL;
michael@0 151 return g_shared_IPC_memory;
michael@0 152 }
michael@0 153
michael@0 154 void* GetGlobalPolicyMemory() {
michael@0 155 if (!MapGlobalMemory())
michael@0 156 return NULL;
michael@0 157 return g_shared_policy_memory;
michael@0 158 }
michael@0 159
michael@0 160 bool InitHeap() {
michael@0 161 if (!g_heap) {
michael@0 162 // Create a new heap using default values for everything.
michael@0 163 void* heap = g_nt.RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL);
michael@0 164 if (!heap)
michael@0 165 return false;
michael@0 166
michael@0 167 if (NULL != _InterlockedCompareExchangePointer(&g_heap, heap, NULL)) {
michael@0 168 // Somebody beat us to the memory setup.
michael@0 169 g_nt.RtlDestroyHeap(heap);
michael@0 170 }
michael@0 171 }
michael@0 172 return (g_heap != NULL);
michael@0 173 }
michael@0 174
michael@0 175 // Physically reads or writes from memory to verify that (at this time), it is
michael@0 176 // valid. Returns a dummy value.
michael@0 177 int TouchMemory(void* buffer, size_t size_bytes, RequiredAccess intent) {
michael@0 178 const int kPageSize = 4096;
michael@0 179 int dummy = 0;
michael@0 180 char* start = reinterpret_cast<char*>(buffer);
michael@0 181 char* end = start + size_bytes - 1;
michael@0 182
michael@0 183 if (WRITE == intent) {
michael@0 184 for (; start < end; start += kPageSize) {
michael@0 185 *start = 0;
michael@0 186 }
michael@0 187 *end = 0;
michael@0 188 } else {
michael@0 189 for (; start < end; start += kPageSize) {
michael@0 190 dummy += *start;
michael@0 191 }
michael@0 192 dummy += *end;
michael@0 193 }
michael@0 194
michael@0 195 return dummy;
michael@0 196 }
michael@0 197
michael@0 198 bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) {
michael@0 199 DCHECK_NT(size);
michael@0 200 __try {
michael@0 201 TouchMemory(buffer, size, intent);
michael@0 202 } __except(EXCEPTION_EXECUTE_HANDLER) {
michael@0 203 return false;
michael@0 204 }
michael@0 205 return true;
michael@0 206 }
michael@0 207
michael@0 208 NTSTATUS CopyData(void* destination, const void* source, size_t bytes) {
michael@0 209 NTSTATUS ret = STATUS_SUCCESS;
michael@0 210 __try {
michael@0 211 if (SandboxFactory::GetTargetServices()->GetState()->InitCalled()) {
michael@0 212 memcpy(destination, source, bytes);
michael@0 213 } else {
michael@0 214 const char* from = reinterpret_cast<const char*>(source);
michael@0 215 char* to = reinterpret_cast<char*>(destination);
michael@0 216 for (size_t i = 0; i < bytes; i++) {
michael@0 217 to[i] = from[i];
michael@0 218 }
michael@0 219 }
michael@0 220 } __except(EXCEPTION_EXECUTE_HANDLER) {
michael@0 221 ret = GetExceptionCode();
michael@0 222 }
michael@0 223 return ret;
michael@0 224 }
michael@0 225
michael@0 226 // Hacky code... replace with AllocAndCopyObjectAttributes.
michael@0 227 NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
michael@0 228 wchar_t** out_name, uint32* attributes,
michael@0 229 HANDLE* root) {
michael@0 230 if (!InitHeap())
michael@0 231 return STATUS_NO_MEMORY;
michael@0 232
michael@0 233 DCHECK_NT(out_name);
michael@0 234 *out_name = NULL;
michael@0 235 NTSTATUS ret = STATUS_UNSUCCESSFUL;
michael@0 236 __try {
michael@0 237 do {
michael@0 238 if (in_object->RootDirectory != static_cast<HANDLE>(0) && !root)
michael@0 239 break;
michael@0 240 if (NULL == in_object->ObjectName)
michael@0 241 break;
michael@0 242 if (NULL == in_object->ObjectName->Buffer)
michael@0 243 break;
michael@0 244
michael@0 245 size_t size = in_object->ObjectName->Length + sizeof(wchar_t);
michael@0 246 *out_name = new(NT_ALLOC) wchar_t[size/sizeof(wchar_t)];
michael@0 247 if (NULL == *out_name)
michael@0 248 break;
michael@0 249
michael@0 250 ret = CopyData(*out_name, in_object->ObjectName->Buffer,
michael@0 251 size - sizeof(wchar_t));
michael@0 252 if (!NT_SUCCESS(ret))
michael@0 253 break;
michael@0 254
michael@0 255 (*out_name)[size / sizeof(wchar_t) - 1] = L'\0';
michael@0 256
michael@0 257 if (attributes)
michael@0 258 *attributes = in_object->Attributes;
michael@0 259
michael@0 260 if (root)
michael@0 261 *root = in_object->RootDirectory;
michael@0 262 ret = STATUS_SUCCESS;
michael@0 263 } while (false);
michael@0 264 } __except(EXCEPTION_EXECUTE_HANDLER) {
michael@0 265 ret = GetExceptionCode();
michael@0 266 }
michael@0 267
michael@0 268 if (!NT_SUCCESS(ret) && *out_name) {
michael@0 269 operator delete(*out_name, NT_ALLOC);
michael@0 270 *out_name = NULL;
michael@0 271 }
michael@0 272
michael@0 273 return ret;
michael@0 274 }
michael@0 275
michael@0 276 NTSTATUS GetProcessId(HANDLE process, ULONG *process_id) {
michael@0 277 PROCESS_BASIC_INFORMATION proc_info;
michael@0 278 ULONG bytes_returned;
michael@0 279
michael@0 280 NTSTATUS ret = g_nt.QueryInformationProcess(process, ProcessBasicInformation,
michael@0 281 &proc_info, sizeof(proc_info),
michael@0 282 &bytes_returned);
michael@0 283 if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned)
michael@0 284 return ret;
michael@0 285
michael@0 286 *process_id = proc_info.UniqueProcessId;
michael@0 287 return STATUS_SUCCESS;
michael@0 288 }
michael@0 289
michael@0 290 bool IsSameProcess(HANDLE process) {
michael@0 291 if (NtCurrentProcess == process)
michael@0 292 return true;
michael@0 293
michael@0 294 static ULONG s_process_id = 0;
michael@0 295
michael@0 296 if (!s_process_id) {
michael@0 297 NTSTATUS ret = GetProcessId(NtCurrentProcess, &s_process_id);
michael@0 298 if (!NT_SUCCESS(ret))
michael@0 299 return false;
michael@0 300 }
michael@0 301
michael@0 302 ULONG process_id;
michael@0 303 NTSTATUS ret = GetProcessId(process, &process_id);
michael@0 304 if (!NT_SUCCESS(ret))
michael@0 305 return false;
michael@0 306
michael@0 307 return (process_id == s_process_id);
michael@0 308 }
michael@0 309
michael@0 310 bool IsValidImageSection(HANDLE section, PVOID *base, PLARGE_INTEGER offset,
michael@0 311 PSIZE_T view_size) {
michael@0 312 if (!section || !base || !view_size || offset)
michael@0 313 return false;
michael@0 314
michael@0 315 HANDLE query_section;
michael@0 316
michael@0 317 NTSTATUS ret = g_nt.DuplicateObject(NtCurrentProcess, section,
michael@0 318 NtCurrentProcess, &query_section,
michael@0 319 SECTION_QUERY, 0, 0);
michael@0 320 if (!NT_SUCCESS(ret))
michael@0 321 return false;
michael@0 322
michael@0 323 SECTION_BASIC_INFORMATION basic_info;
michael@0 324 SIZE_T bytes_returned;
michael@0 325 ret = g_nt.QuerySection(query_section, SectionBasicInformation, &basic_info,
michael@0 326 sizeof(basic_info), &bytes_returned);
michael@0 327
michael@0 328 VERIFY_SUCCESS(g_nt.Close(query_section));
michael@0 329
michael@0 330 if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned)
michael@0 331 return false;
michael@0 332
michael@0 333 if (!(basic_info.Attributes & SEC_IMAGE))
michael@0 334 return false;
michael@0 335
michael@0 336 return true;
michael@0 337 }
michael@0 338
michael@0 339 UNICODE_STRING* AnsiToUnicode(const char* string) {
michael@0 340 ANSI_STRING ansi_string;
michael@0 341 ansi_string.Length = static_cast<USHORT>(g_nt.strlen(string));
michael@0 342 ansi_string.MaximumLength = ansi_string.Length + 1;
michael@0 343 ansi_string.Buffer = const_cast<char*>(string);
michael@0 344
michael@0 345 if (ansi_string.Length > ansi_string.MaximumLength)
michael@0 346 return NULL;
michael@0 347
michael@0 348 size_t name_bytes = ansi_string.MaximumLength * sizeof(wchar_t) +
michael@0 349 sizeof(UNICODE_STRING);
michael@0 350
michael@0 351 UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(
michael@0 352 new(NT_ALLOC) char[name_bytes]);
michael@0 353 if (!out_string)
michael@0 354 return NULL;
michael@0 355
michael@0 356 out_string->MaximumLength = ansi_string.MaximumLength * sizeof(wchar_t);
michael@0 357 out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
michael@0 358
michael@0 359 BOOLEAN alloc_destination = FALSE;
michael@0 360 NTSTATUS ret = g_nt.RtlAnsiStringToUnicodeString(out_string, &ansi_string,
michael@0 361 alloc_destination);
michael@0 362 DCHECK_NT(STATUS_BUFFER_OVERFLOW != ret);
michael@0 363 if (!NT_SUCCESS(ret)) {
michael@0 364 operator delete(out_string, NT_ALLOC);
michael@0 365 return NULL;
michael@0 366 }
michael@0 367
michael@0 368 return out_string;
michael@0 369 }
michael@0 370
michael@0 371 UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32* flags) {
michael@0 372 UNICODE_STRING* out_name = NULL;
michael@0 373 __try {
michael@0 374 do {
michael@0 375 *flags = 0;
michael@0 376 base::win::PEImage pe(module);
michael@0 377
michael@0 378 if (!pe.VerifyMagic())
michael@0 379 break;
michael@0 380 *flags |= MODULE_IS_PE_IMAGE;
michael@0 381
michael@0 382 PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory();
michael@0 383 if (exports) {
michael@0 384 char* name = reinterpret_cast<char*>(pe.RVAToAddr(exports->Name));
michael@0 385 out_name = AnsiToUnicode(name);
michael@0 386 }
michael@0 387
michael@0 388 PIMAGE_NT_HEADERS headers = pe.GetNTHeaders();
michael@0 389 if (headers) {
michael@0 390 if (headers->OptionalHeader.AddressOfEntryPoint)
michael@0 391 *flags |= MODULE_HAS_ENTRY_POINT;
michael@0 392 if (headers->OptionalHeader.SizeOfCode)
michael@0 393 *flags |= MODULE_HAS_CODE;
michael@0 394 }
michael@0 395 } while (false);
michael@0 396 } __except(EXCEPTION_EXECUTE_HANDLER) {
michael@0 397 }
michael@0 398
michael@0 399 return out_name;
michael@0 400 }
michael@0 401
michael@0 402 UNICODE_STRING* GetBackingFilePath(PVOID address) {
michael@0 403 // We'll start with something close to max_path charactes for the name.
michael@0 404 ULONG buffer_bytes = MAX_PATH * 2;
michael@0 405
michael@0 406 for (;;) {
michael@0 407 MEMORY_SECTION_NAME* section_name = reinterpret_cast<MEMORY_SECTION_NAME*>(
michael@0 408 new(NT_ALLOC) char[buffer_bytes]);
michael@0 409
michael@0 410 if (!section_name)
michael@0 411 return NULL;
michael@0 412
michael@0 413 ULONG returned_bytes;
michael@0 414 NTSTATUS ret = g_nt.QueryVirtualMemory(NtCurrentProcess, address,
michael@0 415 MemorySectionName, section_name,
michael@0 416 buffer_bytes, &returned_bytes);
michael@0 417
michael@0 418 if (STATUS_BUFFER_OVERFLOW == ret) {
michael@0 419 // Retry the call with the given buffer size.
michael@0 420 operator delete(section_name, NT_ALLOC);
michael@0 421 section_name = NULL;
michael@0 422 buffer_bytes = returned_bytes;
michael@0 423 continue;
michael@0 424 }
michael@0 425 if (!NT_SUCCESS(ret)) {
michael@0 426 operator delete(section_name, NT_ALLOC);
michael@0 427 return NULL;
michael@0 428 }
michael@0 429
michael@0 430 return reinterpret_cast<UNICODE_STRING*>(section_name);
michael@0 431 }
michael@0 432 }
michael@0 433
michael@0 434 UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path) {
michael@0 435 if ((!module_path) || (!module_path->Buffer))
michael@0 436 return NULL;
michael@0 437
michael@0 438 wchar_t* sep = NULL;
michael@0 439 int start_pos = module_path->Length / sizeof(wchar_t) - 1;
michael@0 440 int ix = start_pos;
michael@0 441
michael@0 442 for (; ix >= 0; --ix) {
michael@0 443 if (module_path->Buffer[ix] == L'\\') {
michael@0 444 sep = &module_path->Buffer[ix];
michael@0 445 break;
michael@0 446 }
michael@0 447 }
michael@0 448
michael@0 449 // Ends with path separator. Not a valid module name.
michael@0 450 if ((ix == start_pos) && sep)
michael@0 451 return NULL;
michael@0 452
michael@0 453 // No path separator found. Use the entire name.
michael@0 454 if (!sep) {
michael@0 455 sep = &module_path->Buffer[-1];
michael@0 456 }
michael@0 457
michael@0 458 // Add one to the size so we can null terminate the string.
michael@0 459 size_t size_bytes = (start_pos - ix + 1) * sizeof(wchar_t);
michael@0 460
michael@0 461 // Based on the code above, size_bytes should always be small enough
michael@0 462 // to make the static_cast below safe.
michael@0 463 DCHECK_NT(kuint16max > size_bytes);
michael@0 464 char* str_buffer = new(NT_ALLOC) char[size_bytes + sizeof(UNICODE_STRING)];
michael@0 465 if (!str_buffer)
michael@0 466 return NULL;
michael@0 467
michael@0 468 UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(str_buffer);
michael@0 469 out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
michael@0 470 out_string->Length = static_cast<USHORT>(size_bytes - sizeof(wchar_t));
michael@0 471 out_string->MaximumLength = static_cast<USHORT>(size_bytes);
michael@0 472
michael@0 473 NTSTATUS ret = CopyData(out_string->Buffer, &sep[1], out_string->Length);
michael@0 474 if (!NT_SUCCESS(ret)) {
michael@0 475 operator delete(out_string, NT_ALLOC);
michael@0 476 return NULL;
michael@0 477 }
michael@0 478
michael@0 479 out_string->Buffer[out_string->Length / sizeof(wchar_t)] = L'\0';
michael@0 480 return out_string;
michael@0 481 }
michael@0 482
michael@0 483 NTSTATUS AutoProtectMemory::ChangeProtection(void* address, size_t bytes,
michael@0 484 ULONG protect) {
michael@0 485 DCHECK_NT(!changed_);
michael@0 486 SIZE_T new_bytes = bytes;
michael@0 487 NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address,
michael@0 488 &new_bytes, protect, &old_protect_);
michael@0 489 if (NT_SUCCESS(ret)) {
michael@0 490 changed_ = true;
michael@0 491 address_ = address;
michael@0 492 bytes_ = new_bytes;
michael@0 493 }
michael@0 494
michael@0 495 return ret;
michael@0 496 }
michael@0 497
michael@0 498 NTSTATUS AutoProtectMemory::RevertProtection() {
michael@0 499 if (!changed_)
michael@0 500 return STATUS_SUCCESS;
michael@0 501
michael@0 502 DCHECK_NT(address_);
michael@0 503 DCHECK_NT(bytes_);
michael@0 504
michael@0 505 SIZE_T new_bytes = bytes_;
michael@0 506 NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address_,
michael@0 507 &new_bytes, old_protect_,
michael@0 508 &old_protect_);
michael@0 509 DCHECK_NT(NT_SUCCESS(ret));
michael@0 510
michael@0 511 changed_ = false;
michael@0 512 address_ = NULL;
michael@0 513 bytes_ = 0;
michael@0 514 old_protect_ = 0;
michael@0 515
michael@0 516 return ret;
michael@0 517 }
michael@0 518
michael@0 519 bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info, DWORD length,
michael@0 520 uint32 file_info_class) {
michael@0 521 if (FileRenameInformation != file_info_class)
michael@0 522 return false;
michael@0 523
michael@0 524 if (length < sizeof(FILE_RENAME_INFORMATION))
michael@0 525 return false;
michael@0 526
michael@0 527 // Make sure file name length doesn't exceed the message length
michael@0 528 if (length - offsetof(FILE_RENAME_INFORMATION, FileName) <
michael@0 529 file_info->FileNameLength)
michael@0 530 return false;
michael@0 531
michael@0 532 // We don't support a root directory.
michael@0 533 if (file_info->RootDirectory)
michael@0 534 return false;
michael@0 535
michael@0 536 // Check if it starts with \\??\\. We don't support relative paths.
michael@0 537 if (file_info->FileNameLength < 4 || file_info->FileNameLength > kuint16max)
michael@0 538 return false;
michael@0 539
michael@0 540 if (file_info->FileName[0] != L'\\' ||
michael@0 541 file_info->FileName[1] != L'?' ||
michael@0 542 file_info->FileName[2] != L'?' ||
michael@0 543 file_info->FileName[3] != L'\\')
michael@0 544 return false;
michael@0 545
michael@0 546 return true;
michael@0 547 }
michael@0 548
michael@0 549 } // namespace sandbox
michael@0 550
michael@0 551 void* operator new(size_t size, sandbox::AllocationType type,
michael@0 552 void* near_to) {
michael@0 553 using namespace sandbox;
michael@0 554
michael@0 555 if (NT_ALLOC == type) {
michael@0 556 if (!InitHeap())
michael@0 557 return NULL;
michael@0 558
michael@0 559 // Use default flags for the allocation.
michael@0 560 return g_nt.RtlAllocateHeap(sandbox::g_heap, 0, size);
michael@0 561 } else if (NT_PAGE == type) {
michael@0 562 return AllocateNearTo(near_to, size);
michael@0 563 }
michael@0 564 NOTREACHED_NT();
michael@0 565 return NULL;
michael@0 566 }
michael@0 567
michael@0 568 void operator delete(void* memory, sandbox::AllocationType type) {
michael@0 569 using namespace sandbox;
michael@0 570
michael@0 571 if (NT_ALLOC == type) {
michael@0 572 // Use default flags.
michael@0 573 VERIFY(g_nt.RtlFreeHeap(sandbox::g_heap, 0, memory));
michael@0 574 } else if (NT_PAGE == type) {
michael@0 575 void* base = memory;
michael@0 576 SIZE_T size = 0;
michael@0 577 VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size,
michael@0 578 MEM_RELEASE));
michael@0 579 } else {
michael@0 580 NOTREACHED_NT();
michael@0 581 }
michael@0 582 }
michael@0 583
michael@0 584 void operator delete(void* memory, sandbox::AllocationType type,
michael@0 585 void* near_to) {
michael@0 586 UNREFERENCED_PARAMETER(near_to);
michael@0 587 operator delete(memory, type);
michael@0 588 }
michael@0 589
michael@0 590 void* __cdecl operator new(size_t size, void* buffer,
michael@0 591 sandbox::AllocationType type) {
michael@0 592 UNREFERENCED_PARAMETER(size);
michael@0 593 UNREFERENCED_PARAMETER(type);
michael@0 594 return buffer;
michael@0 595 }
michael@0 596
michael@0 597 void __cdecl operator delete(void* memory, void* buffer,
michael@0 598 sandbox::AllocationType type) {
michael@0 599 UNREFERENCED_PARAMETER(memory);
michael@0 600 UNREFERENCED_PARAMETER(buffer);
michael@0 601 UNREFERENCED_PARAMETER(type);
michael@0 602 }

mercurial