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 |
11 namespace sandbox { | 11 namespace sandbox { |
12 | 12 |
13 // This is the list of all imported symbols from ntdll.dll. | 13 // This is the list of all imported symbols from ntdll.dll. |
14 SANDBOX_INTERCEPT NtExports g_nt = { NULL }; | 14 SANDBOX_INTERCEPT NtExports g_nt; |
15 | 15 |
16 } // namespace sandbox | 16 } // namespace sandbox |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 #if defined(_WIN64) | 20 #if defined(_WIN64) |
21 void* AllocateNearTo(void* source, size_t size) { | 21 void* AllocateNearTo(void* source, size_t size) { |
22 using sandbox::g_nt; | 22 using sandbox::g_nt; |
23 | 23 |
24 // Start with 1 GB above the source. | 24 // Start with 1 GB above the source. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 if (!NT_SUCCESS(ret)) | 97 if (!NT_SUCCESS(ret)) |
98 return NULL; | 98 return NULL; |
99 return base; | 99 return base; |
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 // This is the list of all imported symbols from ntdll.dll. |
108 void* g_heap = NULL; | 108 SANDBOX_INTERCEPT NtExports g_nt; |
rvargas (doing something else)
2013/11/27 23:53:51
This is already defined up there
robertshield
2013/11/29 01:21:26
Done.
| |
109 | 109 |
110 SANDBOX_INTERCEPT HANDLE g_shared_section; | 110 SANDBOX_INTERCEPT HANDLE g_shared_section; |
111 SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0; | 111 SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0; |
112 SANDBOX_INTERCEPT size_t g_shared_policy_size = 0; | 112 SANDBOX_INTERCEPT size_t g_shared_policy_size = 0; |
113 | 113 |
114 void* volatile g_shared_policy_memory = NULL; | 114 void* volatile g_shared_policy_memory = NULL; |
115 void* volatile g_shared_IPC_memory = NULL; | 115 void* volatile g_shared_IPC_memory = NULL; |
116 | 116 |
117 // Both the IPC and the policy share a single region of memory in which the IPC | 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. | 118 // memory is first and the policy memory is last. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
150 return NULL; | 150 return NULL; |
151 return g_shared_IPC_memory; | 151 return g_shared_IPC_memory; |
152 } | 152 } |
153 | 153 |
154 void* GetGlobalPolicyMemory() { | 154 void* GetGlobalPolicyMemory() { |
155 if (!MapGlobalMemory()) | 155 if (!MapGlobalMemory()) |
156 return NULL; | 156 return NULL; |
157 return g_shared_policy_memory; | 157 return g_shared_policy_memory; |
158 } | 158 } |
159 | 159 |
160 // Handle for our private heap. | |
161 void* g_heap = NULL; | |
rvargas (doing something else)
2013/11/27 23:53:51
don't move this to the middle of the file. The com
robertshield
2013/11/29 01:21:26
Done.
| |
162 | |
160 bool InitHeap() { | 163 bool InitHeap() { |
161 if (!g_heap) { | 164 if (!g_heap) { |
162 // Create a new heap using default values for everything. | 165 // Create a new heap using default values for everything. |
163 void* heap = g_nt.RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL); | 166 void* heap = g_nt.RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL); |
164 if (!heap) | 167 if (!heap) |
165 return false; | 168 return false; |
166 | 169 |
167 if (NULL != _InterlockedCompareExchangePointer(&g_heap, heap, NULL)) { | 170 if (NULL != _InterlockedCompareExchangePointer(&g_heap, heap, NULL)) { |
168 // Somebody beat us to the memory setup. | 171 // Somebody beat us to the memory setup. |
169 g_nt.RtlDestroyHeap(heap); | 172 g_nt.RtlDestroyHeap(heap); |
(...skipping 28 matching lines...) Expand all Loading... | |
198 bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) { | 201 bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) { |
199 DCHECK_NT(size); | 202 DCHECK_NT(size); |
200 __try { | 203 __try { |
201 TouchMemory(buffer, size, intent); | 204 TouchMemory(buffer, size, intent); |
202 } __except(EXCEPTION_EXECUTE_HANDLER) { | 205 } __except(EXCEPTION_EXECUTE_HANDLER) { |
203 return false; | 206 return false; |
204 } | 207 } |
205 return true; | 208 return true; |
206 } | 209 } |
207 | 210 |
208 NTSTATUS CopyData(void* destination, const void* source, size_t bytes) { | |
rvargas (doing something else)
2013/11/27 23:53:51
I presume this is being moved to nt_util_base. I h
rvargas (doing something else)
2013/11/27 23:53:51
After looking at the whole patch I see that interc
rvargas (doing something else)
2013/11/27 23:58:52
There is nt!memcpy (at least on Win7 but i expect
robertshield
2013/11/29 01:21:26
Done.
robertshield
2013/11/29 01:21:26
Done.
robertshield
2013/11/29 01:21:26
And this solves all known problems. Using nt's mem
| |
209 NTSTATUS ret = STATUS_SUCCESS; | |
210 __try { | |
211 if (SandboxFactory::GetTargetServices()->GetState()->InitCalled()) { | |
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) { | 211 NTSTATUS GetProcessId(HANDLE process, ULONG *process_id) { |
277 PROCESS_BASIC_INFORMATION proc_info; | 212 PROCESS_BASIC_INFORMATION proc_info; |
278 ULONG bytes_returned; | 213 ULONG bytes_returned; |
279 | 214 |
280 NTSTATUS ret = g_nt.QueryInformationProcess(process, ProcessBasicInformation, | 215 NTSTATUS ret = g_nt.QueryInformationProcess(process, ProcessBasicInformation, |
281 &proc_info, sizeof(proc_info), | 216 &proc_info, sizeof(proc_info), |
282 &bytes_returned); | 217 &bytes_returned); |
283 if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned) | 218 if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned) |
284 return ret; | 219 return ret; |
285 | 220 |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
424 } | 359 } |
425 if (!NT_SUCCESS(ret)) { | 360 if (!NT_SUCCESS(ret)) { |
426 operator delete(section_name, NT_ALLOC); | 361 operator delete(section_name, NT_ALLOC); |
427 return NULL; | 362 return NULL; |
428 } | 363 } |
429 | 364 |
430 return reinterpret_cast<UNICODE_STRING*>(section_name); | 365 return reinterpret_cast<UNICODE_STRING*>(section_name); |
431 } | 366 } |
432 } | 367 } |
433 | 368 |
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, | 369 NTSTATUS AutoProtectMemory::ChangeProtection(void* address, size_t bytes, |
484 ULONG protect) { | 370 ULONG protect) { |
485 DCHECK_NT(!changed_); | 371 DCHECK_NT(!changed_); |
486 SIZE_T new_bytes = bytes; | 372 SIZE_T new_bytes = bytes; |
487 NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address, | 373 NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address, |
488 &new_bytes, protect, &old_protect_); | 374 &new_bytes, protect, &old_protect_); |
489 if (NT_SUCCESS(ret)) { | 375 if (NT_SUCCESS(ret)) { |
490 changed_ = true; | 376 changed_ = true; |
491 address_ = address; | 377 address_ = address; |
492 bytes_ = new_bytes; | 378 bytes_ = new_bytes; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
593 UNREFERENCED_PARAMETER(type); | 479 UNREFERENCED_PARAMETER(type); |
594 return buffer; | 480 return buffer; |
595 } | 481 } |
596 | 482 |
597 void __cdecl operator delete(void* memory, void* buffer, | 483 void __cdecl operator delete(void* memory, void* buffer, |
598 sandbox::AllocationType type) { | 484 sandbox::AllocationType type) { |
599 UNREFERENCED_PARAMETER(memory); | 485 UNREFERENCED_PARAMETER(memory); |
600 UNREFERENCED_PARAMETER(buffer); | 486 UNREFERENCED_PARAMETER(buffer); |
601 UNREFERENCED_PARAMETER(type); | 487 UNREFERENCED_PARAMETER(type); |
602 } | 488 } |
OLD | NEW |