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 |