1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/common/sandbox_policy.h" 6 7#include <string> 8 9#include "base/command_line.h" 10#include "base/debug/debugger.h" 11#include "base/debug/trace_event.h" 12#include "base/file_util.h" 13#include "base/logging.h" 14#include "base/path_service.h" 15#include "base/process_util.h" 16#include "base/stringprintf.h" 17#include "base/string_number_conversions.h" 18#include "base/string_util.h" 19#include "base/win/windows_version.h" 20#include "chrome/common/chrome_constants.h" 21#include "chrome/common/chrome_paths.h" 22#include "chrome/common/chrome_switches.h" 23#include "content/common/child_process_info.h" 24#include "content/common/debug_flags.h" 25#include "sandbox/src/sandbox.h" 26 27static sandbox::BrokerServices* g_broker_services = NULL; 28 29namespace { 30 31// The DLLs listed here are known (or under strong suspicion) of causing crashes 32// when they are loaded in the renderer. Note: at runtime we generate short 33// versions of the dll name only if the dll has an extension. 34const wchar_t* const kTroublesomeDlls[] = { 35 L"adialhk.dll", // Kaspersky Internet Security. 36 L"acpiz.dll", // Unknown. 37 L"avgrsstx.dll", // AVG 8. 38 L"babylonchromepi.dll", // Babylon translator. 39 L"btkeyind.dll", // Widcomm Bluetooth. 40 L"cmcsyshk.dll", // CMC Internet Security. 41 L"cooliris.dll", // CoolIris. 42 L"dockshellhook.dll", // Stardock Objectdock. 43 L"googledesktopnetwork3.dll", // Google Desktop Search v5. 44 L"fwhook.dll", // PC Tools Firewall Plus. 45 L"hookprocesscreation.dll", // Blumentals Program protector. 46 L"hookterminateapis.dll", // Blumentals and Cyberprinter. 47 L"hookprintapis.dll", // Cyberprinter. 48 L"imon.dll", // NOD32 Antivirus. 49 L"ioloHL.dll", // Iolo (System Mechanic). 50 L"kloehk.dll", // Kaspersky Internet Security. 51 L"lawenforcer.dll", // Spyware-Browser AntiSpyware (Spybro). 52 L"libdivx.dll", // DivX. 53 L"lvprcinj01.dll", // Logitech QuickCam. 54 L"madchook.dll", // Madshi (generic hooking library). 55 L"mdnsnsp.dll", // Bonjour. 56 L"moonsysh.dll", // Moon Secure Antivirus. 57 L"npdivx32.dll", // DivX. 58 L"npggNT.des", // GameGuard 2008. 59 L"npggNT.dll", // GameGuard (older). 60 L"oawatch.dll", // Online Armor. 61 L"pavhook.dll", // Panda Internet Security. 62 L"pavshook.dll", // Panda Antivirus. 63 L"pavshookwow.dll", // Panda Antivirus. 64 L"pctavhook.dll", // PC Tools Antivirus. 65 L"pctgmhk.dll", // PC Tools Spyware Doctor. 66 L"prntrack.dll", // Pharos Systems. 67 L"radhslib.dll", // Radiant Naomi Internet Filter. 68 L"radprlib.dll", // Radiant Naomi Internet Filter. 69 L"rapportnikko.dll", // Trustware Rapport. 70 L"rlhook.dll", // Trustware Bufferzone. 71 L"rooksdol.dll", // Trustware Rapport. 72 L"rpchromebrowserrecordhelper.dll", // RealPlayer. 73 L"rpmainbrowserrecordplugin.dll", // RealPlayer. 74 L"r3hook.dll", // Kaspersky Internet Security. 75 L"sahook.dll", // McAfee Site Advisor. 76 L"sbrige.dll", // Unknown. 77 L"sc2hook.dll", // Supercopier 2. 78 L"sguard.dll", // Iolo (System Guard). 79 L"smum32.dll", // Spyware Doctor version 6. 80 L"smumhook.dll", // Spyware Doctor version 5. 81 L"ssldivx.dll", // DivX. 82 L"syncor11.dll", // SynthCore Midi interface. 83 L"systools.dll", // Panda Antivirus. 84 L"tfwah.dll", // Threatfire (PC tools). 85 L"ycwebcamerasource.ax", // Cyberlink Camera helper. 86 L"wblind.dll", // Stardock Object desktop. 87 L"wbhelp.dll", // Stardock Object desktop. 88 L"winstylerthemehelper.dll" // Tuneup utilities 2006. 89}; 90 91enum PluginPolicyCategory { 92 PLUGIN_GROUP_TRUSTED, 93 PLUGIN_GROUP_UNTRUSTED, 94}; 95 96// Returns the policy category for the plugin dll. 97PluginPolicyCategory GetPolicyCategoryForPlugin( 98 const std::wstring& dll, 99 const std::wstring& list) { 100 std::wstring filename = FilePath(dll).BaseName().value(); 101 std::wstring plugin_dll = StringToLowerASCII(filename); 102 std::wstring trusted_plugins = StringToLowerASCII(list); 103 104 size_t pos = 0; 105 size_t end_item = 0; 106 while (end_item != std::wstring::npos) { 107 end_item = list.find(L",", pos); 108 109 size_t size_item = (end_item == std::wstring::npos) ? end_item : 110 end_item - pos; 111 std::wstring item = list.substr(pos, size_item); 112 if (!item.empty() && item == plugin_dll) 113 return PLUGIN_GROUP_TRUSTED; 114 115 pos = end_item + 1; 116 } 117 118 return PLUGIN_GROUP_UNTRUSTED; 119} 120 121// Adds the policy rules for the path and path\ with the semantic |access|. 122// If |children| is set to true, we need to add the wildcard rules to also 123// apply the rule to the subfiles and subfolders. 124bool AddDirectory(int path, const wchar_t* sub_dir, bool children, 125 sandbox::TargetPolicy::Semantics access, 126 sandbox::TargetPolicy* policy) { 127 FilePath directory; 128 if (!PathService::Get(path, &directory)) 129 return false; 130 131 if (sub_dir) { 132 directory = directory.Append(sub_dir); 133 file_util::AbsolutePath(&directory); 134 } 135 136 sandbox::ResultCode result; 137 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access, 138 directory.value().c_str()); 139 if (result != sandbox::SBOX_ALL_OK) 140 return false; 141 142 std::wstring directory_str = directory.value() + L"\\"; 143 if (children) 144 directory_str += L"*"; 145 // Otherwise, add the version of the path that ends with a separator. 146 147 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access, 148 directory_str.c_str()); 149 if (result != sandbox::SBOX_ALL_OK) 150 return false; 151 152 return true; 153} 154 155// Adds the policy rules for the path and path\* with the semantic |access|. 156// We need to add the wildcard rules to also apply the rule to the subkeys. 157bool AddKeyAndSubkeys(std::wstring key, 158 sandbox::TargetPolicy::Semantics access, 159 sandbox::TargetPolicy* policy) { 160 sandbox::ResultCode result; 161 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, access, 162 key.c_str()); 163 if (result != sandbox::SBOX_ALL_OK) 164 return false; 165 166 key += L"\\*"; 167 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, access, 168 key.c_str()); 169 if (result != sandbox::SBOX_ALL_OK) 170 return false; 171 172 return true; 173} 174 175// Compares the loaded |module| file name matches |module_name|. 176bool IsExpandedModuleName(HMODULE module, const wchar_t* module_name) { 177 wchar_t path[MAX_PATH]; 178 DWORD sz = ::GetModuleFileNameW(module, path, arraysize(path)); 179 if ((sz == arraysize(path)) || (sz == 0)) { 180 // XP does not set the last error properly, so we bail out anyway. 181 return false; 182 } 183 if (!::GetLongPathName(path, path, arraysize(path))) 184 return false; 185 FilePath fname(path); 186 return (fname.BaseName().value() == module_name); 187} 188 189// Adds a single dll by |module_name| into the |policy| blacklist. 190// To minimize the list we only add an unload policy only if the dll is 191// also loaded in this process. All the injected dlls of interest do this. 192void BlacklistAddOneDll(const wchar_t* module_name, 193 sandbox::TargetPolicy* policy) { 194 HMODULE module = ::GetModuleHandleW(module_name); 195 if (!module) { 196 // The module could have been loaded with a 8.3 short name. We use 197 // the most common case: 'thelongname.dll' becomes 'thelon~1.dll'. 198 std::wstring name(module_name); 199 size_t period = name.rfind(L'.'); 200 DCHECK_NE(std::string::npos, period); 201 DCHECK_LE(3U, (name.size() - period)); 202 if (period <= 8) 203 return; 204 std::wstring alt_name = name.substr(0, 6) + L"~1"; 205 alt_name += name.substr(period, name.size()); 206 module = ::GetModuleHandleW(alt_name.c_str()); 207 if (!module) 208 return; 209 // We found it, but because it only has 6 significant letters, we 210 // want to make sure it is the right one. 211 if (!IsExpandedModuleName(module, module_name)) 212 return; 213 // Found a match. We add both forms to the policy. 214 policy->AddDllToUnload(alt_name.c_str()); 215 } 216 policy->AddDllToUnload(module_name); 217 VLOG(1) << "dll to unload found: " << module_name; 218 return; 219} 220 221// Adds policy rules for unloaded the known dlls that cause chrome to crash. 222// Eviction of injected DLLs is done by the sandbox so that the injected module 223// does not get a chance to execute any code. 224void AddDllEvictionPolicy(sandbox::TargetPolicy* policy) { 225 for (int ix = 0; ix != arraysize(kTroublesomeDlls); ++ix) 226 BlacklistAddOneDll(kTroublesomeDlls[ix], policy); 227} 228 229// Adds the generic policy rules to a sandbox TargetPolicy. 230bool AddGenericPolicy(sandbox::TargetPolicy* policy) { 231 sandbox::ResultCode result; 232 233 // Add the policy for the pipes 234 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, 235 sandbox::TargetPolicy::FILES_ALLOW_ANY, 236 L"\\??\\pipe\\chrome.*"); 237 if (result != sandbox::SBOX_ALL_OK) 238 return false; 239 240 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, 241 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, 242 L"\\\\.\\pipe\\chrome.nacl.*"); 243 if (result != sandbox::SBOX_ALL_OK) 244 return false; 245 246 // Add the policy for debug message only in debug 247#ifndef NDEBUG 248 FilePath app_dir; 249 if (!PathService::Get(chrome::DIR_APP, &app_dir)) 250 return false; 251 252 wchar_t long_path_buf[MAX_PATH]; 253 DWORD long_path_return_value = GetLongPathName(app_dir.value().c_str(), 254 long_path_buf, 255 MAX_PATH); 256 if (long_path_return_value == 0 || long_path_return_value >= MAX_PATH) 257 return false; 258 259 string16 debug_message(long_path_buf); 260 file_util::AppendToPath(&debug_message, L"debug_message.exe"); 261 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS, 262 sandbox::TargetPolicy::PROCESS_MIN_EXEC, 263 debug_message.c_str()); 264 if (result != sandbox::SBOX_ALL_OK) 265 return false; 266#endif // NDEBUG 267 268 return true; 269} 270 271// Creates a sandbox without any restriction. 272bool ApplyPolicyForTrustedPlugin(sandbox::TargetPolicy* policy) { 273 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0); 274 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED); 275 return true; 276} 277 278// Creates a sandbox with the plugin running in a restricted environment. 279// Only the "Users" and "Everyone" groups are enabled in the token. The User SID 280// is disabled. 281bool ApplyPolicyForUntrustedPlugin(sandbox::TargetPolicy* policy) { 282 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0); 283 284 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED; 285 if (base::win::GetVersion() > base::win::VERSION_XP) { 286 // On 2003/Vista the initial token has to be restricted if the main token 287 // is restricted. 288 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS; 289 } 290 policy->SetTokenLevel(initial_token, sandbox::USER_LIMITED); 291 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 292 293 if (!AddDirectory(base::DIR_TEMP, NULL, true, 294 sandbox::TargetPolicy::FILES_ALLOW_ANY, policy)) 295 return false; 296 297 if (!AddDirectory(base::DIR_IE_INTERNET_CACHE, NULL, true, 298 sandbox::TargetPolicy::FILES_ALLOW_ANY, policy)) 299 return false; 300 301 if (!AddDirectory(base::DIR_APP_DATA, NULL, true, 302 sandbox::TargetPolicy::FILES_ALLOW_READONLY, 303 policy)) 304 return false; 305 306 if (!AddDirectory(base::DIR_PROFILE, NULL, false, /*not recursive*/ 307 sandbox::TargetPolicy::FILES_ALLOW_READONLY, 308 policy)) 309 return false; 310 311 if (!AddDirectory(base::DIR_APP_DATA, L"Adobe", true, 312 sandbox::TargetPolicy::FILES_ALLOW_ANY, 313 policy)) 314 return false; 315 316 if (!AddDirectory(base::DIR_APP_DATA, L"Macromedia", true, 317 sandbox::TargetPolicy::FILES_ALLOW_ANY, 318 policy)) 319 return false; 320 321 if (!AddDirectory(base::DIR_LOCAL_APP_DATA, NULL, true, 322 sandbox::TargetPolicy::FILES_ALLOW_READONLY, 323 policy)) 324 return false; 325 326 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\ADOBE", 327 sandbox::TargetPolicy::REG_ALLOW_ANY, 328 policy)) 329 return false; 330 331 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\MACROMEDIA", 332 sandbox::TargetPolicy::REG_ALLOW_ANY, 333 policy)) 334 return false; 335 336 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 337 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\AppDataLow", 338 sandbox::TargetPolicy::REG_ALLOW_ANY, 339 policy)) 340 return false; 341 342 if (!AddDirectory(base::DIR_LOCAL_APP_DATA_LOW, NULL, true, 343 sandbox::TargetPolicy::FILES_ALLOW_ANY, 344 policy)) 345 return false; 346 347 // DIR_APP_DATA is AppData\Roaming, but Adobe needs to do a directory 348 // listing in AppData directly, so we add a non-recursive policy for 349 // AppData itself. 350 if (!AddDirectory(base::DIR_APP_DATA, L"..", false, 351 sandbox::TargetPolicy::FILES_ALLOW_READONLY, 352 policy)) 353 return false; 354 } 355 356 return true; 357} 358 359// Launches the privileged flash broker, used when flash is sandboxed. 360// The broker is the same flash dll, except that it uses a different 361// entrypoint (BrokerMain) and it is hosted in windows' generic surrogate 362// process rundll32. After launching the broker we need to pass to 363// the flash plugin the process id of the broker via the command line 364// using --flash-broker=pid. 365// More info about rundll32 at http://support.microsoft.com/kb/164787. 366bool LoadFlashBroker(const FilePath& plugin_path, CommandLine* cmd_line) { 367 FilePath rundll; 368 if (!PathService::Get(base::DIR_SYSTEM, &rundll)) 369 return false; 370 rundll = rundll.AppendASCII("rundll32.exe"); 371 // Rundll32 cannot handle paths with spaces, so we use the short path. 372 wchar_t short_path[MAX_PATH]; 373 if (0 == ::GetShortPathNameW(plugin_path.value().c_str(), 374 short_path, arraysize(short_path))) 375 return false; 376 // Here is the kicker, if the user has disabled 8.3 (short path) support 377 // on the volume GetShortPathNameW does not fail but simply returns the 378 // input path. In this case if the path had any spaces then rundll32 will 379 // incorrectly interpret its parameters. So we quote the path, even though 380 // the kb/164787 says you should not. 381 std::wstring cmd_final = 382 base::StringPrintf(L"%ls \"%ls\",BrokerMain browser=chrome", 383 rundll.value().c_str(), 384 short_path); 385 base::ProcessHandle process; 386 if (!base::LaunchApp(cmd_final, false, true, &process)) 387 return false; 388 389 cmd_line->AppendSwitchASCII("flash-broker", 390 base::Int64ToString(::GetProcessId(process))); 391 392 // The flash broker, unders some circumstances can linger beyond the lifetime 393 // of the flash player, so we put it in a job object, when the browser 394 // terminates the job object is destroyed (by the OS) and the flash broker 395 // is terminated. 396 HANDLE job = ::CreateJobObjectW(NULL, NULL); 397 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limits = {0}; 398 job_limits.BasicLimitInformation.LimitFlags = 399 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 400 if (::SetInformationJobObject(job, JobObjectExtendedLimitInformation, 401 &job_limits, sizeof(job_limits))) { 402 ::AssignProcessToJobObject(job, process); 403 // Yes, we are leaking the object here. Read comment above. 404 } else { 405 ::CloseHandle(job); 406 return false; 407 } 408 409 ::CloseHandle(process); 410 return true; 411} 412 413// Creates a sandbox for the built-in flash plugin running in a restricted 414// environment. This policy is in continual flux as flash changes 415// capabilities. For more information see bug 50796. 416bool ApplyPolicyForBuiltInFlashPlugin(sandbox::TargetPolicy* policy) { 417 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0); 418 // Vista and Win7 get a weaker token but have low integrity. 419 if (base::win::GetVersion() > base::win::VERSION_XP) { 420 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, 421 sandbox::USER_INTERACTIVE); 422 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 423 } else { 424 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, 425 sandbox::USER_LIMITED); 426 427 if (!AddKeyAndSubkeys(L"HKEY_LOCAL_MACHINE\\SOFTWARE", 428 sandbox::TargetPolicy::REG_ALLOW_READONLY, 429 policy)) 430 return false; 431 if (!AddKeyAndSubkeys(L"HKEY_LOCAL_MACHINE\\SYSTEM", 432 sandbox::TargetPolicy::REG_ALLOW_READONLY, 433 policy)) 434 return false; 435 436 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE", 437 sandbox::TargetPolicy::REG_ALLOW_READONLY, 438 policy)) 439 return false; 440 } 441 442 AddDllEvictionPolicy(policy); 443 return true; 444} 445 446// Returns true of the plugin specified in |cmd_line| is the built-in 447// flash plugin and optionally returns its full path in |flash_path| 448bool IsBuiltInFlash(const CommandLine* cmd_line, FilePath* flash_path) { 449 std::wstring plugin_dll = cmd_line-> 450 GetSwitchValueNative(switches::kPluginPath); 451 452 FilePath builtin_flash; 453 if (!PathService::Get(chrome::FILE_FLASH_PLUGIN, &builtin_flash)) 454 return false; 455 456 FilePath plugin_path(plugin_dll); 457 if (plugin_path != builtin_flash) 458 return false; 459 460 if (flash_path) 461 *flash_path = plugin_path; 462 return true; 463} 464 465 466// Adds the custom policy rules for a given plugin. |trusted_plugins| contains 467// the comma separate list of plugin dll names that should not be sandboxed. 468bool AddPolicyForPlugin(CommandLine* cmd_line, 469 sandbox::TargetPolicy* policy) { 470 std::wstring plugin_dll = cmd_line-> 471 GetSwitchValueNative(switches::kPluginPath); 472 std::wstring trusted_plugins = CommandLine::ForCurrentProcess()-> 473 GetSwitchValueNative(switches::kTrustedPlugins); 474 // Add the policy for the pipes. 475 sandbox::ResultCode result = sandbox::SBOX_ALL_OK; 476 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, 477 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, 478 L"\\\\.\\pipe\\chrome.*"); 479 if (result != sandbox::SBOX_ALL_OK) { 480 NOTREACHED(); 481 return false; 482 } 483 484 // The built-in flash gets a custom, more restricted sandbox. 485 FilePath flash_path; 486 if (IsBuiltInFlash(cmd_line, &flash_path)) { 487 // Spawn the flash broker and apply sandbox policy. 488 if (!LoadFlashBroker(flash_path, cmd_line)) { 489 // Could not start the broker, use a very weak policy instead. 490 DLOG(WARNING) << "Failed to start flash broker"; 491 return ApplyPolicyForTrustedPlugin(policy); 492 } 493 return ApplyPolicyForBuiltInFlashPlugin(policy); 494 } 495 496 PluginPolicyCategory policy_category = 497 GetPolicyCategoryForPlugin(plugin_dll, trusted_plugins); 498 499 switch (policy_category) { 500 case PLUGIN_GROUP_TRUSTED: 501 return ApplyPolicyForTrustedPlugin(policy); 502 case PLUGIN_GROUP_UNTRUSTED: 503 return ApplyPolicyForUntrustedPlugin(policy); 504 default: 505 NOTREACHED(); 506 break; 507 } 508 509 return false; 510} 511 512// For the GPU process we gotten as far as USER_LIMITED. The next level 513// which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL 514// backend. Note that the GPU process is connected to the interactive 515// desktop. 516// TODO(cpu): Lock down the sandbox more if possible. 517// TODO(apatrick): Use D3D9Ex to render windowless. 518bool AddPolicyForGPU(CommandLine*, sandbox::TargetPolicy* policy) { 519 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0); 520 521 if (base::win::GetVersion() > base::win::VERSION_XP) { 522 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, 523 sandbox::USER_LIMITED); 524 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 525 } else { 526 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, 527 sandbox::USER_LIMITED); 528 } 529 530 AddDllEvictionPolicy(policy); 531 return true; 532} 533 534void AddPolicyForRenderer(sandbox::TargetPolicy* policy, 535 bool* on_sandbox_desktop) { 536 policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0); 537 538 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED; 539 if (base::win::GetVersion() > base::win::VERSION_XP) { 540 // On 2003/Vista the initial token has to be restricted if the main 541 // token is restricted. 542 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS; 543 } 544 545 policy->SetTokenLevel(initial_token, sandbox::USER_LOCKDOWN); 546 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 547 548 bool use_winsta = !CommandLine::ForCurrentProcess()->HasSwitch( 549 switches::kDisableAltWinstation); 550 551 if (sandbox::SBOX_ALL_OK == policy->SetAlternateDesktop(use_winsta)) { 552 *on_sandbox_desktop = true; 553 } else { 554 *on_sandbox_desktop = false; 555 DLOG(WARNING) << "Failed to apply desktop security to the renderer"; 556 } 557 558 AddDllEvictionPolicy(policy); 559} 560 561} // namespace 562 563namespace sandbox { 564 565void InitBrokerServices(sandbox::BrokerServices* broker_services) { 566 // TODO(abarth): DCHECK(CalledOnValidThread()); 567 // See <http://b/1287166>. 568 CHECK(broker_services); 569 CHECK(!g_broker_services); 570 broker_services->Init(); 571 g_broker_services = broker_services; 572} 573 574base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, 575 const FilePath& exposed_dir) { 576 base::ProcessHandle process = 0; 577 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 578 ChildProcessInfo::ProcessType type; 579 std::string type_str = cmd_line->GetSwitchValueASCII(switches::kProcessType); 580 if (type_str == switches::kRendererProcess) { 581 type = ChildProcessInfo::RENDER_PROCESS; 582 } else if (type_str == switches::kExtensionProcess) { 583 // Extensions are just renderers with another name. 584 type = ChildProcessInfo::RENDER_PROCESS; 585 } else if (type_str == switches::kPluginProcess) { 586 type = ChildProcessInfo::PLUGIN_PROCESS; 587 } else if (type_str == switches::kWorkerProcess) { 588 type = ChildProcessInfo::WORKER_PROCESS; 589 } else if (type_str == switches::kNaClLoaderProcess) { 590 type = ChildProcessInfo::NACL_LOADER_PROCESS; 591 } else if (type_str == switches::kUtilityProcess) { 592 type = ChildProcessInfo::UTILITY_PROCESS; 593 } else if (type_str == switches::kNaClBrokerProcess) { 594 type = ChildProcessInfo::NACL_BROKER_PROCESS; 595 } else if (type_str == switches::kGpuProcess) { 596 type = ChildProcessInfo::GPU_PROCESS; 597 } else if (type_str == switches::kPpapiPluginProcess) { 598 type = ChildProcessInfo::PPAPI_PLUGIN_PROCESS; 599 } else { 600 NOTREACHED(); 601 return 0; 602 } 603 604 TRACE_EVENT_BEGIN("StartProcessWithAccess", 0, type_str); 605 606 // To decide if the process is going to be sandboxed we have two cases. 607 // First case: all process types except the nacl broker, and the plugin 608 // process are sandboxed by default. 609 bool in_sandbox = 610 (type != ChildProcessInfo::NACL_BROKER_PROCESS) && 611 (type != ChildProcessInfo::PLUGIN_PROCESS); 612 613 // Second case: If it is the plugin process then it depends on it being 614 // the built-in flash, the user forcing plugins into sandbox or the 615 // the user explicitly excluding flash from the sandbox. 616 if (!in_sandbox && (type == ChildProcessInfo::PLUGIN_PROCESS)) { 617 in_sandbox = browser_command_line.HasSwitch(switches::kSafePlugins) || 618 (IsBuiltInFlash(cmd_line, NULL) && 619 (base::win::GetVersion() > base::win::VERSION_XP) && 620 !browser_command_line.HasSwitch(switches::kDisableFlashSandbox)); 621 } 622 623 // Third case: If it is the GPU process then it can be disabled by a 624 // command line flag. 625 if ((type == ChildProcessInfo::GPU_PROCESS) && 626 (browser_command_line.HasSwitch(switches::kDisableGpuSandbox))) { 627 in_sandbox = false; 628 VLOG(1) << "GPU sandbox is disabled"; 629 } 630 631 if (browser_command_line.HasSwitch(switches::kNoSandbox)) { 632 // The user has explicity opted-out from all sandboxing. 633 in_sandbox = false; 634 } 635 636#if !defined (GOOGLE_CHROME_BUILD) 637 if (browser_command_line.HasSwitch(switches::kInProcessPlugins)) { 638 // In process plugins won't work if the sandbox is enabled. 639 in_sandbox = false; 640 } 641#endif 642 if (!browser_command_line.HasSwitch(switches::kDisable3DAPIs) && 643 !browser_command_line.HasSwitch(switches::kDisableExperimentalWebGL) && 644 browser_command_line.HasSwitch(switches::kInProcessWebGL)) { 645 // In process WebGL won't work if the sandbox is enabled. 646 in_sandbox = false; 647 } 648 649 // Propagate the Chrome Frame flag to sandboxed processes if present. 650 if (browser_command_line.HasSwitch(switches::kChromeFrame)) { 651 if (!cmd_line->HasSwitch(switches::kChromeFrame)) { 652 cmd_line->AppendSwitch(switches::kChromeFrame); 653 } 654 } 655 656 bool child_needs_help = 657 DebugFlags::ProcessDebugFlags(cmd_line, type, in_sandbox); 658 659 // Prefetch hints on windows: 660 // Using a different prefetch profile per process type will allow Windows 661 // to create separate pretetch settings for browser, renderer etc. 662 cmd_line->AppendArg(base::StringPrintf("/prefetch:%d", type)); 663 664 if (!in_sandbox) { 665 base::LaunchApp(*cmd_line, false, false, &process); 666 return process; 667 } 668 669 sandbox::ResultCode result; 670 PROCESS_INFORMATION target = {0}; 671 sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy(); 672 673 bool on_sandbox_desktop = false; 674 if (type == ChildProcessInfo::PLUGIN_PROCESS) { 675 if (!AddPolicyForPlugin(cmd_line, policy)) 676 return 0; 677 } else if (type == ChildProcessInfo::GPU_PROCESS) { 678 if (!AddPolicyForGPU(cmd_line, policy)) 679 return 0; 680 } else { 681 AddPolicyForRenderer(policy, &on_sandbox_desktop); 682 683 if (type_str != switches::kRendererProcess) { 684 // Hack for Google Desktop crash. Trick GD into not injecting its DLL into 685 // this subprocess. See 686 // http://code.google.com/p/chromium/issues/detail?id=25580 687 cmd_line->AppendSwitchASCII("ignored", " --type=renderer "); 688 } 689 } 690 691 if (!exposed_dir.empty()) { 692 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, 693 sandbox::TargetPolicy::FILES_ALLOW_ANY, 694 exposed_dir.value().c_str()); 695 if (result != sandbox::SBOX_ALL_OK) 696 return 0; 697 698 FilePath exposed_files = exposed_dir.AppendASCII("*"); 699 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, 700 sandbox::TargetPolicy::FILES_ALLOW_ANY, 701 exposed_files.value().c_str()); 702 if (result != sandbox::SBOX_ALL_OK) 703 return 0; 704 } 705 706 if (!AddGenericPolicy(policy)) { 707 NOTREACHED(); 708 return 0; 709 } 710 711 TRACE_EVENT_BEGIN("StartProcessWithAccess::LAUNCHPROCESS", 0, 0); 712 713 result = g_broker_services->SpawnTarget( 714 cmd_line->GetProgram().value().c_str(), 715 cmd_line->command_line_string().c_str(), 716 policy, &target); 717 policy->Release(); 718 719 TRACE_EVENT_END("StartProcessWithAccess::LAUNCHPROCESS", 0, 0); 720 721 if (sandbox::SBOX_ALL_OK != result) 722 return 0; 723 724 ResumeThread(target.hThread); 725 CloseHandle(target.hThread); 726 process = target.hProcess; 727 728 // Help the process a little. It can't start the debugger by itself if 729 // the process is in a sandbox. 730 if (child_needs_help) 731 base::debug::SpawnDebuggerOnProcess(target.dwProcessId); 732 733 return process; 734} 735 736} // namespace sandbox 737