Enable webgl and accelerated compositing by default on all platforms. Removes
[chromium-blink-merge.git] / chrome / common / sandbox_policy.cc
blobdd9996c98e999ed35ddc634c1abe82133f7bfa84
1 // Copyright (c) 2010 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.
5 #include "chrome/common/sandbox_policy.h"
7 #include <string>
9 #include "app/win_util.h"
10 #include "base/command_line.h"
11 #include "base/debug_util.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/string_util.h"
17 #include "base/trace_event.h"
18 #include "base/win_util.h"
19 #include "chrome/common/child_process_info.h"
20 #include "chrome/common/chrome_constants.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/debug_flags.h"
24 #include "sandbox/src/sandbox.h"
26 static sandbox::BrokerServices* g_broker_services = NULL;
28 namespace {
30 // The DLLs listed here are known (or under strong suspicion) of causing crashes
31 // when they are loaded in the renderer.
32 const wchar_t* const kTroublesomeDlls[] = {
33 L"adialhk.dll", // Kaspersky Internet Security.
34 L"acpiz.dll", // Unknown.
35 L"avgrsstx.dll", // AVG 8.
36 L"btkeyind.dll", // Widcomm Bluetooth.
37 L"cmcsyshk.dll", // CMC Internet Security.
38 L"dockshellhook.dll", // Stardock Objectdock.
39 L"GoogleDesktopNetwork3.DLL", // Google Desktop Search v5.
40 L"fwhook.dll", // PC Tools Firewall Plus.
41 L"hookprocesscreation.dll", // Blumentals Program protector.
42 L"hookterminateapis.dll", // Blumentals and Cyberprinter.
43 L"hookprintapis.dll", // Cyberprinter.
44 L"imon.dll", // NOD32 Antivirus.
45 L"ioloHL.dll", // Iolo (System Mechanic).
46 L"kloehk.dll", // Kaspersky Internet Security.
47 L"lawenforcer.dll", // Spyware-Browser AntiSpyware (Spybro).
48 L"libdivx.dll", // DivX.
49 L"lvprcinj01.dll", // Logitech QuickCam.
50 L"madchook.dll", // Madshi (generic hooking library).
51 L"mdnsnsp.dll", // Bonjour.
52 L"moonsysh.dll", // Moon Secure Antivirus.
53 L"npdivx32.dll", // DivX.
54 L"npggNT.des", // GameGuard 2008.
55 L"npggNT.dll", // GameGuard (older).
56 L"oawatch.dll", // Online Armor.
57 L"pavhook.dll", // Panda Internet Security.
58 L"pavshook.dll", // Panda Antivirus.
59 L"pctavhook.dll", // PC Tools Antivirus.
60 L"pctgmhk.dll", // PC Tools Spyware Doctor.
61 L"prntrack.dll", // Pharos Systems.
62 L"radhslib.dll", // Radiant Naomi Internet Filter.
63 L"radprlib.dll", // Radiant Naomi Internet Filter.
64 L"rlhook.dll", // Trustware Bufferzone.
65 L"r3hook.dll", // Kaspersky Internet Security.
66 L"sahook.dll", // McAfee Site Advisor.
67 L"sbrige.dll", // Unknown.
68 L"sc2hook.dll", // Supercopier 2.
69 L"sguard.dll", // Iolo (System Guard).
70 L"smum32.dll", // Spyware Doctor version 6.
71 L"smumhook.dll", // Spyware Doctor version 5.
72 L"ssldivx.dll", // DivX.
73 L"syncor11.dll", // SynthCore Midi interface.
74 L"systools.dll", // Panda Antivirus.
75 L"tfwah.dll", // Threatfire (PC tools).
76 L"wblind.dll", // Stardock Object desktop.
77 L"wbhelp.dll", // Stardock Object desktop.
78 L"winstylerthemehelper.dll" // Tuneup utilities 2006.
81 enum PluginPolicyCategory {
82 PLUGIN_GROUP_TRUSTED,
83 PLUGIN_GROUP_UNTRUSTED,
86 // Returns the policy category for the plugin dll.
87 PluginPolicyCategory GetPolicyCategoryForPlugin(
88 const std::wstring& dll,
89 const std::wstring& list) {
90 std::wstring filename = FilePath(dll).BaseName().value();
91 std::wstring plugin_dll = StringToLowerASCII(filename);
92 std::wstring trusted_plugins = StringToLowerASCII(list);
94 size_t pos = 0;
95 size_t end_item = 0;
96 while (end_item != std::wstring::npos) {
97 end_item = list.find(L",", pos);
99 size_t size_item = (end_item == std::wstring::npos) ? end_item :
100 end_item - pos;
101 std::wstring item = list.substr(pos, size_item);
102 if (!item.empty() && item == plugin_dll)
103 return PLUGIN_GROUP_TRUSTED;
105 pos = end_item + 1;
108 return PLUGIN_GROUP_UNTRUSTED;
111 // Adds the policy rules for the path and path\ with the semantic |access|.
112 // If |children| is set to true, we need to add the wildcard rules to also
113 // apply the rule to the subfiles and subfolders.
114 bool AddDirectory(int path, const wchar_t* sub_dir, bool children,
115 sandbox::TargetPolicy::Semantics access,
116 sandbox::TargetPolicy* policy) {
117 std::wstring directory;
118 if (!PathService::Get(path, &directory))
119 return false;
121 if (sub_dir) {
122 file_util::AppendToPath(&directory, sub_dir);
123 file_util::AbsolutePath(&directory);
126 sandbox::ResultCode result;
127 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
128 directory.c_str());
129 if (result != sandbox::SBOX_ALL_OK)
130 return false;
132 if (children)
133 file_util::AppendToPath(&directory, L"*");
134 else
135 // Add the version of the path that ends with a separator.
136 file_util::AppendToPath(&directory, L"");
138 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
139 directory.c_str());
140 if (result != sandbox::SBOX_ALL_OK)
141 return false;
143 return true;
146 // Adds the policy rules for the path and path\* with the semantic |access|.
147 // We need to add the wildcard rules to also apply the rule to the subkeys.
148 bool AddKeyAndSubkeys(std::wstring key,
149 sandbox::TargetPolicy::Semantics access,
150 sandbox::TargetPolicy* policy) {
151 sandbox::ResultCode result;
152 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, access,
153 key.c_str());
154 if (result != sandbox::SBOX_ALL_OK)
155 return false;
157 key += L"\\*";
158 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, access,
159 key.c_str());
160 if (result != sandbox::SBOX_ALL_OK)
161 return false;
163 return true;
166 // Adds policy rules for unloaded the known dlls that cause chrome to crash.
167 // Eviction of injected DLLs is done by the sandbox so that the injected module
168 // does not get a chance to execute any code.
169 void AddDllEvictionPolicy(sandbox::TargetPolicy* policy) {
170 for (int ix = 0; ix != arraysize(kTroublesomeDlls); ++ix) {
171 // To minimize the list we only add an unload policy if the dll is also
172 // loaded in this process. All the injected dlls of interest do this.
173 if (::GetModuleHandleW(kTroublesomeDlls[ix])) {
174 LOG(INFO) << "dll to unload found: " << kTroublesomeDlls[ix];
175 policy->AddDllToUnload(kTroublesomeDlls[ix]);
180 // Adds the generic policy rules to a sandbox TargetPolicy.
181 bool AddGenericPolicy(sandbox::TargetPolicy* policy) {
182 sandbox::ResultCode result;
184 // Add the policy for the pipes
185 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
186 sandbox::TargetPolicy::FILES_ALLOW_ANY,
187 L"\\??\\pipe\\chrome.*");
188 if (result != sandbox::SBOX_ALL_OK)
189 return false;
191 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
192 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
193 L"\\\\.\\pipe\\chrome.nacl.*");
194 if (result != sandbox::SBOX_ALL_OK)
195 return false;
197 // Add the policy for debug message only in debug
198 #ifndef NDEBUG
199 std::wstring debug_message;
200 if (!PathService::Get(chrome::DIR_APP, &debug_message))
201 return false;
202 if (!win_util::ConvertToLongPath(debug_message, &debug_message))
203 return false;
204 file_util::AppendToPath(&debug_message, L"debug_message.exe");
205 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS,
206 sandbox::TargetPolicy::PROCESS_MIN_EXEC,
207 debug_message.c_str());
208 if (result != sandbox::SBOX_ALL_OK)
209 return false;
210 #endif // NDEBUG
212 return true;
215 // Creates a sandbox without any restriction.
216 bool ApplyPolicyForTrustedPlugin(sandbox::TargetPolicy* policy) {
217 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
218 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
219 return true;
222 // Creates a sandbox with the plugin running in a restricted environment.
223 // Only the "Users" and "Everyone" groups are enabled in the token. The User SID
224 // is disabled.
225 bool ApplyPolicyForUntrustedPlugin(sandbox::TargetPolicy* policy) {
226 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
228 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED;
229 if (win_util::GetWinVersion() > win_util::WINVERSION_XP) {
230 // On 2003/Vista the initial token has to be restricted if the main token
231 // is restricted.
232 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS;
234 policy->SetTokenLevel(initial_token, sandbox::USER_LIMITED);
235 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
237 if (!AddDirectory(base::DIR_TEMP, NULL, true,
238 sandbox::TargetPolicy::FILES_ALLOW_ANY, policy))
239 return false;
241 if (!AddDirectory(base::DIR_IE_INTERNET_CACHE, NULL, true,
242 sandbox::TargetPolicy::FILES_ALLOW_ANY, policy))
243 return false;
245 if (!AddDirectory(base::DIR_APP_DATA, NULL, true,
246 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
247 policy))
248 return false;
250 if (!AddDirectory(base::DIR_PROFILE, NULL, false, /*not recursive*/
251 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
252 policy))
253 return false;
255 if (!AddDirectory(base::DIR_APP_DATA, L"Adobe", true,
256 sandbox::TargetPolicy::FILES_ALLOW_ANY,
257 policy))
258 return false;
260 if (!AddDirectory(base::DIR_APP_DATA, L"Macromedia", true,
261 sandbox::TargetPolicy::FILES_ALLOW_ANY,
262 policy))
263 return false;
265 if (!AddDirectory(base::DIR_LOCAL_APP_DATA, NULL, true,
266 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
267 policy))
268 return false;
270 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\ADOBE",
271 sandbox::TargetPolicy::REG_ALLOW_ANY,
272 policy))
273 return false;
275 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\MACROMEDIA",
276 sandbox::TargetPolicy::REG_ALLOW_ANY,
277 policy))
278 return false;
280 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) {
281 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\AppDataLow",
282 sandbox::TargetPolicy::REG_ALLOW_ANY,
283 policy))
284 return false;
286 if (!AddDirectory(base::DIR_LOCAL_APP_DATA_LOW, NULL, true,
287 sandbox::TargetPolicy::FILES_ALLOW_ANY,
288 policy))
289 return false;
291 // DIR_APP_DATA is AppData\Roaming, but Adobe needs to do a directory
292 // listing in AppData directly, so we add a non-recursive policy for
293 // AppData itself.
294 if (!AddDirectory(base::DIR_APP_DATA, L"..", false,
295 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
296 policy))
297 return false;
300 return true;
303 // Creates a sandbox for the built-in flash plugin running in a restricted
304 // environment. This is a work in progress and for the time being do not
305 // pay attention to the duplication between this function and the above
306 // function. For more information see bug 50796.
307 bool ApplyPolicyForBuiltInFlashPlugin(sandbox::TargetPolicy* policy) {
308 // TODO(cpu): Lock down the job level more.
309 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
311 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED;
312 if (win_util::GetWinVersion() > win_util::WINVERSION_XP)
313 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS;
314 policy->SetTokenLevel(initial_token, sandbox::USER_LIMITED);
316 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
318 // TODO(cpu): Proxy registry access and remove these policies.
319 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\ADOBE",
320 sandbox::TargetPolicy::REG_ALLOW_ANY,
321 policy))
322 return false;
324 if (!AddKeyAndSubkeys(L"HKEY_CURRENT_USER\\SOFTWARE\\MACROMEDIA",
325 sandbox::TargetPolicy::REG_ALLOW_ANY,
326 policy))
327 return false;
329 // Use a different data folder for flash data. This needs to be
330 // reverted once we stop the experiments.
331 FilePath flash_path;
332 PathService::Get(chrome::DIR_USER_DATA, &flash_path);
333 flash_path = flash_path.AppendASCII("swflash");
334 ::SetEnvironmentVariableW(L"CHROME_FLASH_ROOT",
335 flash_path.ToWStringHack().c_str());
336 return true;
339 // Adds the custom policy rules for a given plugin. |trusted_plugins| contains
340 // the comma separate list of plugin dll names that should not be sandboxed.
341 bool AddPolicyForPlugin(const CommandLine* cmd_line,
342 sandbox::TargetPolicy* policy) {
343 std::wstring plugin_dll = cmd_line->
344 GetSwitchValueNative(switches::kPluginPath);
345 std::wstring trusted_plugins = CommandLine::ForCurrentProcess()->
346 GetSwitchValueNative(switches::kTrustedPlugins);
347 // Add the policy for the pipes.
348 sandbox::ResultCode result = sandbox::SBOX_ALL_OK;
349 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
350 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
351 L"\\\\.\\pipe\\chrome.*");
352 if (result != sandbox::SBOX_ALL_OK) {
353 NOTREACHED();
354 return false;
357 // The built-in flash gets a custom, more restricted sandbox.
358 FilePath builtin_flash;
359 if (PathService::Get(chrome::FILE_FLASH_PLUGIN, &builtin_flash)) {
360 FilePath plugin_path(plugin_dll);
361 if (plugin_path == builtin_flash)
362 return ApplyPolicyForBuiltInFlashPlugin(policy);
365 PluginPolicyCategory policy_category =
366 GetPolicyCategoryForPlugin(plugin_dll, trusted_plugins);
368 switch (policy_category) {
369 case PLUGIN_GROUP_TRUSTED:
370 return ApplyPolicyForTrustedPlugin(policy);
371 case PLUGIN_GROUP_UNTRUSTED:
372 return ApplyPolicyForUntrustedPlugin(policy);
373 default:
374 NOTREACHED();
375 break;
378 return false;
381 void AddPolicyForRenderer(sandbox::TargetPolicy* policy,
382 bool* on_sandbox_desktop) {
383 policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0);
385 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED;
386 if (win_util::GetWinVersion() > win_util::WINVERSION_XP) {
387 // On 2003/Vista the initial token has to be restricted if the main
388 // token is restricted.
389 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS;
392 policy->SetTokenLevel(initial_token, sandbox::USER_LOCKDOWN);
393 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
395 bool use_winsta = !CommandLine::ForCurrentProcess()->HasSwitch(
396 switches::kDisableAltWinstation);
398 if (sandbox::SBOX_ALL_OK == policy->SetAlternateDesktop(use_winsta)) {
399 *on_sandbox_desktop = true;
400 } else {
401 *on_sandbox_desktop = false;
402 DLOG(WARNING) << "Failed to apply desktop security to the renderer";
405 AddDllEvictionPolicy(policy);
408 } // namespace
410 namespace sandbox {
412 void InitBrokerServices(sandbox::BrokerServices* broker_services) {
413 // TODO(abarth): DCHECK(CalledOnValidThread());
414 // See <http://b/1287166>.
415 CHECK(broker_services);
416 CHECK(!g_broker_services);
417 broker_services->Init();
418 g_broker_services = broker_services;
421 base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
422 const FilePath& exposed_dir) {
423 base::ProcessHandle process = 0;
424 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
425 ChildProcessInfo::ProcessType type;
426 std::string type_str = cmd_line->GetSwitchValueASCII(switches::kProcessType);
427 if (type_str == switches::kRendererProcess) {
428 type = ChildProcessInfo::RENDER_PROCESS;
429 } else if (type_str == switches::kExtensionProcess) {
430 // Extensions are just renderers with another name.
431 type = ChildProcessInfo::RENDER_PROCESS;
432 } else if (type_str == switches::kPluginProcess) {
433 type = ChildProcessInfo::PLUGIN_PROCESS;
434 } else if (type_str == switches::kWorkerProcess) {
435 type = ChildProcessInfo::WORKER_PROCESS;
436 } else if (type_str == switches::kNaClLoaderProcess) {
437 type = ChildProcessInfo::NACL_LOADER_PROCESS;
438 } else if (type_str == switches::kUtilityProcess) {
439 type = ChildProcessInfo::UTILITY_PROCESS;
440 } else if (type_str == switches::kNaClBrokerProcess) {
441 type = ChildProcessInfo::NACL_BROKER_PROCESS;
442 } else if (type_str == switches::kGpuProcess) {
443 type = ChildProcessInfo::GPU_PROCESS;
444 } else {
445 NOTREACHED();
446 return 0;
449 TRACE_EVENT_BEGIN("StartProcessWithAccess", 0, type_str);
451 bool in_sandbox =
452 (type != ChildProcessInfo::NACL_BROKER_PROCESS) &&
453 !browser_command_line.HasSwitch(switches::kNoSandbox) &&
454 (type != ChildProcessInfo::PLUGIN_PROCESS ||
455 browser_command_line.HasSwitch(switches::kSafePlugins)) &&
456 (type != ChildProcessInfo::GPU_PROCESS);
457 #if !defined (GOOGLE_CHROME_BUILD)
458 if (browser_command_line.HasSwitch(switches::kInProcessPlugins)) {
459 // In process plugins won't work if the sandbox is enabled.
460 in_sandbox = false;
462 #endif
463 if (!browser_command_line.HasSwitch(switches::kDisableExperimentalWebGL) &&
464 browser_command_line.HasSwitch(switches::kInProcessWebGL)) {
465 // In process WebGL won't work if the sandbox is enabled.
466 in_sandbox = false;
469 // Propagate the Chrome Frame flag to sandboxed processes if present.
470 if (browser_command_line.HasSwitch(switches::kChromeFrame)) {
471 if (!cmd_line->HasSwitch(switches::kChromeFrame)) {
472 cmd_line->AppendSwitch(switches::kChromeFrame);
476 bool child_needs_help =
477 DebugFlags::ProcessDebugFlags(cmd_line, type, in_sandbox);
479 // Prefetch hints on windows:
480 // Using a different prefetch profile per process type will allow Windows
481 // to create separate pretetch settings for browser, renderer etc.
482 cmd_line->AppendArg(StringPrintf("/prefetch:%d", type));
484 if (!in_sandbox) {
485 base::LaunchApp(*cmd_line, false, false, &process);
486 return process;
489 sandbox::ResultCode result;
490 PROCESS_INFORMATION target = {0};
491 sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy();
493 bool on_sandbox_desktop = false;
494 if (type == ChildProcessInfo::PLUGIN_PROCESS) {
495 if (!AddPolicyForPlugin(cmd_line, policy))
496 return 0;
497 } else {
498 AddPolicyForRenderer(policy, &on_sandbox_desktop);
500 if (type_str != switches::kRendererProcess) {
501 // Hack for Google Desktop crash. Trick GD into not injecting its DLL into
502 // this subprocess. See
503 // http://code.google.com/p/chromium/issues/detail?id=25580
504 cmd_line->AppendSwitchASCII("ignored", " --type=renderer ");
508 if (!exposed_dir.empty()) {
509 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
510 sandbox::TargetPolicy::FILES_ALLOW_ANY,
511 exposed_dir.ToWStringHack().c_str());
512 if (result != sandbox::SBOX_ALL_OK)
513 return 0;
515 FilePath exposed_files = exposed_dir.AppendASCII("*");
516 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
517 sandbox::TargetPolicy::FILES_ALLOW_ANY,
518 exposed_files.ToWStringHack().c_str());
519 if (result != sandbox::SBOX_ALL_OK)
520 return 0;
523 if (!AddGenericPolicy(policy)) {
524 NOTREACHED();
525 return 0;
528 TRACE_EVENT_BEGIN("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
530 result = g_broker_services->SpawnTarget(
531 cmd_line->program().c_str(),
532 cmd_line->command_line_string().c_str(),
533 policy, &target);
534 policy->Release();
536 TRACE_EVENT_END("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
538 if (sandbox::SBOX_ALL_OK != result)
539 return 0;
541 ResumeThread(target.hThread);
542 CloseHandle(target.hThread);
543 process = target.hProcess;
545 // Help the process a little. It can't start the debugger by itself if
546 // the process is in a sandbox.
547 if (child_needs_help)
548 DebugUtil::SpawnDebuggerOnProcess(target.dwProcessId);
550 return process;
553 } // namespace sandbox