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
3 // found in the LICENSE file.
5 #include "content/common/sandbox_policy.h"
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/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/path_service.h"
16 #include "base/process_util.h"
17 #include "base/string_util.h"
18 #include "base/stringprintf.h"
19 #include "base/win/iat_patch_function.h"
20 #include "base/win/scoped_handle.h"
21 #include "base/win/scoped_process_information.h"
22 #include "base/win/windows_version.h"
23 #include "content/common/debug_flags.h"
24 #include "content/public/common/content_client.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/process_type.h"
27 #include "content/public/common/sandbox_init.h"
28 #include "sandbox/win/src/process_mitigations.h"
29 #include "sandbox/win/src/sandbox.h"
30 #include "sandbox/win/src/sandbox_nt_util.h"
31 #include "sandbox/win/src/win_utils.h"
32 #include "ui/gl/gl_switches.h"
34 static sandbox::BrokerServices
* g_broker_services
= NULL
;
35 static sandbox::TargetServices
* g_target_services
= NULL
;
39 // The DLLs listed here are known (or under strong suspicion) of causing crashes
40 // when they are loaded in the renderer. Note: at runtime we generate short
41 // versions of the dll name only if the dll has an extension.
42 const wchar_t* const kTroublesomeDlls
[] = {
43 L
"adialhk.dll", // Kaspersky Internet Security.
44 L
"acpiz.dll", // Unknown.
45 L
"avgrsstx.dll", // AVG 8.
46 L
"babylonchromepi.dll", // Babylon translator.
47 L
"btkeyind.dll", // Widcomm Bluetooth.
48 L
"cmcsyshk.dll", // CMC Internet Security.
49 L
"cmsetac.dll", // Unknown (suspected malware).
50 L
"cooliris.dll", // CoolIris.
51 L
"dockshellhook.dll", // Stardock Objectdock.
52 L
"easyhook32.dll", // GDIPP and others.
53 L
"googledesktopnetwork3.dll", // Google Desktop Search v5.
54 L
"fwhook.dll", // PC Tools Firewall Plus.
55 L
"hookprocesscreation.dll", // Blumentals Program protector.
56 L
"hookterminateapis.dll", // Blumentals and Cyberprinter.
57 L
"hookprintapis.dll", // Cyberprinter.
58 L
"imon.dll", // NOD32 Antivirus.
59 L
"ioloHL.dll", // Iolo (System Mechanic).
60 L
"kloehk.dll", // Kaspersky Internet Security.
61 L
"lawenforcer.dll", // Spyware-Browser AntiSpyware (Spybro).
62 L
"libdivx.dll", // DivX.
63 L
"lvprcinj01.dll", // Logitech QuickCam.
64 L
"madchook.dll", // Madshi (generic hooking library).
65 L
"mdnsnsp.dll", // Bonjour.
66 L
"moonsysh.dll", // Moon Secure Antivirus.
67 L
"mpk.dll", // KGB Spy.
68 L
"npdivx32.dll", // DivX.
69 L
"npggNT.des", // GameGuard 2008.
70 L
"npggNT.dll", // GameGuard (older).
71 L
"oawatch.dll", // Online Armor.
72 L
"owexplorer-10513.dll", // Overwolf.
73 L
"owexplorer-10514.dll", // Overwolf.
74 L
"owexplorer-10515.dll", // Overwolf.
75 L
"owexplorer-10516.dll", // Overwolf.
76 L
"owexplorer-10517.dll", // Overwolf.
77 L
"owexplorer-10518.dll", // Overwolf.
78 L
"owexplorer-10519.dll", // Overwolf.
79 L
"owexplorer-10520.dll", // Overwolf.
80 L
"owexplorer-10521.dll", // Overwolf.
81 L
"owexplorer-10522.dll", // Overwolf.
82 L
"owexplorer-10523.dll", // Overwolf.
83 L
"pavhook.dll", // Panda Internet Security.
84 L
"pavlsphook.dll", // Panda Antivirus.
85 L
"pavshook.dll", // Panda Antivirus.
86 L
"pavshookwow.dll", // Panda Antivirus.
87 L
"pctavhook.dll", // PC Tools Antivirus.
88 L
"pctgmhk.dll", // PC Tools Spyware Doctor.
89 L
"prntrack.dll", // Pharos Systems.
90 L
"protector.dll", // Unknown (suspected malware).
91 L
"radhslib.dll", // Radiant Naomi Internet Filter.
92 L
"radprlib.dll", // Radiant Naomi Internet Filter.
93 L
"rapportnikko.dll", // Trustware Rapport.
94 L
"rlhook.dll", // Trustware Bufferzone.
95 L
"rooksdol.dll", // Trustware Rapport.
96 L
"rpchromebrowserrecordhelper.dll", // RealPlayer.
97 L
"r3hook.dll", // Kaspersky Internet Security.
98 L
"sahook.dll", // McAfee Site Advisor.
99 L
"sbrige.dll", // Unknown.
100 L
"sc2hook.dll", // Supercopier 2.
101 L
"sdhook32.dll", // Spybot - Search & Destroy Live Protection.
102 L
"sguard.dll", // Iolo (System Guard).
103 L
"smum32.dll", // Spyware Doctor version 6.
104 L
"smumhook.dll", // Spyware Doctor version 5.
105 L
"ssldivx.dll", // DivX.
106 L
"syncor11.dll", // SynthCore Midi interface.
107 L
"systools.dll", // Panda Antivirus.
108 L
"tfwah.dll", // Threatfire (PC tools).
109 L
"wblind.dll", // Stardock Object desktop.
110 L
"wbhelp.dll", // Stardock Object desktop.
111 L
"winstylerthemehelper.dll" // Tuneup utilities 2006.
114 // The DLLs listed here are known (or under strong suspicion) of causing crashes
115 // when they are loaded in the GPU process.
116 const wchar_t* const kTroublesomeGpuDlls
[] = {
117 L
"cmsetac.dll", // Unknown (suspected malware).
120 // Adds the policy rules for the path and path\ with the semantic |access|.
121 // If |children| is set to true, we need to add the wildcard rules to also
122 // apply the rule to the subfiles and subfolders.
123 bool AddDirectory(int path
, const wchar_t* sub_dir
, bool children
,
124 sandbox::TargetPolicy::Semantics access
,
125 sandbox::TargetPolicy
* policy
) {
127 if (!PathService::Get(path
, &directory
))
131 directory
= directory
.Append(sub_dir
);
132 file_util::AbsolutePath(&directory
);
135 sandbox::ResultCode result
;
136 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_FILES
, access
,
137 directory
.value().c_str());
138 if (result
!= sandbox::SBOX_ALL_OK
)
141 std::wstring directory_str
= directory
.value() + L
"\\";
143 directory_str
+= L
"*";
144 // Otherwise, add the version of the path that ends with a separator.
146 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_FILES
, access
,
147 directory_str
.c_str());
148 if (result
!= sandbox::SBOX_ALL_OK
)
154 // Adds the policy rules for the path and path\* with the semantic |access|.
155 // We need to add the wildcard rules to also apply the rule to the subkeys.
156 bool AddKeyAndSubkeys(std::wstring key
,
157 sandbox::TargetPolicy::Semantics access
,
158 sandbox::TargetPolicy
* policy
) {
159 sandbox::ResultCode result
;
160 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY
, access
,
162 if (result
!= sandbox::SBOX_ALL_OK
)
166 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY
, access
,
168 if (result
!= sandbox::SBOX_ALL_OK
)
174 // Compares the loaded |module| file name matches |module_name|.
175 bool IsExpandedModuleName(HMODULE module
, const wchar_t* module_name
) {
176 wchar_t path
[MAX_PATH
];
177 DWORD sz
= ::GetModuleFileNameW(module
, path
, arraysize(path
));
178 if ((sz
== arraysize(path
)) || (sz
== 0)) {
179 // XP does not set the last error properly, so we bail out anyway.
182 if (!::GetLongPathName(path
, path
, arraysize(path
)))
184 FilePath
fname(path
);
185 return (fname
.BaseName().value() == module_name
);
188 // Adds a single dll by |module_name| into the |policy| blacklist.
189 // If |check_in_browser| is true we only add an unload policy only if the dll
190 // is also loaded in this process.
191 void BlacklistAddOneDll(const wchar_t* module_name
,
192 bool check_in_browser
,
193 sandbox::TargetPolicy
* policy
) {
194 HMODULE module
= check_in_browser
? ::GetModuleHandleW(module_name
) : NULL
;
196 // The module could have been loaded with a 8.3 short name. We check
197 // the three most common cases: 'thelongname.dll' becomes
198 // 'thelon~1.dll', 'thelon~2.dll' and 'thelon~3.dll'.
199 std::wstring
name(module_name
);
200 size_t period
= name
.rfind(L
'.');
201 DCHECK_NE(std::string::npos
, period
);
202 DCHECK_LE(3U, (name
.size() - period
));
205 for (int ix
= 0; ix
< 3; ++ix
) {
206 const wchar_t suffix
[] = {'~', ('1' + ix
), 0};
207 std::wstring alt_name
= name
.substr(0, 6) + suffix
;
208 alt_name
+= name
.substr(period
, name
.size());
209 if (check_in_browser
) {
210 module
= ::GetModuleHandleW(alt_name
.c_str());
213 // We found it, but because it only has 6 significant letters, we
214 // want to make sure it is the right one.
215 if (!IsExpandedModuleName(module
, module_name
))
218 // Found a match. We add both forms to the policy.
219 policy
->AddDllToUnload(alt_name
.c_str());
222 policy
->AddDllToUnload(module_name
);
223 DVLOG(1) << "dll to unload found: " << module_name
;
227 // Adds policy rules for unloaded the known dlls that cause chrome to crash.
228 // Eviction of injected DLLs is done by the sandbox so that the injected module
229 // does not get a chance to execute any code.
230 void AddGenericDllEvictionPolicy(sandbox::TargetPolicy
* policy
) {
231 for (int ix
= 0; ix
!= arraysize(kTroublesomeDlls
); ++ix
)
232 BlacklistAddOneDll(kTroublesomeDlls
[ix
], true, policy
);
235 // Same as AddGenericDllEvictionPolicy but specifically for the GPU process.
236 // In this we add the blacklisted dlls even if they are not loaded in this
238 void AddGpuDllEvictionPolicy(sandbox::TargetPolicy
* policy
) {
239 for (int ix
= 0; ix
!= arraysize(kTroublesomeGpuDlls
); ++ix
)
240 BlacklistAddOneDll(kTroublesomeGpuDlls
[ix
], false, policy
);
243 // Returns the object path prepended with the current logon session.
244 string16
PrependWindowsSessionPath(const char16
* object
) {
245 // Cache this because it can't change after process creation.
246 static uintptr_t s_session_id
= 0;
247 if (s_session_id
== 0) {
249 DWORD session_id_length
;
250 DWORD session_id
= 0;
252 CHECK(::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY
, &token
));
253 CHECK(::GetTokenInformation(token
, TokenSessionId
, &session_id
,
254 sizeof(session_id
), &session_id_length
));
257 s_session_id
= session_id
;
260 return base::StringPrintf(L
"\\Sessions\\%d%ls", s_session_id
, object
);
263 // Checks if the sandbox should be let to run without a job object assigned.
264 bool ShouldSetJobLevel(const CommandLine
& cmd_line
) {
265 if (!cmd_line
.HasSwitch(switches::kAllowNoSandboxJob
))
268 // Windows 8 allows nested jobs so we don't need to check if we are in other
270 if (base::win::GetVersion() >= base::win::VERSION_WIN8
)
274 // Either there is no job yet associated so we must add our job,
275 if (!::IsProcessInJob(::GetCurrentProcess(), NULL
, &in_job
))
276 NOTREACHED() << "IsProcessInJob failed. " << GetLastError();
280 // ...or there is a job but the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit is set.
281 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info
= {0};
282 if (!::QueryInformationJobObject(NULL
,
283 JobObjectExtendedLimitInformation
, &job_info
,
284 sizeof(job_info
), NULL
)) {
285 NOTREACHED() << "QueryInformationJobObject failed. " << GetLastError();
288 if (job_info
.BasicLimitInformation
.LimitFlags
& JOB_OBJECT_LIMIT_BREAKAWAY_OK
)
294 void SetJobLevel(const CommandLine
& cmd_line
,
295 sandbox::JobLevel job_level
,
296 uint32 ui_exceptions
,
297 sandbox::TargetPolicy
* policy
) {
298 if (ShouldSetJobLevel(cmd_line
))
299 policy
->SetJobLevel(job_level
, ui_exceptions
);
301 policy
->SetJobLevel(sandbox::JOB_NONE
, 0);
304 // Closes handles that are opened at process creation and initialization.
305 void AddBaseHandleClosePolicy(sandbox::TargetPolicy
* policy
) {
306 // Being able to manipulate anything BaseNamedObjects is bad.
307 string16 object_path
= PrependWindowsSessionPath(L
"\\BaseNamedObjects");
308 policy
->AddKernelObjectToClose(L
"Directory", object_path
.data());
309 object_path
= PrependWindowsSessionPath(
310 L
"\\BaseNamedObjects\\windows_shell_global_counters");
311 policy
->AddKernelObjectToClose(L
"Section", object_path
.data());
314 // Adds the generic policy rules to a sandbox TargetPolicy.
315 bool AddGenericPolicy(sandbox::TargetPolicy
* policy
) {
316 sandbox::ResultCode result
;
318 // Add the policy for the client side of a pipe. It is just a file
319 // in the \pipe\ namespace. We restrict it to pipes that start with
320 // "chrome." so the sandboxed process cannot connect to system services.
321 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_FILES
,
322 sandbox::TargetPolicy::FILES_ALLOW_ANY
,
323 L
"\\??\\pipe\\chrome.*");
324 if (result
!= sandbox::SBOX_ALL_OK
)
326 // Allow the server side of a pipe restricted to the "chrome.nacl."
327 // namespace so that it cannot impersonate other system or other chrome
329 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES
,
330 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY
,
331 L
"\\\\.\\pipe\\chrome.nacl.*");
332 if (result
!= sandbox::SBOX_ALL_OK
)
334 // Allow the server side of sync sockets, which are pipes that have
335 // the "chrome.sync" namespace and a randomly generated suffix.
336 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES
,
337 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY
,
338 L
"\\\\.\\pipe\\chrome.sync.*");
339 if (result
!= sandbox::SBOX_ALL_OK
)
342 // Add the policy for debug message only in debug
345 if (!PathService::Get(base::DIR_MODULE
, &app_dir
))
348 wchar_t long_path_buf
[MAX_PATH
];
349 DWORD long_path_return_value
= GetLongPathName(app_dir
.value().c_str(),
352 if (long_path_return_value
== 0 || long_path_return_value
>= MAX_PATH
)
355 FilePath
debug_message(long_path_buf
);
356 debug_message
= debug_message
.AppendASCII("debug_message.exe");
357 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS
,
358 sandbox::TargetPolicy::PROCESS_MIN_EXEC
,
359 debug_message
.value().c_str());
360 if (result
!= sandbox::SBOX_ALL_OK
)
367 // For the GPU process we gotten as far as USER_LIMITED. The next level
368 // which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL
369 // backend. Note that the GPU process is connected to the interactive
371 // TODO(cpu): Lock down the sandbox more if possible.
372 bool AddPolicyForGPU(CommandLine
* cmd_line
, sandbox::TargetPolicy
* policy
) {
373 #if !defined(NACL_WIN64) // We don't need this code on win nacl64.
374 if (base::win::GetVersion() > base::win::VERSION_XP
) {
375 if (cmd_line
->GetSwitchValueASCII(switches::kUseGL
) ==
376 gfx::kGLImplementationDesktopName
) {
378 policy
->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS
,
379 sandbox::USER_LIMITED
);
380 SetJobLevel(*cmd_line
, sandbox::JOB_UNPROTECTED
, 0, policy
);
381 policy
->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW
);
383 if (cmd_line
->GetSwitchValueASCII(switches::kUseGL
) ==
384 gfx::kGLImplementationSwiftShaderName
||
385 cmd_line
->HasSwitch(switches::kReduceGpuSandbox
) ||
386 cmd_line
->HasSwitch(switches::kDisableImageTransportSurface
)) {
388 policy
->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS
,
389 sandbox::USER_LIMITED
);
391 // Angle + DirectX path.
392 policy
->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS
,
393 sandbox::USER_RESTRICTED
);
394 // This is a trick to keep the GPU out of low-integrity processes. It
395 // starts at low-integrity for UIPI to work, then drops below
396 // low-integrity after warm-up.
397 policy
->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED
);
400 // UI restrictions break when we access Windows from outside our job.
401 // However, we don't want a proxy window in this process because it can
402 // introduce deadlocks where the renderer blocks on the gpu, which in
403 // turn blocks on the browser UI thread. So, instead we forgo a window
404 // message pump entirely and just add job restrictions to prevent child
406 SetJobLevel(*cmd_line
,
407 sandbox::JOB_LIMITED_USER
,
408 JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS
|
409 JOB_OBJECT_UILIMIT_DESKTOP
|
410 JOB_OBJECT_UILIMIT_EXITWINDOWS
|
411 JOB_OBJECT_UILIMIT_DISPLAYSETTINGS
,
414 policy
->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW
);
417 SetJobLevel(*cmd_line
, sandbox::JOB_UNPROTECTED
, 0, policy
);
418 policy
->SetTokenLevel(sandbox::USER_UNPROTECTED
,
419 sandbox::USER_LIMITED
);
422 // Allow the server side of GPU sockets, which are pipes that have
423 // the "chrome.gpu" namespace and an arbitrary suffix.
424 sandbox::ResultCode result
= policy
->AddRule(
425 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES
,
426 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY
,
427 L
"\\\\.\\pipe\\chrome.gpu.*");
428 if (result
!= sandbox::SBOX_ALL_OK
)
431 // GPU needs to copy sections to renderers.
432 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES
,
433 sandbox::TargetPolicy::HANDLES_DUP_ANY
,
435 if (result
!= sandbox::SBOX_ALL_OK
)
439 // GPU also needs to add sections to the browser for aura
440 // TODO(jschuh): refactor the GPU channel to remove this. crbug.com/128786
441 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES
,
442 sandbox::TargetPolicy::HANDLES_DUP_BROKER
,
444 if (result
!= sandbox::SBOX_ALL_OK
)
448 AddGenericDllEvictionPolicy(policy
);
449 AddGpuDllEvictionPolicy(policy
);
454 bool AddPolicyForRenderer(sandbox::TargetPolicy
* policy
) {
455 // Renderers need to copy sections for plugin DIBs and GPU.
456 sandbox::ResultCode result
;
457 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES
,
458 sandbox::TargetPolicy::HANDLES_DUP_ANY
,
460 if (result
!= sandbox::SBOX_ALL_OK
)
463 // Renderers need to share events with plugins.
464 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES
,
465 sandbox::TargetPolicy::HANDLES_DUP_ANY
,
467 if (result
!= sandbox::SBOX_ALL_OK
)
470 // Renderers need to send named pipe handles and shared memory
471 // segment handles to NaCl loader processes.
472 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES
,
473 sandbox::TargetPolicy::HANDLES_DUP_ANY
,
475 if (result
!= sandbox::SBOX_ALL_OK
)
478 sandbox::TokenLevel initial_token
= sandbox::USER_UNPROTECTED
;
479 if (base::win::GetVersion() > base::win::VERSION_XP
) {
480 // On 2003/Vista the initial token has to be restricted if the main
481 // token is restricted.
482 initial_token
= sandbox::USER_RESTRICTED_SAME_ACCESS
;
485 policy
->SetTokenLevel(initial_token
, sandbox::USER_LOCKDOWN
);
486 // Prevents the renderers from manipulating low-integrity processes.
487 policy
->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED
);
489 bool use_winsta
= !CommandLine::ForCurrentProcess()->HasSwitch(
490 switches::kDisableAltWinstation
);
492 if (sandbox::SBOX_ALL_OK
!= policy
->SetAlternateDesktop(use_winsta
)) {
493 DLOG(WARNING
) << "Failed to apply desktop security to the renderer";
496 AddGenericDllEvictionPolicy(policy
);
501 // The Pepper process as locked-down as a renderer execpt that it can
502 // create the server side of chrome pipes.
503 bool AddPolicyForPepperPlugin(sandbox::TargetPolicy
* policy
) {
504 sandbox::ResultCode result
;
505 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES
,
506 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY
,
507 L
"\\\\.\\pipe\\chrome.*");
508 return result
== sandbox::SBOX_ALL_OK
;
511 // This code is test only, and attempts to catch unsafe uses of
512 // DuplicateHandle() that copy privileged handles into sandboxed processes.
513 #ifndef OFFICIAL_BUILD
514 base::win::IATPatchFunction g_iat_patch_duplicate_handle
;
516 BOOL (WINAPI
*g_iat_orig_duplicate_handle
)(HANDLE source_process_handle
,
517 HANDLE source_handle
,
518 HANDLE target_process_handle
,
519 LPHANDLE target_handle
,
520 DWORD desired_access
,
524 NtQueryObject g_QueryObject
= NULL
;
526 static const char* kDuplicateHandleWarning
=
527 "You are attempting to duplicate a privileged handle into a sandboxed"
528 " process.\n Please use the sandbox::BrokerDuplicateHandle API or"
529 " contact security@chromium.org for assistance.";
531 void CheckDuplicateHandle(HANDLE handle
) {
532 // Get the object type (32 characters is safe; current max is 14).
533 BYTE buffer
[sizeof(OBJECT_TYPE_INFORMATION
) + 32 * sizeof(wchar_t)];
534 OBJECT_TYPE_INFORMATION
* type_info
=
535 reinterpret_cast<OBJECT_TYPE_INFORMATION
*>(buffer
);
536 ULONG size
= sizeof(buffer
) - sizeof(wchar_t);
538 error
= g_QueryObject(handle
, ObjectTypeInformation
, type_info
, size
, &size
);
539 CHECK(NT_SUCCESS(error
));
540 type_info
->Name
.Buffer
[type_info
->Name
.Length
/ sizeof(wchar_t)] = L
'\0';
542 // Get the object basic information.
543 OBJECT_BASIC_INFORMATION basic_info
;
544 size
= sizeof(basic_info
);
545 error
= g_QueryObject(handle
, ObjectBasicInformation
, &basic_info
, size
,
547 CHECK(NT_SUCCESS(error
));
549 if (0 == _wcsicmp(type_info
->Name
.Buffer
, L
"Process")) {
550 const ACCESS_MASK kDangerousMask
= ~(PROCESS_QUERY_LIMITED_INFORMATION
|
552 CHECK(!(basic_info
.GrantedAccess
& kDangerousMask
)) <<
553 kDuplicateHandleWarning
;
557 BOOL WINAPI
DuplicateHandlePatch(HANDLE source_process_handle
,
558 HANDLE source_handle
,
559 HANDLE target_process_handle
,
560 LPHANDLE target_handle
,
561 DWORD desired_access
,
564 // Duplicate the handle so we get the final access mask.
565 if (!g_iat_orig_duplicate_handle(source_process_handle
, source_handle
,
566 target_process_handle
, target_handle
,
567 desired_access
, inherit_handle
, options
))
570 // We're not worried about broker handles or not crossing process boundaries.
571 if (source_process_handle
== target_process_handle
||
572 target_process_handle
== ::GetCurrentProcess())
575 // Only sandboxed children are placed in jobs, so just check them.
576 BOOL is_in_job
= FALSE
;
577 if (!::IsProcessInJob(target_process_handle
, NULL
, &is_in_job
)) {
578 // We need a handle with permission to check the job object.
579 if (ERROR_ACCESS_DENIED
== ::GetLastError()) {
580 base::win::ScopedHandle process
;
581 CHECK(g_iat_orig_duplicate_handle(::GetCurrentProcess(),
582 target_process_handle
,
583 ::GetCurrentProcess(),
585 PROCESS_QUERY_INFORMATION
,
587 CHECK(::IsProcessInJob(process
, NULL
, &is_in_job
));
592 // We never allow inheritable child handles.
593 CHECK(!inherit_handle
) << kDuplicateHandleWarning
;
595 // Duplicate the handle again, to get the final permissions.
596 base::win::ScopedHandle handle
;
597 CHECK(g_iat_orig_duplicate_handle(target_process_handle
, *target_handle
,
598 ::GetCurrentProcess(), handle
.Receive(),
599 0, FALSE
, DUPLICATE_SAME_ACCESS
));
601 // Callers use CHECK macro to make sure we get the right stack.
602 CheckDuplicateHandle(handle
);
613 bool InitBrokerServices(sandbox::BrokerServices
* broker_services
) {
614 // TODO(abarth): DCHECK(CalledOnValidThread());
615 // See <http://b/1287166>.
616 DCHECK(broker_services
);
617 DCHECK(!g_broker_services
);
618 sandbox::ResultCode result
= broker_services
->Init();
619 g_broker_services
= broker_services
;
621 // In non-official builds warn about dangerous uses of DuplicateHandle.
622 BOOL is_in_job
= FALSE
;
624 CHECK(::IsProcessInJob(::GetCurrentProcess(), NULL
, &is_in_job
));
626 #ifndef OFFICIAL_BUILD
627 if (!is_in_job
&& !g_iat_patch_duplicate_handle
.is_patched()) {
628 HMODULE module
= NULL
;
629 wchar_t module_name
[MAX_PATH
];
630 CHECK(::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
,
631 reinterpret_cast<LPCWSTR
>(InitBrokerServices
),
633 DWORD result
= ::GetModuleFileNameW(module
, module_name
, MAX_PATH
);
634 if (result
&& (result
!= MAX_PATH
)) {
635 ResolveNTFunctionPtr("NtQueryObject", &g_QueryObject
);
636 g_iat_orig_duplicate_handle
= ::DuplicateHandle
;
637 g_iat_patch_duplicate_handle
.Patch(
638 module_name
, "kernel32.dll", "DuplicateHandle",
639 DuplicateHandlePatch
);
644 return sandbox::SBOX_ALL_OK
== result
;
647 bool InitTargetServices(sandbox::TargetServices
* target_services
) {
648 DCHECK(target_services
);
649 DCHECK(!g_target_services
);
650 sandbox::ResultCode result
= target_services
->Init();
651 g_target_services
= target_services
;
652 return sandbox::SBOX_ALL_OK
== result
;
655 base::ProcessHandle
StartProcessWithAccess(CommandLine
* cmd_line
,
656 const FilePath
& exposed_dir
) {
657 const CommandLine
& browser_command_line
= *CommandLine::ForCurrentProcess();
659 std::string type_str
= cmd_line
->GetSwitchValueASCII(switches::kProcessType
);
660 if (type_str
== switches::kRendererProcess
) {
661 type
= PROCESS_TYPE_RENDERER
;
662 } else if (type_str
== switches::kPluginProcess
) {
663 type
= PROCESS_TYPE_PLUGIN
;
664 } else if (type_str
== switches::kWorkerProcess
) {
665 type
= PROCESS_TYPE_WORKER
;
666 } else if (type_str
== switches::kNaClLoaderProcess
) {
667 type
= PROCESS_TYPE_NACL_LOADER
;
668 } else if (type_str
== switches::kUtilityProcess
) {
669 type
= PROCESS_TYPE_UTILITY
;
670 } else if (type_str
== switches::kNaClBrokerProcess
) {
671 type
= PROCESS_TYPE_NACL_BROKER
;
672 } else if (type_str
== switches::kGpuProcess
) {
673 type
= PROCESS_TYPE_GPU
;
674 } else if (type_str
== switches::kPpapiPluginProcess
) {
675 type
= PROCESS_TYPE_PPAPI_PLUGIN
;
676 } else if (type_str
== switches::kPpapiBrokerProcess
) {
677 type
= PROCESS_TYPE_PPAPI_BROKER
;
683 TRACE_EVENT_BEGIN_ETW("StartProcessWithAccess", 0, type_str
);
685 // To decide if the process is going to be sandboxed we have two cases.
686 // First case: all process types except the nacl broker, and the plugin
687 // process are sandboxed by default.
689 (type
!= PROCESS_TYPE_NACL_BROKER
) &&
690 (type
!= PROCESS_TYPE_PLUGIN
) &&
691 (type
!= PROCESS_TYPE_PPAPI_BROKER
);
693 // If it is the GPU process then it can be disabled by a command line flag.
694 if ((type
== PROCESS_TYPE_GPU
) &&
695 (cmd_line
->HasSwitch(switches::kDisableGpuSandbox
))) {
697 DVLOG(1) << "GPU sandbox is disabled";
700 if (browser_command_line
.HasSwitch(switches::kNoSandbox
) ||
701 cmd_line
->HasSwitch(switches::kNoSandbox
)) {
702 // The user or the caller has explicity opted-out from all sandboxing.
706 #if !defined (GOOGLE_CHROME_BUILD)
707 if (browser_command_line
.HasSwitch(switches::kInProcessPlugins
)) {
708 // In process plugins won't work if the sandbox is enabled.
712 if (!browser_command_line
.HasSwitch(switches::kDisable3DAPIs
) &&
713 !browser_command_line
.HasSwitch(switches::kDisableExperimentalWebGL
) &&
714 browser_command_line
.HasSwitch(switches::kInProcessWebGL
)) {
715 // In process WebGL won't work if the sandbox is enabled.
719 // Propagate the Chrome Frame flag to sandboxed processes if present.
720 if (browser_command_line
.HasSwitch(switches::kChromeFrame
)) {
721 if (!cmd_line
->HasSwitch(switches::kChromeFrame
)) {
722 cmd_line
->AppendSwitch(switches::kChromeFrame
);
726 // Propagate the --allow-no-job flag if present.
727 if (browser_command_line
.HasSwitch(switches::kAllowNoSandboxJob
) &&
728 !cmd_line
->HasSwitch(switches::kAllowNoSandboxJob
)) {
729 cmd_line
->AppendSwitch(switches::kAllowNoSandboxJob
);
732 bool child_needs_help
= ProcessDebugFlags(cmd_line
, type
, in_sandbox
);
734 // Prefetch hints on windows:
735 // Using a different prefetch profile per process type will allow Windows
736 // to create separate pretetch settings for browser, renderer etc.
737 cmd_line
->AppendArg(base::StringPrintf("/prefetch:%d", type
));
740 base::ProcessHandle process
= 0;
741 base::LaunchProcess(*cmd_line
, base::LaunchOptions(), &process
);
742 g_broker_services
->AddTargetPeer(process
);
746 base::win::ScopedProcessInformation target
;
747 sandbox::TargetPolicy
* policy
= g_broker_services
->CreatePolicy();
749 // TODO(jschuh): Make NaCl work with DEP and SEHOP. crbug.com/147752
750 sandbox::MitigationFlags mitigations
= sandbox::MITIGATION_HEAP_TERMINATE
|
751 sandbox::MITIGATION_BOTTOM_UP_ASLR
;
752 #if !defined(NACL_WIN64)
753 // TODO(jschuh,bsy): Make NaCl work with HIGH_ENTROPY_ASLR. crbug.com/158133
754 mitigations
|= sandbox::MITIGATION_DEP
|
755 sandbox::MITIGATION_DEP_NO_ATL_THUNK
|
756 sandbox::MITIGATION_SEHOP
|
757 sandbox::MITIGATION_HIGH_ENTROPY_ASLR
;
759 mitigations
|= sandbox::MITIGATION_RELOCATE_IMAGE
|
760 sandbox::MITIGATION_RELOCATE_IMAGE_REQUIRED
;
764 if (policy
->SetProcessMitigations(mitigations
) != sandbox::SBOX_ALL_OK
)
767 mitigations
= sandbox::MITIGATION_STRICT_HANDLE_CHECKS
|
768 sandbox::MITIGATION_DLL_SEARCH_ORDER
;
769 #if defined(NACL_WIN64)
770 mitigations
|= sandbox::MITIGATION_DEP
|
771 sandbox::MITIGATION_DEP_NO_ATL_THUNK
;
774 if (policy
->SetDelayedProcessMitigations(mitigations
) != sandbox::SBOX_ALL_OK
)
777 SetJobLevel(*cmd_line
, sandbox::JOB_LOCKDOWN
, 0, policy
);
779 if (type
== PROCESS_TYPE_GPU
) {
780 if (!AddPolicyForGPU(cmd_line
, policy
))
783 if (!AddPolicyForRenderer(policy
))
785 // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper.
786 // Just have to figure out what needs to be warmed up first.
787 if (type
== PROCESS_TYPE_RENDERER
||
788 type
== PROCESS_TYPE_WORKER
) {
789 AddBaseHandleClosePolicy(policy
);
790 // Pepper uses the renderer's policy, whith some tweaks.
791 } else if (type
== PROCESS_TYPE_PPAPI_PLUGIN
) {
792 if (!AddPolicyForPepperPlugin(policy
))
797 if (type_str
!= switches::kRendererProcess
) {
798 // Hack for Google Desktop crash. Trick GD into not injecting its DLL into
799 // this subprocess. See
800 // http://code.google.com/p/chromium/issues/detail?id=25580
801 cmd_line
->AppendSwitchASCII("ignored", " --type=renderer ");
805 sandbox::ResultCode result
;
806 if (!exposed_dir
.empty()) {
807 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_FILES
,
808 sandbox::TargetPolicy::FILES_ALLOW_ANY
,
809 exposed_dir
.value().c_str());
810 if (result
!= sandbox::SBOX_ALL_OK
)
813 FilePath exposed_files
= exposed_dir
.AppendASCII("*");
814 result
= policy
->AddRule(sandbox::TargetPolicy::SUBSYS_FILES
,
815 sandbox::TargetPolicy::FILES_ALLOW_ANY
,
816 exposed_files
.value().c_str());
817 if (result
!= sandbox::SBOX_ALL_OK
)
821 if (!AddGenericPolicy(policy
)) {
826 TRACE_EVENT_BEGIN_ETW("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
828 result
= g_broker_services
->SpawnTarget(
829 cmd_line
->GetProgram().value().c_str(),
830 cmd_line
->GetCommandLineString().c_str(),
831 policy
, target
.Receive());
834 TRACE_EVENT_END_ETW("StartProcessWithAccess::LAUNCHPROCESS", 0, 0);
836 if (sandbox::SBOX_ALL_OK
!= result
) {
837 DLOG(ERROR
) << "Failed to launch process. Error: " << result
;
841 #if !defined(NACL_WIN64)
842 // For Native Client sel_ldr processes on 32-bit Windows, reserve 1 GB of
843 // address space to prevent later failure due to address space fragmentation
844 // from .dll loading. The NaCl process will attempt to locate this space by
845 // scanning the address space using VirtualQuery.
846 // TODO(bbudge) Handle the --no-sandbox case.
847 // http://code.google.com/p/nativeclient/issues/detail?id=2131
848 if (type
== PROCESS_TYPE_NACL_LOADER
) {
849 const SIZE_T kOneGigabyte
= 1 << 30;
850 void* nacl_mem
= VirtualAllocEx(target
.process_handle(),
856 DLOG(WARNING
) << "Failed to reserve address space for Native Client";
859 #endif // !defined(NACL_WIN64)
861 ResumeThread(target
.thread_handle());
863 // Help the process a little. It can't start the debugger by itself if
864 // the process is in a sandbox.
865 if (child_needs_help
)
866 base::debug::SpawnDebuggerOnProcess(target
.process_id());
868 return target
.TakeProcessHandle();
871 bool BrokerDuplicateHandle(HANDLE source_handle
,
872 DWORD target_process_id
,
873 HANDLE
* target_handle
,
874 DWORD desired_access
,
876 // If our process is the target just duplicate the handle.
877 if (::GetCurrentProcessId() == target_process_id
) {
878 return !!::DuplicateHandle(::GetCurrentProcess(), source_handle
,
879 ::GetCurrentProcess(), target_handle
,
880 desired_access
, FALSE
, options
);
884 // Try the broker next
885 if (g_target_services
&&
886 g_target_services
->DuplicateHandle(source_handle
, target_process_id
,
887 target_handle
, desired_access
,
888 options
) == sandbox::SBOX_ALL_OK
) {
892 // Finally, see if we already have access to the process.
893 base::win::ScopedHandle target_process
;
894 target_process
.Set(::OpenProcess(PROCESS_DUP_HANDLE
, FALSE
,
896 if (target_process
.IsValid()) {
897 return !!::DuplicateHandle(::GetCurrentProcess(), source_handle
,
898 target_process
, target_handle
,
899 desired_access
, FALSE
, options
);
905 bool BrokerAddTargetPeer(HANDLE peer_process
) {
906 return g_broker_services
->AddTargetPeer(peer_process
) == sandbox::SBOX_ALL_OK
;
909 } // namespace content