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 "content/common/sandbox_win.h" | 5 #include "content/common/sandbox_win.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/base_switches.h" | 9 #include "base/base_switches.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "content/public/common/content_client.h" | 24 #include "content/public/common/content_client.h" |
25 #include "content/public/common/content_switches.h" | 25 #include "content/public/common/content_switches.h" |
26 #include "content/public/common/sandbox_init.h" | 26 #include "content/public/common/sandbox_init.h" |
27 #include "content/public/common/sandboxed_process_launcher_delegate.h" | 27 #include "content/public/common/sandboxed_process_launcher_delegate.h" |
28 #include "sandbox/win/src/process_mitigations.h" | 28 #include "sandbox/win/src/process_mitigations.h" |
29 #include "sandbox/win/src/sandbox.h" | 29 #include "sandbox/win/src/sandbox.h" |
30 #include "sandbox/win/src/sandbox_nt_util.h" | 30 #include "sandbox/win/src/sandbox_nt_util.h" |
31 #include "sandbox/win/src/win_utils.h" | 31 #include "sandbox/win/src/win_utils.h" |
32 #include "ui/gfx/win/dpi.h" | 32 #include "ui/gfx/win/dpi.h" |
33 | 33 |
34 static sandbox::BrokerServices* g_broker_services = NULL; | 34 static sandbox::BrokerServices* g_broker_services = nullptr; |
35 static sandbox::TargetServices* g_target_services = NULL; | 35 static sandbox::TargetServices* g_target_services = nullptr; |
36 | 36 |
37 namespace content { | 37 namespace content { |
38 namespace { | 38 namespace { |
39 | 39 |
40 // The DLLs listed here are known (or under strong suspicion) of causing crashes | 40 // The DLLs listed here are known (or under strong suspicion) of causing crashes |
41 // when they are loaded in the renderer. Note: at runtime we generate short | 41 // when they are loaded in the renderer. Note: at runtime we generate short |
42 // versions of the dll name only if the dll has an extension. | 42 // versions of the dll name only if the dll has an extension. |
43 // For more information about how this list is generated, and how to get off | 43 // For more information about how this list is generated, and how to get off |
44 // of it, see: | 44 // of it, see: |
45 // https://sites.google.com/a/chromium.org/dev/Home/third-party-developers | 45 // https://sites.google.com/a/chromium.org/dev/Home/third-party-developers |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 base::FilePath fname(path); | 176 base::FilePath fname(path); |
177 return (fname.BaseName().value() == module_name); | 177 return (fname.BaseName().value() == module_name); |
178 } | 178 } |
179 | 179 |
180 // Adds a single dll by |module_name| into the |policy| blacklist. | 180 // Adds a single dll by |module_name| into the |policy| blacklist. |
181 // If |check_in_browser| is true we only add an unload policy only if the dll | 181 // If |check_in_browser| is true we only add an unload policy only if the dll |
182 // is also loaded in this process. | 182 // is also loaded in this process. |
183 void BlacklistAddOneDll(const wchar_t* module_name, | 183 void BlacklistAddOneDll(const wchar_t* module_name, |
184 bool check_in_browser, | 184 bool check_in_browser, |
185 sandbox::TargetPolicy* policy) { | 185 sandbox::TargetPolicy* policy) { |
186 HMODULE module = check_in_browser ? ::GetModuleHandleW(module_name) : NULL; | 186 HMODULE module = check_in_browser ? ::GetModuleHandleW(module_name) : nullptr; |
187 if (!module) { | 187 if (!module) { |
188 // The module could have been loaded with a 8.3 short name. We check | 188 // The module could have been loaded with a 8.3 short name. We check |
189 // the three most common cases: 'thelongname.dll' becomes | 189 // the three most common cases: 'thelongname.dll' becomes |
190 // 'thelon~1.dll', 'thelon~2.dll' and 'thelon~3.dll'. | 190 // 'thelon~1.dll', 'thelon~2.dll' and 'thelon~3.dll'. |
191 std::wstring name(module_name); | 191 std::wstring name(module_name); |
192 size_t period = name.rfind(L'.'); | 192 size_t period = name.rfind(L'.'); |
193 DCHECK_NE(std::string::npos, period); | 193 DCHECK_NE(std::string::npos, period); |
194 DCHECK_LE(3U, (name.size() - period)); | 194 DCHECK_LE(3U, (name.size() - period)); |
195 if (period <= 8) | 195 if (period <= 8) |
196 return; | 196 return; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 if (!cmd_line.HasSwitch(switches::kAllowNoSandboxJob)) | 249 if (!cmd_line.HasSwitch(switches::kAllowNoSandboxJob)) |
250 return true; | 250 return true; |
251 | 251 |
252 // Windows 8 allows nested jobs so we don't need to check if we are in other | 252 // Windows 8 allows nested jobs so we don't need to check if we are in other |
253 // job. | 253 // job. |
254 if (base::win::GetVersion() >= base::win::VERSION_WIN8) | 254 if (base::win::GetVersion() >= base::win::VERSION_WIN8) |
255 return true; | 255 return true; |
256 | 256 |
257 BOOL in_job = true; | 257 BOOL in_job = true; |
258 // Either there is no job yet associated so we must add our job, | 258 // Either there is no job yet associated so we must add our job, |
259 if (!::IsProcessInJob(::GetCurrentProcess(), NULL, &in_job)) | 259 if (!::IsProcessInJob(::GetCurrentProcess(), nullptr, &in_job)) |
260 NOTREACHED() << "IsProcessInJob failed. " << GetLastError(); | 260 NOTREACHED() << "IsProcessInJob failed. " << GetLastError(); |
261 if (!in_job) | 261 if (!in_job) |
262 return true; | 262 return true; |
263 | 263 |
264 // ...or there is a job but the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit is set. | 264 // ...or there is a job but the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit is set. |
265 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {0}; | 265 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {0}; |
266 if (!::QueryInformationJobObject(NULL, | 266 if (!::QueryInformationJobObject(nullptr, |
267 JobObjectExtendedLimitInformation, &job_info, | 267 JobObjectExtendedLimitInformation, &job_info, |
268 sizeof(job_info), NULL)) { | 268 sizeof(job_info), nullptr)) { |
269 NOTREACHED() << "QueryInformationJobObject failed. " << GetLastError(); | 269 NOTREACHED() << "QueryInformationJobObject failed. " << GetLastError(); |
270 return true; | 270 return true; |
271 } | 271 } |
272 if (job_info.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK) | 272 if (job_info.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK) |
273 return true; | 273 return true; |
274 | 274 |
275 return false; | 275 return false; |
276 } | 276 } |
277 | 277 |
278 // Adds the generic policy rules to a sandbox TargetPolicy. | 278 // Adds the generic policy rules to a sandbox TargetPolicy. |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 typedef BOOL (WINAPI *DuplicateHandleFunctionPtr)(HANDLE source_process_handle, | 409 typedef BOOL (WINAPI *DuplicateHandleFunctionPtr)(HANDLE source_process_handle, |
410 HANDLE source_handle, | 410 HANDLE source_handle, |
411 HANDLE target_process_handle, | 411 HANDLE target_process_handle, |
412 LPHANDLE target_handle, | 412 LPHANDLE target_handle, |
413 DWORD desired_access, | 413 DWORD desired_access, |
414 BOOL inherit_handle, | 414 BOOL inherit_handle, |
415 DWORD options); | 415 DWORD options); |
416 | 416 |
417 DuplicateHandleFunctionPtr g_iat_orig_duplicate_handle; | 417 DuplicateHandleFunctionPtr g_iat_orig_duplicate_handle; |
418 | 418 |
419 NtQueryObject g_QueryObject = NULL; | 419 NtQueryObject g_QueryObject = nullptr; |
420 | 420 |
421 static const char* kDuplicateHandleWarning = | 421 static const char* kDuplicateHandleWarning = |
422 "You are attempting to duplicate a privileged handle into a sandboxed" | 422 "You are attempting to duplicate a privileged handle into a sandboxed" |
423 " process.\n Please use the sandbox::BrokerDuplicateHandle API or" | 423 " process.\n Please use the sandbox::BrokerDuplicateHandle API or" |
424 " contact security@chromium.org for assistance."; | 424 " contact security@chromium.org for assistance."; |
425 | 425 |
426 void CheckDuplicateHandle(HANDLE handle) { | 426 void CheckDuplicateHandle(HANDLE handle) { |
427 // Get the object type (32 characters is safe; current max is 14). | 427 // Get the object type (32 characters is safe; current max is 14). |
428 BYTE buffer[sizeof(OBJECT_TYPE_INFORMATION) + 32 * sizeof(wchar_t)]; | 428 BYTE buffer[sizeof(OBJECT_TYPE_INFORMATION) + 32 * sizeof(wchar_t)]; |
429 OBJECT_TYPE_INFORMATION* type_info = | 429 OBJECT_TYPE_INFORMATION* type_info = |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 desired_access, inherit_handle, options)) | 465 desired_access, inherit_handle, options)) |
466 return FALSE; | 466 return FALSE; |
467 | 467 |
468 // We're not worried about broker handles or not crossing process boundaries. | 468 // We're not worried about broker handles or not crossing process boundaries. |
469 if (source_process_handle == target_process_handle || | 469 if (source_process_handle == target_process_handle || |
470 target_process_handle == ::GetCurrentProcess()) | 470 target_process_handle == ::GetCurrentProcess()) |
471 return TRUE; | 471 return TRUE; |
472 | 472 |
473 // Only sandboxed children are placed in jobs, so just check them. | 473 // Only sandboxed children are placed in jobs, so just check them. |
474 BOOL is_in_job = FALSE; | 474 BOOL is_in_job = FALSE; |
475 if (!::IsProcessInJob(target_process_handle, NULL, &is_in_job)) { | 475 if (!::IsProcessInJob(target_process_handle, nullptr, &is_in_job)) { |
476 // We need a handle with permission to check the job object. | 476 // We need a handle with permission to check the job object. |
477 if (ERROR_ACCESS_DENIED == ::GetLastError()) { | 477 if (ERROR_ACCESS_DENIED == ::GetLastError()) { |
478 HANDLE temp_handle; | 478 HANDLE temp_handle; |
479 CHECK(g_iat_orig_duplicate_handle(::GetCurrentProcess(), | 479 CHECK(g_iat_orig_duplicate_handle(::GetCurrentProcess(), |
480 target_process_handle, | 480 target_process_handle, |
481 ::GetCurrentProcess(), | 481 ::GetCurrentProcess(), |
482 &temp_handle, | 482 &temp_handle, |
483 PROCESS_QUERY_INFORMATION, | 483 PROCESS_QUERY_INFORMATION, |
484 FALSE, 0)); | 484 FALSE, 0)); |
485 base::win::ScopedHandle process(temp_handle); | 485 base::win::ScopedHandle process(temp_handle); |
486 CHECK(::IsProcessInJob(process.Get(), NULL, &is_in_job)); | 486 CHECK(::IsProcessInJob(process.Get(), nullptr, &is_in_job)); |
487 } | 487 } |
488 } | 488 } |
489 | 489 |
490 if (is_in_job) { | 490 if (is_in_job) { |
491 // We never allow inheritable child handles. | 491 // We never allow inheritable child handles. |
492 CHECK(!inherit_handle) << kDuplicateHandleWarning; | 492 CHECK(!inherit_handle) << kDuplicateHandleWarning; |
493 | 493 |
494 // Duplicate the handle again, to get the final permissions. | 494 // Duplicate the handle again, to get the final permissions. |
495 HANDLE temp_handle; | 495 HANDLE temp_handle; |
496 CHECK(g_iat_orig_duplicate_handle(target_process_handle, *target_handle, | 496 CHECK(g_iat_orig_duplicate_handle(target_process_handle, *target_handle, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 // TODO(abarth): DCHECK(CalledOnValidThread()); | 535 // TODO(abarth): DCHECK(CalledOnValidThread()); |
536 // See <http://b/1287166>. | 536 // See <http://b/1287166>. |
537 DCHECK(broker_services); | 537 DCHECK(broker_services); |
538 DCHECK(!g_broker_services); | 538 DCHECK(!g_broker_services); |
539 sandbox::ResultCode result = broker_services->Init(); | 539 sandbox::ResultCode result = broker_services->Init(); |
540 g_broker_services = broker_services; | 540 g_broker_services = broker_services; |
541 | 541 |
542 // In non-official builds warn about dangerous uses of DuplicateHandle. | 542 // In non-official builds warn about dangerous uses of DuplicateHandle. |
543 #ifndef OFFICIAL_BUILD | 543 #ifndef OFFICIAL_BUILD |
544 BOOL is_in_job = FALSE; | 544 BOOL is_in_job = FALSE; |
545 CHECK(::IsProcessInJob(::GetCurrentProcess(), NULL, &is_in_job)); | 545 CHECK(::IsProcessInJob(::GetCurrentProcess(), nullptr, &is_in_job)); |
546 // In a Syzygy-profiled binary, instrumented for import profiling, this | 546 // In a Syzygy-profiled binary, instrumented for import profiling, this |
547 // patch will end in infinite recursion on the attempted delegation to the | 547 // patch will end in infinite recursion on the attempted delegation to the |
548 // original function. | 548 // original function. |
549 if (!base::debug::IsBinaryInstrumented() && | 549 if (!base::debug::IsBinaryInstrumented() && |
550 !is_in_job && !g_iat_patch_duplicate_handle.is_patched()) { | 550 !is_in_job && !g_iat_patch_duplicate_handle.is_patched()) { |
551 HMODULE module = NULL; | 551 HMODULE module = nullptr; |
552 wchar_t module_name[MAX_PATH]; | 552 wchar_t module_name[MAX_PATH]; |
553 CHECK(::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, | 553 CHECK(::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, |
554 reinterpret_cast<LPCWSTR>(InitBrokerServices), | 554 reinterpret_cast<LPCWSTR>(InitBrokerServices), |
555 &module)); | 555 &module)); |
556 DWORD result = ::GetModuleFileNameW(module, module_name, MAX_PATH); | 556 DWORD result = ::GetModuleFileNameW(module, module_name, MAX_PATH); |
557 if (result && (result != MAX_PATH)) { | 557 if (result && (result != MAX_PATH)) { |
558 ResolveNTFunctionPtr("NtQueryObject", &g_QueryObject); | 558 ResolveNTFunctionPtr("NtQueryObject", &g_QueryObject); |
559 result = g_iat_patch_duplicate_handle.Patch( | 559 result = g_iat_patch_duplicate_handle.Patch( |
560 module_name, "kernel32.dll", "DuplicateHandle", | 560 module_name, "kernel32.dll", "DuplicateHandle", |
561 DuplicateHandlePatch); | 561 DuplicateHandlePatch); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 sandbox::MITIGATION_DEP | | 649 sandbox::MITIGATION_DEP | |
650 sandbox::MITIGATION_DEP_NO_ATL_THUNK | | 650 sandbox::MITIGATION_DEP_NO_ATL_THUNK | |
651 sandbox::MITIGATION_SEHOP; | 651 sandbox::MITIGATION_SEHOP; |
652 | 652 |
653 if (base::win::GetVersion() >= base::win::VERSION_WIN8 && | 653 if (base::win::GetVersion() >= base::win::VERSION_WIN8 && |
654 type_str == switches::kRendererProcess && | 654 type_str == switches::kRendererProcess && |
655 browser_command_line.HasSwitch( | 655 browser_command_line.HasSwitch( |
656 switches::kEnableWin32kRendererLockDown)) { | 656 switches::kEnableWin32kRendererLockDown)) { |
657 if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN, | 657 if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN, |
658 sandbox::TargetPolicy::FAKE_USER_GDI_INIT, | 658 sandbox::TargetPolicy::FAKE_USER_GDI_INIT, |
659 NULL) != sandbox::SBOX_ALL_OK) { | 659 nullptr) != sandbox::SBOX_ALL_OK) { |
660 return 0; | 660 return 0; |
661 } | 661 } |
662 mitigations |= sandbox::MITIGATION_WIN32K_DISABLE; | 662 mitigations |= sandbox::MITIGATION_WIN32K_DISABLE; |
663 } | 663 } |
664 | 664 |
665 if (policy->SetProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK) | 665 if (policy->SetProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK) |
666 return 0; | 666 return 0; |
667 | 667 |
668 mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS | | 668 mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS | |
669 sandbox::MITIGATION_DLL_SEARCH_ORDER; | 669 sandbox::MITIGATION_DLL_SEARCH_ORDER; |
670 | 670 |
671 if (policy->SetDelayedProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK) | 671 if (policy->SetDelayedProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK) |
672 return 0; | 672 return 0; |
673 | 673 |
674 SetJobLevel(*cmd_line, sandbox::JOB_LOCKDOWN, 0, policy); | 674 SetJobLevel(*cmd_line, sandbox::JOB_LOCKDOWN, 0, policy); |
675 | 675 |
676 bool disable_default_policy = false; | 676 bool disable_default_policy = false; |
677 base::FilePath exposed_dir; | 677 base::FilePath exposed_dir; |
678 if (delegate) | 678 if (delegate) |
679 delegate->PreSandbox(&disable_default_policy, &exposed_dir); | 679 delegate->PreSandbox(&disable_default_policy, &exposed_dir); |
680 | 680 |
681 if (!disable_default_policy && !AddPolicyForSandboxedProcess(policy)) | 681 if (!disable_default_policy && !AddPolicyForSandboxedProcess(policy)) |
682 return 0; | 682 return 0; |
683 | 683 |
684 if (type_str == switches::kRendererProcess) { | 684 if (type_str == switches::kRendererProcess) { |
685 if (ShouldUseDirectWrite()) { | 685 if (ShouldUseDirectWrite()) { |
686 AddDirectory(base::DIR_WINDOWS_FONTS, | 686 AddDirectory(base::DIR_WINDOWS_FONTS, |
687 NULL, | 687 nullptr, |
688 true, | 688 true, |
689 sandbox::TargetPolicy::FILES_ALLOW_READONLY, | 689 sandbox::TargetPolicy::FILES_ALLOW_READONLY, |
690 policy); | 690 policy); |
691 } | 691 } |
692 } else { | 692 } else { |
693 // Hack for Google Desktop crash. Trick GD into not injecting its DLL into | 693 // Hack for Google Desktop crash. Trick GD into not injecting its DLL into |
694 // this subprocess. See | 694 // this subprocess. See |
695 // http://code.google.com/p/chromium/issues/detail?id=25580 | 695 // http://code.google.com/p/chromium/issues/detail?id=25580 |
696 cmd_line->AppendSwitchASCII("ignored", " --type=renderer "); | 696 cmd_line->AppendSwitchASCII("ignored", " --type=renderer "); |
697 } | 697 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 } | 791 } |
792 | 792 |
793 return false; | 793 return false; |
794 } | 794 } |
795 | 795 |
796 bool BrokerAddTargetPeer(HANDLE peer_process) { | 796 bool BrokerAddTargetPeer(HANDLE peer_process) { |
797 return g_broker_services->AddTargetPeer(peer_process) == sandbox::SBOX_ALL_OK; | 797 return g_broker_services->AddTargetPeer(peer_process) == sandbox::SBOX_ALL_OK; |
798 } | 798 } |
799 | 799 |
800 } // namespace content | 800 } // namespace content |
OLD | NEW |