• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 static sandbox::BrokerServices* g_broker_services = NULL;
28 
29 namespace {
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.
34 const 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 
91 enum PluginPolicyCategory {
92   PLUGIN_GROUP_TRUSTED,
93   PLUGIN_GROUP_UNTRUSTED,
94 };
95 
96 // Returns the policy category for the plugin dll.
GetPolicyCategoryForPlugin(const std::wstring & dll,const std::wstring & list)97 PluginPolicyCategory 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.
AddDirectory(int path,const wchar_t * sub_dir,bool children,sandbox::TargetPolicy::Semantics access,sandbox::TargetPolicy * policy)124 bool 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.
AddKeyAndSubkeys(std::wstring key,sandbox::TargetPolicy::Semantics access,sandbox::TargetPolicy * policy)157 bool 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|.
IsExpandedModuleName(HMODULE module,const wchar_t * module_name)176 bool 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.
BlacklistAddOneDll(const wchar_t * module_name,sandbox::TargetPolicy * policy)192 void 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.
AddDllEvictionPolicy(sandbox::TargetPolicy * policy)224 void 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.
AddGenericPolicy(sandbox::TargetPolicy * policy)230 bool 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.
ApplyPolicyForTrustedPlugin(sandbox::TargetPolicy * policy)272 bool 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.
ApplyPolicyForUntrustedPlugin(sandbox::TargetPolicy * policy)281 bool 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.
LoadFlashBroker(const FilePath & plugin_path,CommandLine * cmd_line)366 bool 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.
ApplyPolicyForBuiltInFlashPlugin(sandbox::TargetPolicy * policy)416 bool 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|
IsBuiltInFlash(const CommandLine * cmd_line,FilePath * flash_path)448 bool 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.
AddPolicyForPlugin(CommandLine * cmd_line,sandbox::TargetPolicy * policy)468 bool 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.
AddPolicyForGPU(CommandLine *,sandbox::TargetPolicy * policy)518 bool 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 
AddPolicyForRenderer(sandbox::TargetPolicy * policy,bool * on_sandbox_desktop)534 void 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 
563 namespace sandbox {
564 
InitBrokerServices(sandbox::BrokerServices * broker_services)565 void 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 
StartProcessWithAccess(CommandLine * cmd_line,const FilePath & exposed_dir)574 base::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