Chromium Code Reviews| 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 "base/win/pe_image.h" | 7 #include "base/win/pe_image.h" |
| 8 #include "sandbox/win/src/sandbox_factory.h" | 8 #include "sandbox/win/src/sandbox_factory.h" |
| 9 #include "sandbox/win/src/target_services.h" | 9 #include "sandbox/win/src/target_services.h" |
| 10 | 10 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 100 } | 100 } |
| 101 #endif // defined(_WIN64). | 101 #endif // defined(_WIN64). |
| 102 | 102 |
| 103 } // namespace. | 103 } // namespace. |
| 104 | 104 |
| 105 namespace sandbox { | 105 namespace sandbox { |
| 106 | 106 |
| 107 // Handle for our private heap. | 107 // Handle for our private heap. |
| 108 void* g_heap = NULL; | 108 void* g_heap = NULL; |
| 109 | 109 |
| 110 SANDBOX_INTERCEPT HANDLE g_shared_section; | |
| 111 SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0; | |
| 112 SANDBOX_INTERCEPT size_t g_shared_policy_size = 0; | |
| 113 | |
| 114 void* volatile g_shared_policy_memory = NULL; | |
| 115 void* volatile g_shared_IPC_memory = NULL; | |
| 116 | |
| 117 // Both the IPC and the policy share a single region of memory in which the IPC | |
| 118 // memory is first and the policy memory is last. | |
| 119 bool MapGlobalMemory() { | |
|
rvargas (doing something else)
2013/11/26 20:42:12
I don't see anything in this block of code that sh
robertshield
2013/11/27 20:28:01
The code in just this block doesn't actually pull
| |
| 120 if (NULL == g_shared_IPC_memory) { | |
| 121 void* memory = NULL; | |
| 122 SIZE_T size = 0; | |
| 123 // Map the entire shared section from the start. | |
| 124 NTSTATUS ret = g_nt.MapViewOfSection(g_shared_section, NtCurrentProcess, | |
| 125 &memory, 0, 0, NULL, &size, ViewUnmap, | |
| 126 0, PAGE_READWRITE); | |
| 127 | |
| 128 if (!NT_SUCCESS(ret) || NULL == memory) { | |
| 129 NOTREACHED_NT(); | |
| 130 return false; | |
| 131 } | |
| 132 | |
| 133 if (NULL != _InterlockedCompareExchangePointer(&g_shared_IPC_memory, | |
| 134 memory, NULL)) { | |
| 135 // Somebody beat us to the memory setup. | |
| 136 ret = g_nt.UnmapViewOfSection(NtCurrentProcess, memory); | |
| 137 VERIFY_SUCCESS(ret); | |
| 138 } | |
| 139 DCHECK_NT(g_shared_IPC_size > 0); | |
| 140 g_shared_policy_memory = reinterpret_cast<char*>(g_shared_IPC_memory) | |
| 141 + g_shared_IPC_size; | |
| 142 } | |
| 143 DCHECK_NT(g_shared_policy_memory); | |
| 144 DCHECK_NT(g_shared_policy_size > 0); | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 void* GetGlobalIPCMemory() { | |
| 149 if (!MapGlobalMemory()) | |
| 150 return NULL; | |
| 151 return g_shared_IPC_memory; | |
| 152 } | |
| 153 | |
| 154 void* GetGlobalPolicyMemory() { | |
| 155 if (!MapGlobalMemory()) | |
| 156 return NULL; | |
| 157 return g_shared_policy_memory; | |
| 158 } | |
| 159 | |
| 160 bool InitHeap() { | 110 bool InitHeap() { |
| 161 if (!g_heap) { | 111 if (!g_heap) { |
| 162 // Create a new heap using default values for everything. | 112 // Create a new heap using default values for everything. |
| 163 void* heap = g_nt.RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL); | 113 void* heap = g_nt.RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL); |
| 164 if (!heap) | 114 if (!heap) |
| 165 return false; | 115 return false; |
| 166 | 116 |
| 167 if (NULL != _InterlockedCompareExchangePointer(&g_heap, heap, NULL)) { | 117 if (NULL != _InterlockedCompareExchangePointer(&g_heap, heap, NULL)) { |
| 168 // Somebody beat us to the memory setup. | 118 // Somebody beat us to the memory setup. |
| 169 g_nt.RtlDestroyHeap(heap); | 119 g_nt.RtlDestroyHeap(heap); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 198 bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) { | 148 bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) { |
| 199 DCHECK_NT(size); | 149 DCHECK_NT(size); |
| 200 __try { | 150 __try { |
| 201 TouchMemory(buffer, size, intent); | 151 TouchMemory(buffer, size, intent); |
| 202 } __except(EXCEPTION_EXECUTE_HANDLER) { | 152 } __except(EXCEPTION_EXECUTE_HANDLER) { |
| 203 return false; | 153 return false; |
| 204 } | 154 } |
| 205 return true; | 155 return true; |
| 206 } | 156 } |
| 207 | 157 |
| 208 NTSTATUS CopyData(void* destination, const void* source, size_t bytes) { | |
| 209 NTSTATUS ret = STATUS_SUCCESS; | |
| 210 __try { | |
| 211 if (SandboxFactory::GetTargetServices()->GetState()->InitCalled()) { | |
|
rvargas (doing something else)
2013/11/26 20:42:12
Same thing here... and ExtractModuleName... is it
robertshield
2013/11/27 20:28:01
Yes, the GetTargetServices() call is the problem.
rvargas (doing something else)
2013/11/27 23:53:50
Carlos may have an opinion here, but I'd say we co
robertshield
2013/11/29 01:21:26
I believe this is now solved by your observation t
| |
| 212 memcpy(destination, source, bytes); | |
| 213 } else { | |
| 214 const char* from = reinterpret_cast<const char*>(source); | |
| 215 char* to = reinterpret_cast<char*>(destination); | |
| 216 for (size_t i = 0; i < bytes; i++) { | |
| 217 to[i] = from[i]; | |
| 218 } | |
| 219 } | |
| 220 } __except(EXCEPTION_EXECUTE_HANDLER) { | |
| 221 ret = GetExceptionCode(); | |
| 222 } | |
| 223 return ret; | |
| 224 } | |
| 225 | |
| 226 // Hacky code... replace with AllocAndCopyObjectAttributes. | |
| 227 NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object, | |
| 228 wchar_t** out_name, uint32* attributes, | |
| 229 HANDLE* root) { | |
| 230 if (!InitHeap()) | |
| 231 return STATUS_NO_MEMORY; | |
| 232 | |
| 233 DCHECK_NT(out_name); | |
| 234 *out_name = NULL; | |
| 235 NTSTATUS ret = STATUS_UNSUCCESSFUL; | |
| 236 __try { | |
| 237 do { | |
| 238 if (in_object->RootDirectory != static_cast<HANDLE>(0) && !root) | |
| 239 break; | |
| 240 if (NULL == in_object->ObjectName) | |
| 241 break; | |
| 242 if (NULL == in_object->ObjectName->Buffer) | |
| 243 break; | |
| 244 | |
| 245 size_t size = in_object->ObjectName->Length + sizeof(wchar_t); | |
| 246 *out_name = new(NT_ALLOC) wchar_t[size/sizeof(wchar_t)]; | |
| 247 if (NULL == *out_name) | |
| 248 break; | |
| 249 | |
| 250 ret = CopyData(*out_name, in_object->ObjectName->Buffer, | |
| 251 size - sizeof(wchar_t)); | |
| 252 if (!NT_SUCCESS(ret)) | |
| 253 break; | |
| 254 | |
| 255 (*out_name)[size / sizeof(wchar_t) - 1] = L'\0'; | |
| 256 | |
| 257 if (attributes) | |
| 258 *attributes = in_object->Attributes; | |
| 259 | |
| 260 if (root) | |
| 261 *root = in_object->RootDirectory; | |
| 262 ret = STATUS_SUCCESS; | |
| 263 } while (false); | |
| 264 } __except(EXCEPTION_EXECUTE_HANDLER) { | |
| 265 ret = GetExceptionCode(); | |
| 266 } | |
| 267 | |
| 268 if (!NT_SUCCESS(ret) && *out_name) { | |
| 269 operator delete(*out_name, NT_ALLOC); | |
| 270 *out_name = NULL; | |
| 271 } | |
| 272 | |
| 273 return ret; | |
| 274 } | |
| 275 | |
| 276 NTSTATUS GetProcessId(HANDLE process, ULONG *process_id) { | 158 NTSTATUS GetProcessId(HANDLE process, ULONG *process_id) { |
| 277 PROCESS_BASIC_INFORMATION proc_info; | 159 PROCESS_BASIC_INFORMATION proc_info; |
| 278 ULONG bytes_returned; | 160 ULONG bytes_returned; |
| 279 | 161 |
| 280 NTSTATUS ret = g_nt.QueryInformationProcess(process, ProcessBasicInformation, | 162 NTSTATUS ret = g_nt.QueryInformationProcess(process, ProcessBasicInformation, |
| 281 &proc_info, sizeof(proc_info), | 163 &proc_info, sizeof(proc_info), |
| 282 &bytes_returned); | 164 &bytes_returned); |
| 283 if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned) | 165 if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned) |
| 284 return ret; | 166 return ret; |
| 285 | 167 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 424 } | 306 } |
| 425 if (!NT_SUCCESS(ret)) { | 307 if (!NT_SUCCESS(ret)) { |
| 426 operator delete(section_name, NT_ALLOC); | 308 operator delete(section_name, NT_ALLOC); |
| 427 return NULL; | 309 return NULL; |
| 428 } | 310 } |
| 429 | 311 |
| 430 return reinterpret_cast<UNICODE_STRING*>(section_name); | 312 return reinterpret_cast<UNICODE_STRING*>(section_name); |
| 431 } | 313 } |
| 432 } | 314 } |
| 433 | 315 |
| 434 UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path) { | |
| 435 if ((!module_path) || (!module_path->Buffer)) | |
| 436 return NULL; | |
| 437 | |
| 438 wchar_t* sep = NULL; | |
| 439 int start_pos = module_path->Length / sizeof(wchar_t) - 1; | |
| 440 int ix = start_pos; | |
| 441 | |
| 442 for (; ix >= 0; --ix) { | |
| 443 if (module_path->Buffer[ix] == L'\\') { | |
| 444 sep = &module_path->Buffer[ix]; | |
| 445 break; | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 // Ends with path separator. Not a valid module name. | |
| 450 if ((ix == start_pos) && sep) | |
| 451 return NULL; | |
| 452 | |
| 453 // No path separator found. Use the entire name. | |
| 454 if (!sep) { | |
| 455 sep = &module_path->Buffer[-1]; | |
| 456 } | |
| 457 | |
| 458 // Add one to the size so we can null terminate the string. | |
| 459 size_t size_bytes = (start_pos - ix + 1) * sizeof(wchar_t); | |
| 460 | |
| 461 // Based on the code above, size_bytes should always be small enough | |
| 462 // to make the static_cast below safe. | |
| 463 DCHECK_NT(kuint16max > size_bytes); | |
| 464 char* str_buffer = new(NT_ALLOC) char[size_bytes + sizeof(UNICODE_STRING)]; | |
| 465 if (!str_buffer) | |
| 466 return NULL; | |
| 467 | |
| 468 UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(str_buffer); | |
| 469 out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]); | |
| 470 out_string->Length = static_cast<USHORT>(size_bytes - sizeof(wchar_t)); | |
| 471 out_string->MaximumLength = static_cast<USHORT>(size_bytes); | |
| 472 | |
| 473 NTSTATUS ret = CopyData(out_string->Buffer, &sep[1], out_string->Length); | |
| 474 if (!NT_SUCCESS(ret)) { | |
| 475 operator delete(out_string, NT_ALLOC); | |
| 476 return NULL; | |
| 477 } | |
| 478 | |
| 479 out_string->Buffer[out_string->Length / sizeof(wchar_t)] = L'\0'; | |
| 480 return out_string; | |
| 481 } | |
| 482 | |
| 483 NTSTATUS AutoProtectMemory::ChangeProtection(void* address, size_t bytes, | 316 NTSTATUS AutoProtectMemory::ChangeProtection(void* address, size_t bytes, |
| 484 ULONG protect) { | 317 ULONG protect) { |
| 485 DCHECK_NT(!changed_); | 318 DCHECK_NT(!changed_); |
| 486 SIZE_T new_bytes = bytes; | 319 SIZE_T new_bytes = bytes; |
| 487 NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address, | 320 NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address, |
| 488 &new_bytes, protect, &old_protect_); | 321 &new_bytes, protect, &old_protect_); |
| 489 if (NT_SUCCESS(ret)) { | 322 if (NT_SUCCESS(ret)) { |
| 490 changed_ = true; | 323 changed_ = true; |
| 491 address_ = address; | 324 address_ = address; |
| 492 bytes_ = new_bytes; | 325 bytes_ = new_bytes; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 | 372 |
| 540 if (file_info->FileName[0] != L'\\' || | 373 if (file_info->FileName[0] != L'\\' || |
| 541 file_info->FileName[1] != L'?' || | 374 file_info->FileName[1] != L'?' || |
| 542 file_info->FileName[2] != L'?' || | 375 file_info->FileName[2] != L'?' || |
| 543 file_info->FileName[3] != L'\\') | 376 file_info->FileName[3] != L'\\') |
| 544 return false; | 377 return false; |
| 545 | 378 |
| 546 return true; | 379 return true; |
| 547 } | 380 } |
| 548 | 381 |
| 382 bool WriteProtectedChildMemory(HANDLE child_process, void* address, | |
| 383 const void* buffer, size_t length) { | |
| 384 // First, remove the protections. | |
| 385 DWORD old_protection; | |
| 386 if (!::VirtualProtectEx(child_process, address, length, | |
|
rvargas (doing something else)
2013/11/26 20:42:12
This, on the other hand, is not part of the nt lay
robertshield
2013/11/27 20:28:01
Moved it back.
| |
| 387 PAGE_WRITECOPY, &old_protection)) | |
| 388 return false; | |
| 389 | |
| 390 SIZE_T written; | |
| 391 bool ok = ::WriteProcessMemory(child_process, address, buffer, length, | |
| 392 &written) && (length == written); | |
| 393 | |
| 394 // Always attempt to restore the original protection. | |
| 395 if (!::VirtualProtectEx(child_process, address, length, | |
| 396 old_protection, &old_protection)) | |
| 397 return false; | |
| 398 | |
| 399 return ok; | |
| 400 } | |
| 401 | |
| 549 } // namespace sandbox | 402 } // namespace sandbox |
| 550 | 403 |
| 551 void* operator new(size_t size, sandbox::AllocationType type, | 404 void* operator new(size_t size, sandbox::AllocationType type, |
| 552 void* near_to) { | 405 void* near_to) { |
| 553 using namespace sandbox; | 406 using namespace sandbox; |
| 554 | 407 |
| 555 if (NT_ALLOC == type) { | 408 if (NT_ALLOC == type) { |
| 556 if (!InitHeap()) | 409 if (!InitHeap()) |
| 557 return NULL; | 410 return NULL; |
| 558 | 411 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 UNREFERENCED_PARAMETER(type); | 446 UNREFERENCED_PARAMETER(type); |
| 594 return buffer; | 447 return buffer; |
| 595 } | 448 } |
| 596 | 449 |
| 597 void __cdecl operator delete(void* memory, void* buffer, | 450 void __cdecl operator delete(void* memory, void* buffer, |
| 598 sandbox::AllocationType type) { | 451 sandbox::AllocationType type) { |
| 599 UNREFERENCED_PARAMETER(memory); | 452 UNREFERENCED_PARAMETER(memory); |
| 600 UNREFERENCED_PARAMETER(buffer); | 453 UNREFERENCED_PARAMETER(buffer); |
| 601 UNREFERENCED_PARAMETER(type); | 454 UNREFERENCED_PARAMETER(type); |
| 602 } | 455 } |
| OLD | NEW |