Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: content/common/sandbox_win.cc

Issue 1851213002: Remove sandbox on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix nacl compile issues Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/common/sandbox_win.h ('k') | content/content.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/common/sandbox_win.h" 5 #include "content/common/sandbox_win.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <string> 9 #include <string>
10 10
(...skipping 16 matching lines...) Expand all
27 #include "base/win/iat_patch_function.h" 27 #include "base/win/iat_patch_function.h"
28 #include "base/win/scoped_handle.h" 28 #include "base/win/scoped_handle.h"
29 #include "base/win/scoped_process_information.h" 29 #include "base/win/scoped_process_information.h"
30 #include "base/win/win_util.h" 30 #include "base/win/win_util.h"
31 #include "base/win/windows_version.h" 31 #include "base/win/windows_version.h"
32 #include "content/common/content_switches_internal.h" 32 #include "content/common/content_switches_internal.h"
33 #include "content/public/common/content_client.h" 33 #include "content/public/common/content_client.h"
34 #include "content/public/common/content_switches.h" 34 #include "content/public/common/content_switches.h"
35 #include "content/public/common/sandbox_init.h" 35 #include "content/public/common/sandbox_init.h"
36 #include "content/public/common/sandboxed_process_launcher_delegate.h" 36 #include "content/public/common/sandboxed_process_launcher_delegate.h"
37 #include "sandbox/win/src/process_mitigations.h"
38 #include "sandbox/win/src/sandbox.h"
39 #include "sandbox/win/src/sandbox_nt_util.h"
40 #include "sandbox/win/src/sandbox_policy_base.h"
41 #include "sandbox/win/src/win_utils.h"
42 37
43 #if !defined(NACL_WIN64) 38 #if !defined(NACL_WIN64)
44 #include "ui/gfx/win/direct_write.h" // nogncheck: unused #ifdef NACL_WIN64 39 #include "ui/gfx/win/direct_write.h" // nogncheck: unused #ifdef NACL_WIN64
45 #endif // !defined(NACL_WIN64) 40 #endif // !defined(NACL_WIN64)
46 41
47 static sandbox::BrokerServices* g_broker_services = NULL; 42 static void* g_broker_services = NULL;
48 static sandbox::TargetServices* g_target_services = NULL; 43 static void* g_target_services = NULL;
49 44
50 namespace content { 45 namespace content {
51 namespace { 46 namespace {
52 47
53 // The DLLs listed here are known (or under strong suspicion) of causing crashes
54 // when they are loaded in the renderer. Note: at runtime we generate short
55 // versions of the dll name only if the dll has an extension.
56 // For more information about how this list is generated, and how to get off
57 // of it, see:
58 // https://sites.google.com/a/chromium.org/dev/Home/third-party-developers
59 const wchar_t* const kTroublesomeDlls[] = {
60 L"adialhk.dll", // Kaspersky Internet Security.
61 L"acpiz.dll", // Unknown.
62 L"activedetect32.dll", // Lenovo One Key Theater (crbug.com/536056).
63 L"activedetect64.dll", // Lenovo One Key Theater (crbug.com/536056).
64 L"airfoilinject3.dll", // Airfoil.
65 L"akinsofthook32.dll", // Akinsoft Software Engineering.
66 L"assistant_x64.dll", // Unknown.
67 L"avcuf64.dll", // Bit Defender Internet Security x64.
68 L"avgrsstx.dll", // AVG 8.
69 L"babylonchromepi.dll", // Babylon translator.
70 L"btkeyind.dll", // Widcomm Bluetooth.
71 L"cmcsyshk.dll", // CMC Internet Security.
72 L"cmsetac.dll", // Unknown (suspected malware).
73 L"cooliris.dll", // CoolIris.
74 L"cplushook.dll", // Unknown (suspected malware).
75 L"dockshellhook.dll", // Stardock Objectdock.
76 L"easyhook32.dll", // GDIPP and others.
77 L"esspd.dll", // Samsung Smart Security ESCORT.
78 L"googledesktopnetwork3.dll", // Google Desktop Search v5.
79 L"fwhook.dll", // PC Tools Firewall Plus.
80 L"hookprocesscreation.dll", // Blumentals Program protector.
81 L"hookterminateapis.dll", // Blumentals and Cyberprinter.
82 L"hookprintapis.dll", // Cyberprinter.
83 L"imon.dll", // NOD32 Antivirus.
84 L"icatcdll.dll", // Samsung Smart Security ESCORT.
85 L"icdcnl.dll", // Samsung Smart Security ESCORT.
86 L"ioloHL.dll", // Iolo (System Mechanic).
87 L"kloehk.dll", // Kaspersky Internet Security.
88 L"lawenforcer.dll", // Spyware-Browser AntiSpyware (Spybro).
89 L"libdivx.dll", // DivX.
90 L"lvprcinj01.dll", // Logitech QuickCam.
91 L"madchook.dll", // Madshi (generic hooking library).
92 L"mdnsnsp.dll", // Bonjour.
93 L"moonsysh.dll", // Moon Secure Antivirus.
94 L"mpk.dll", // KGB Spy.
95 L"npdivx32.dll", // DivX.
96 L"npggNT.des", // GameGuard 2008.
97 L"npggNT.dll", // GameGuard (older).
98 L"oawatch.dll", // Online Armor.
99 L"pastali32.dll", // PastaLeads.
100 L"pavhook.dll", // Panda Internet Security.
101 L"pavlsphook.dll", // Panda Antivirus.
102 L"pavshook.dll", // Panda Antivirus.
103 L"pavshookwow.dll", // Panda Antivirus.
104 L"pctavhook.dll", // PC Tools Antivirus.
105 L"pctgmhk.dll", // PC Tools Spyware Doctor.
106 L"picrmi32.dll", // PicRec.
107 L"picrmi64.dll", // PicRec.
108 L"prntrack.dll", // Pharos Systems.
109 L"protector.dll", // Unknown (suspected malware).
110 L"radhslib.dll", // Radiant Naomi Internet Filter.
111 L"radprlib.dll", // Radiant Naomi Internet Filter.
112 L"rapportnikko.dll", // Trustware Rapport.
113 L"rlhook.dll", // Trustware Bufferzone.
114 L"rooksdol.dll", // Trustware Rapport.
115 L"rndlpepperbrowserrecordhelper.dll", // RealPlayer.
116 L"rpchromebrowserrecordhelper.dll", // RealPlayer.
117 L"r3hook.dll", // Kaspersky Internet Security.
118 L"sahook.dll", // McAfee Site Advisor.
119 L"sbrige.dll", // Unknown.
120 L"sc2hook.dll", // Supercopier 2.
121 L"sdhook32.dll", // Spybot - Search & Destroy Live Protection.
122 L"sguard.dll", // Iolo (System Guard).
123 L"smum32.dll", // Spyware Doctor version 6.
124 L"smumhook.dll", // Spyware Doctor version 5.
125 L"ssldivx.dll", // DivX.
126 L"syncor11.dll", // SynthCore Midi interface.
127 L"systools.dll", // Panda Antivirus.
128 L"tfwah.dll", // Threatfire (PC tools).
129 L"wblind.dll", // Stardock Object desktop.
130 L"wbhelp.dll", // Stardock Object desktop.
131 L"windowsapihookdll32.dll", // Lenovo One Key Theater (crbug.com/536056).
132 L"windowsapihookdll64.dll", // Lenovo One Key Theater (crbug.com/536056).
133 L"winstylerthemehelper.dll" // Tuneup utilities 2006.
134 };
135
136 #if !defined(NACL_WIN64)
137 // Adds the policy rules for the path and path\ with the semantic |access|.
138 // If |children| is set to true, we need to add the wildcard rules to also
139 // apply the rule to the subfiles and subfolders.
140 bool AddDirectory(int path, const wchar_t* sub_dir, bool children,
141 sandbox::TargetPolicy::Semantics access,
142 sandbox::TargetPolicy* policy) {
143 base::FilePath directory;
144 if (!PathService::Get(path, &directory))
145 return false;
146
147 if (sub_dir)
148 directory = base::MakeAbsoluteFilePath(directory.Append(sub_dir));
149
150 sandbox::ResultCode result;
151 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
152 directory.value().c_str());
153 if (result != sandbox::SBOX_ALL_OK)
154 return false;
155
156 std::wstring directory_str = directory.value() + L"\\";
157 if (children)
158 directory_str += L"*";
159 // Otherwise, add the version of the path that ends with a separator.
160
161 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
162 directory_str.c_str());
163 if (result != sandbox::SBOX_ALL_OK)
164 return false;
165
166 return true;
167 }
168 #endif // !defined(NACL_WIN64)
169
170 // Compares the loaded |module| file name matches |module_name|.
171 bool IsExpandedModuleName(HMODULE module, const wchar_t* module_name) {
172 wchar_t path[MAX_PATH];
173 DWORD sz = ::GetModuleFileNameW(module, path, arraysize(path));
174 if ((sz == arraysize(path)) || (sz == 0)) {
175 // XP does not set the last error properly, so we bail out anyway.
176 return false;
177 }
178 if (!::GetLongPathName(path, path, arraysize(path)))
179 return false;
180 base::FilePath fname(path);
181 return (fname.BaseName().value() == module_name);
182 }
183
184 // Adds a single dll by |module_name| into the |policy| blacklist.
185 // If |check_in_browser| is true we only add an unload policy only if the dll
186 // is also loaded in this process.
187 void BlacklistAddOneDll(const wchar_t* module_name,
188 bool check_in_browser,
189 sandbox::TargetPolicy* policy) {
190 HMODULE module = check_in_browser ? ::GetModuleHandleW(module_name) : NULL;
191 if (!module) {
192 // The module could have been loaded with a 8.3 short name. We check
193 // the three most common cases: 'thelongname.dll' becomes
194 // 'thelon~1.dll', 'thelon~2.dll' and 'thelon~3.dll'.
195 std::wstring name(module_name);
196 size_t period = name.rfind(L'.');
197 DCHECK_NE(std::string::npos, period);
198 DCHECK_LE(3U, (name.size() - period));
199 if (period <= 8)
200 return;
201 for (wchar_t ix = '1'; ix <= '3'; ++ix) {
202 const wchar_t suffix[] = {'~', ix, 0};
203 std::wstring alt_name = name.substr(0, 6) + suffix;
204 alt_name += name.substr(period, name.size());
205 if (check_in_browser) {
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 }
214 // Found a match. We add both forms to the policy.
215 policy->AddDllToUnload(alt_name.c_str());
216 }
217 }
218 policy->AddDllToUnload(module_name);
219 DVLOG(1) << "dll to unload found: " << module_name;
220 return;
221 }
222
223 // Adds policy rules for unloaded the known dlls that cause chrome to crash.
224 // Eviction of injected DLLs is done by the sandbox so that the injected module
225 // does not get a chance to execute any code.
226 void AddGenericDllEvictionPolicy(sandbox::TargetPolicy* policy) {
227 for (int ix = 0; ix != arraysize(kTroublesomeDlls); ++ix)
228 BlacklistAddOneDll(kTroublesomeDlls[ix], true, policy);
229 }
230
231 // Returns the object path prepended with the current logon session.
232 base::string16 PrependWindowsSessionPath(const base::char16* object) {
233 // Cache this because it can't change after process creation.
234 static DWORD s_session_id = 0;
235 if (s_session_id == 0) {
236 HANDLE token;
237 DWORD session_id_length;
238 DWORD session_id = 0;
239
240 CHECK(::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token));
241 CHECK(::GetTokenInformation(token, TokenSessionId, &session_id,
242 sizeof(session_id), &session_id_length));
243 CloseHandle(token);
244 if (session_id)
245 s_session_id = session_id;
246 }
247
248 return base::StringPrintf(L"\\Sessions\\%lu%ls", s_session_id, object);
249 }
250
251 // Checks if the sandbox should be let to run without a job object assigned.
252 bool ShouldSetJobLevel(const base::CommandLine& cmd_line) {
253 if (!cmd_line.HasSwitch(switches::kAllowNoSandboxJob))
254 return true;
255
256 // Windows 8 allows nested jobs so we don't need to check if we are in other
257 // job.
258 if (base::win::GetVersion() >= base::win::VERSION_WIN8)
259 return true;
260
261 BOOL in_job = true;
262 // Either there is no job yet associated so we must add our job,
263 if (!::IsProcessInJob(::GetCurrentProcess(), NULL, &in_job))
264 NOTREACHED() << "IsProcessInJob failed. " << GetLastError();
265 if (!in_job)
266 return true;
267
268 // ...or there is a job but the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit is set.
269 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {};
270 if (!::QueryInformationJobObject(NULL,
271 JobObjectExtendedLimitInformation, &job_info,
272 sizeof(job_info), NULL)) {
273 NOTREACHED() << "QueryInformationJobObject failed. " << GetLastError();
274 return true;
275 }
276 if (job_info.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)
277 return true;
278
279 return false;
280 }
281
282 // Adds the generic policy rules to a sandbox TargetPolicy.
283 bool AddGenericPolicy(sandbox::TargetPolicy* policy) {
284 sandbox::ResultCode result;
285
286 // Renderers need to copy sections for plugin DIBs and GPU.
287 // GPU needs to copy sections to renderers.
288 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
289 sandbox::TargetPolicy::HANDLES_DUP_ANY,
290 L"Section");
291 if (result != sandbox::SBOX_ALL_OK)
292 return false;
293
294 // Add the policy for the client side of a pipe. It is just a file
295 // in the \pipe\ namespace. We restrict it to pipes that start with
296 // "chrome." so the sandboxed process cannot connect to system services.
297 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
298 sandbox::TargetPolicy::FILES_ALLOW_ANY,
299 L"\\??\\pipe\\chrome.*");
300 if (result != sandbox::SBOX_ALL_OK)
301 return false;
302
303 // Add the policy for the server side of nacl pipe. It is just a file
304 // in the \pipe\ namespace. We restrict it to pipes that start with
305 // "chrome.nacl" so the sandboxed process cannot connect to
306 // system services.
307 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
308 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
309 L"\\\\.\\pipe\\chrome.nacl.*");
310 if (result != sandbox::SBOX_ALL_OK)
311 return false;
312
313 // Allow the server side of sync sockets, which are pipes that have
314 // the "chrome.sync" namespace and a randomly generated suffix.
315 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
316 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
317 L"\\\\.\\pipe\\chrome.sync.*");
318 if (result != sandbox::SBOX_ALL_OK)
319 return false;
320
321 // Add the policy for debug message only in debug
322 #ifndef NDEBUG
323 base::FilePath app_dir;
324 if (!PathService::Get(base::DIR_MODULE, &app_dir))
325 return false;
326
327 wchar_t long_path_buf[MAX_PATH];
328 DWORD long_path_return_value = GetLongPathName(app_dir.value().c_str(),
329 long_path_buf,
330 MAX_PATH);
331 if (long_path_return_value == 0 || long_path_return_value >= MAX_PATH)
332 return false;
333
334 base::FilePath debug_message(long_path_buf);
335 debug_message = debug_message.AppendASCII("debug_message.exe");
336 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS,
337 sandbox::TargetPolicy::PROCESS_MIN_EXEC,
338 debug_message.value().c_str());
339 if (result != sandbox::SBOX_ALL_OK)
340 return false;
341 #endif // NDEBUG
342
343 // Add the policy for read-only PDB file access for stack traces.
344 #if !defined(OFFICIAL_BUILD)
345 base::FilePath exe;
346 if (!PathService::Get(base::FILE_EXE, &exe))
347 return false;
348 base::FilePath pdb_path = exe.DirName().Append(L"*.pdb");
349 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
350 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
351 pdb_path.value().c_str());
352 if (result != sandbox::SBOX_ALL_OK)
353 return false;
354 #endif
355
356 #if defined(SANITIZER_COVERAGE)
357 DWORD coverage_dir_size =
358 ::GetEnvironmentVariable(L"SANITIZER_COVERAGE_DIR", NULL, 0);
359 if (coverage_dir_size == 0) {
360 LOG(WARNING) << "SANITIZER_COVERAGE_DIR was not set, coverage won't work.";
361 } else {
362 std::wstring coverage_dir;
363 wchar_t* coverage_dir_str =
364 base::WriteInto(&coverage_dir, coverage_dir_size);
365 coverage_dir_size = ::GetEnvironmentVariable(
366 L"SANITIZER_COVERAGE_DIR", coverage_dir_str, coverage_dir_size);
367 CHECK(coverage_dir.size() == coverage_dir_size);
368 base::FilePath sancov_path =
369 base::FilePath(coverage_dir).Append(L"*.sancov");
370 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
371 sandbox::TargetPolicy::FILES_ALLOW_ANY,
372 sancov_path.value().c_str());
373 if (result != sandbox::SBOX_ALL_OK)
374 return false;
375 }
376 #endif
377
378 AddGenericDllEvictionPolicy(policy);
379 return true;
380 }
381
382 bool AddPolicyForSandboxedProcess(sandbox::TargetPolicy* policy) {
383 sandbox::ResultCode result;
384 // Renderers need to share events with plugins.
385 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
386 sandbox::TargetPolicy::HANDLES_DUP_ANY,
387 L"Event");
388 if (result != sandbox::SBOX_ALL_OK)
389 return false;
390
391 // Win8+ adds a device DeviceApi that we don't need.
392 if (base::win::GetVersion() > base::win::VERSION_WIN7)
393 result = policy->AddKernelObjectToClose(L"File", L"\\Device\\DeviceApi");
394 if (result != sandbox::SBOX_ALL_OK)
395 return false;
396
397 // Close the proxy settings on XP.
398 if (base::win::GetVersion() <= base::win::VERSION_SERVER_2003)
399 result = policy->AddKernelObjectToClose(L"Key",
400 L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\" \
401 L"CurrentVersion\\Internet Settings");
402 if (result != sandbox::SBOX_ALL_OK)
403 return false;
404
405 sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED;
406 if (base::win::GetVersion() > base::win::VERSION_XP) {
407 // On 2003/Vista the initial token has to be restricted if the main
408 // token is restricted.
409 initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS;
410 }
411
412 policy->SetTokenLevel(initial_token, sandbox::USER_LOCKDOWN);
413 // Prevents the renderers from manipulating low-integrity processes.
414 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
415 policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
416 policy->SetLockdownDefaultDacl();
417
418 if (sandbox::SBOX_ALL_OK != policy->SetAlternateDesktop(true)) {
419 DLOG(WARNING) << "Failed to apply desktop security to the renderer";
420 }
421
422 return true;
423 }
424
425 // Updates the command line arguments with debug-related flags. If debug flags 48 // Updates the command line arguments with debug-related flags. If debug flags
426 // have been used with this process, they will be filtered and added to 49 // have been used with this process, they will be filtered and added to
427 // command_line as needed. 50 // command_line as needed.
428 void ProcessDebugFlags(base::CommandLine* command_line) { 51 void ProcessDebugFlags(base::CommandLine* command_line) {
429 const base::CommandLine& current_cmd_line = 52 const base::CommandLine& current_cmd_line =
430 *base::CommandLine::ForCurrentProcess(); 53 *base::CommandLine::ForCurrentProcess();
431 std::string type = command_line->GetSwitchValueASCII(switches::kProcessType); 54 std::string type = command_line->GetSwitchValueASCII(switches::kProcessType);
432 if (current_cmd_line.HasSwitch(switches::kWaitForDebuggerChildren)) { 55 if (current_cmd_line.HasSwitch(switches::kWaitForDebuggerChildren)) {
433 // Look to pass-on the kWaitForDebugger flag. 56 // Look to pass-on the kWaitForDebugger flag.
434 std::string value = current_cmd_line.GetSwitchValueASCII( 57 std::string value = current_cmd_line.GetSwitchValueASCII(
435 switches::kWaitForDebuggerChildren); 58 switches::kWaitForDebuggerChildren);
436 if (value.empty() || value == type) { 59 if (value.empty() || value == type) {
437 command_line->AppendSwitch(switches::kWaitForDebugger); 60 command_line->AppendSwitch(switches::kWaitForDebugger);
438 } 61 }
439 command_line->AppendSwitchASCII(switches::kWaitForDebuggerChildren, value); 62 command_line->AppendSwitchASCII(switches::kWaitForDebuggerChildren, value);
440 } 63 }
441 } 64 }
442 65
443 // This code is test only, and attempts to catch unsafe uses of
444 // DuplicateHandle() that copy privileged handles into sandboxed processes.
445 #ifndef OFFICIAL_BUILD
446 base::win::IATPatchFunction g_iat_patch_duplicate_handle;
447
448 typedef BOOL (WINAPI *DuplicateHandleFunctionPtr)(HANDLE source_process_handle,
449 HANDLE source_handle,
450 HANDLE target_process_handle,
451 LPHANDLE target_handle,
452 DWORD desired_access,
453 BOOL inherit_handle,
454 DWORD options);
455
456 DuplicateHandleFunctionPtr g_iat_orig_duplicate_handle;
457
458 NtQueryObject g_QueryObject = NULL;
459
460 static const char* kDuplicateHandleWarning =
461 "You are attempting to duplicate a privileged handle into a sandboxed"
462 " process.\n Please use the sandbox::BrokerDuplicateHandle API or"
463 " contact security@chromium.org for assistance.";
464
465 void CheckDuplicateHandle(HANDLE handle) {
466 // Get the object type (32 characters is safe; current max is 14).
467 BYTE buffer[sizeof(OBJECT_TYPE_INFORMATION) + 32 * sizeof(wchar_t)];
468 OBJECT_TYPE_INFORMATION* type_info =
469 reinterpret_cast<OBJECT_TYPE_INFORMATION*>(buffer);
470 ULONG size = sizeof(buffer) - sizeof(wchar_t);
471 NTSTATUS error;
472 error = g_QueryObject(handle, ObjectTypeInformation, type_info, size, &size);
473 CHECK(NT_SUCCESS(error));
474 type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
475
476 // Get the object basic information.
477 OBJECT_BASIC_INFORMATION basic_info;
478 size = sizeof(basic_info);
479 error = g_QueryObject(handle, ObjectBasicInformation, &basic_info, size,
480 &size);
481 CHECK(NT_SUCCESS(error));
482
483 CHECK(!(basic_info.GrantedAccess & WRITE_DAC)) <<
484 kDuplicateHandleWarning;
485
486 if (0 == _wcsicmp(type_info->Name.Buffer, L"Process")) {
487 const ACCESS_MASK kDangerousMask =
488 ~static_cast<DWORD>(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE);
489 CHECK(!(basic_info.GrantedAccess & kDangerousMask)) <<
490 kDuplicateHandleWarning;
491 }
492 }
493
494 BOOL WINAPI DuplicateHandlePatch(HANDLE source_process_handle,
495 HANDLE source_handle,
496 HANDLE target_process_handle,
497 LPHANDLE target_handle,
498 DWORD desired_access,
499 BOOL inherit_handle,
500 DWORD options) {
501 // Duplicate the handle so we get the final access mask.
502 if (!g_iat_orig_duplicate_handle(source_process_handle, source_handle,
503 target_process_handle, target_handle,
504 desired_access, inherit_handle, options))
505 return FALSE;
506
507 // We're not worried about broker handles or not crossing process boundaries.
508 if (source_process_handle == target_process_handle ||
509 target_process_handle == ::GetCurrentProcess())
510 return TRUE;
511
512 // Only sandboxed children are placed in jobs, so just check them.
513 BOOL is_in_job = FALSE;
514 if (!::IsProcessInJob(target_process_handle, NULL, &is_in_job)) {
515 // We need a handle with permission to check the job object.
516 if (ERROR_ACCESS_DENIED == ::GetLastError()) {
517 HANDLE temp_handle;
518 CHECK(g_iat_orig_duplicate_handle(::GetCurrentProcess(),
519 target_process_handle,
520 ::GetCurrentProcess(),
521 &temp_handle,
522 PROCESS_QUERY_INFORMATION,
523 FALSE, 0));
524 base::win::ScopedHandle process(temp_handle);
525 CHECK(::IsProcessInJob(process.Get(), NULL, &is_in_job));
526 }
527 }
528
529 if (is_in_job) {
530 // We never allow inheritable child handles.
531 CHECK(!inherit_handle) << kDuplicateHandleWarning;
532
533 // Duplicate the handle again, to get the final permissions.
534 HANDLE temp_handle;
535 CHECK(g_iat_orig_duplicate_handle(target_process_handle, *target_handle,
536 ::GetCurrentProcess(), &temp_handle,
537 0, FALSE, DUPLICATE_SAME_ACCESS));
538 base::win::ScopedHandle handle(temp_handle);
539
540 // Callers use CHECK macro to make sure we get the right stack.
541 CheckDuplicateHandle(handle.Get());
542 }
543
544 return TRUE;
545 }
546 #endif
547
548 bool IsAppContainerEnabled() {
549 if (base::win::GetVersion() < base::win::VERSION_WIN8)
550 return false;
551 const base::CommandLine& command_line =
552 *base::CommandLine::ForCurrentProcess();
553 const std::string appcontainer_group_name =
554 base::FieldTrialList::FindFullName("EnableAppContainer");
555 if (command_line.HasSwitch(switches::kDisableAppContainer))
556 return false;
557 if (command_line.HasSwitch(switches::kEnableAppContainer))
558 return true;
559 return base::StartsWith(appcontainer_group_name, "Enabled",
560 base::CompareCase::INSENSITIVE_ASCII);
561 }
562
563 } // namespace 66 } // namespace
564 67
565 void SetJobLevel(const base::CommandLine& cmd_line,
566 sandbox::JobLevel job_level,
567 uint32_t ui_exceptions,
568 sandbox::TargetPolicy* policy) {
569 if (ShouldSetJobLevel(cmd_line)) {
570 #ifdef _WIN64
571 policy->SetJobMemoryLimit(4ULL * 1024 * 1024 * 1024);
572 #endif
573 policy->SetJobLevel(job_level, ui_exceptions);
574 } else {
575 policy->SetJobLevel(sandbox::JOB_NONE, 0);
576 }
577 }
578
579 // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper.
580 // Just have to figure out what needs to be warmed up first.
581 void AddBaseHandleClosePolicy(sandbox::TargetPolicy* policy) {
582 // TODO(cpu): Add back the BaseNamedObjects policy.
583 base::string16 object_path = PrependWindowsSessionPath(
584 L"\\BaseNamedObjects\\windows_shell_global_counters");
585 policy->AddKernelObjectToClose(L"Section", object_path.data());
586 }
587
588 void AddAppContainerPolicy(sandbox::TargetPolicy* policy, const wchar_t* sid) {
589 if (IsAppContainerEnabled())
590 policy->SetLowBox(sid);
591 }
592
593 bool AddWin32kLockdownPolicy(sandbox::TargetPolicy* policy) {
594 #if !defined(NACL_WIN64)
595 if (!IsWin32kRendererLockdownEnabled())
596 return true;
597
598 // Enable win32k lockdown if not already.
599 sandbox::MitigationFlags flags = policy->GetProcessMitigations();
600 if ((flags & sandbox::MITIGATION_WIN32K_DISABLE) ==
601 sandbox::MITIGATION_WIN32K_DISABLE)
602 return true;
603
604 sandbox::ResultCode result =
605 policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
606 sandbox::TargetPolicy::FAKE_USER_GDI_INIT, nullptr);
607 if (result != sandbox::SBOX_ALL_OK)
608 return false;
609
610 flags |= sandbox::MITIGATION_WIN32K_DISABLE;
611 result = policy->SetProcessMitigations(flags);
612 if (result != sandbox::SBOX_ALL_OK)
613 return false;
614 #endif
615 return true;
616 }
617
618 bool InitBrokerServices(sandbox::BrokerServices* broker_services) {
619 // TODO(abarth): DCHECK(CalledOnValidThread());
620 // See <http://b/1287166>.
621 DCHECK(broker_services);
622 DCHECK(!g_broker_services);
623 sandbox::ResultCode result = broker_services->Init();
624 g_broker_services = broker_services;
625
626 // In non-official builds warn about dangerous uses of DuplicateHandle.
627 #ifndef OFFICIAL_BUILD
628 BOOL is_in_job = FALSE;
629 CHECK(::IsProcessInJob(::GetCurrentProcess(), NULL, &is_in_job));
630 // In a Syzygy-profiled binary, instrumented for import profiling, this
631 // patch will end in infinite recursion on the attempted delegation to the
632 // original function.
633 if (!base::debug::IsBinaryInstrumented() &&
634 !is_in_job && !g_iat_patch_duplicate_handle.is_patched()) {
635 HMODULE module = NULL;
636 wchar_t module_name[MAX_PATH];
637 CHECK(::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
638 reinterpret_cast<LPCWSTR>(InitBrokerServices),
639 &module));
640 DWORD result = ::GetModuleFileNameW(module, module_name, MAX_PATH);
641 if (result && (result != MAX_PATH)) {
642 ResolveNTFunctionPtr("NtQueryObject", &g_QueryObject);
643 result = g_iat_patch_duplicate_handle.Patch(
644 module_name, "kernel32.dll", "DuplicateHandle",
645 DuplicateHandlePatch);
646 CHECK(result == 0);
647 g_iat_orig_duplicate_handle =
648 reinterpret_cast<DuplicateHandleFunctionPtr>(
649 g_iat_patch_duplicate_handle.original_function());
650 }
651 }
652 #endif
653
654 return sandbox::SBOX_ALL_OK == result;
655 }
656
657 bool InitTargetServices(sandbox::TargetServices* target_services) {
658 DCHECK(target_services);
659 DCHECK(!g_target_services);
660 sandbox::ResultCode result = target_services->Init();
661 g_target_services = target_services;
662 return sandbox::SBOX_ALL_OK == result;
663 }
664 68
665 base::Process StartSandboxedProcess( 69 base::Process StartSandboxedProcess(
666 SandboxedProcessLauncherDelegate* delegate, 70 SandboxedProcessLauncherDelegate* delegate,
667 base::CommandLine* cmd_line, 71 base::CommandLine* cmd_line,
668 const base::HandlesToInheritVector& handles_to_inherit) { 72 const base::HandlesToInheritVector& handles_to_inherit) {
669 DCHECK(delegate); 73 DCHECK(delegate);
670 const base::CommandLine& browser_command_line = 74 const base::CommandLine& browser_command_line =
671 *base::CommandLine::ForCurrentProcess(); 75 *base::CommandLine::ForCurrentProcess();
672 std::string type_str = cmd_line->GetSwitchValueASCII(switches::kProcessType); 76 std::string type_str = cmd_line->GetSwitchValueASCII(switches::kProcessType);
673 77
674 TRACE_EVENT1("startup", "StartProcessWithAccess", "type", type_str); 78 TRACE_EVENT1("startup", "StartProcessWithAccess", "type", type_str);
675 79
676 // Propagate the --allow-no-job flag if present. 80 // Propagate the --allow-no-job flag if present.
677 if (browser_command_line.HasSwitch(switches::kAllowNoSandboxJob) && 81 if (browser_command_line.HasSwitch(switches::kAllowNoSandboxJob) &&
678 !cmd_line->HasSwitch(switches::kAllowNoSandboxJob)) { 82 !cmd_line->HasSwitch(switches::kAllowNoSandboxJob)) {
679 cmd_line->AppendSwitch(switches::kAllowNoSandboxJob); 83 cmd_line->AppendSwitch(switches::kAllowNoSandboxJob);
680 } 84 }
681 85
682 ProcessDebugFlags(cmd_line); 86 ProcessDebugFlags(cmd_line);
683 87
684 if ((!delegate->ShouldSandbox()) || 88 base::LaunchOptions options;
685 browser_command_line.HasSwitch(switches::kNoSandbox) ||
686 cmd_line->HasSwitch(switches::kNoSandbox)) {
687 base::LaunchOptions options;
688 89
689 base::HandlesToInheritVector handles = handles_to_inherit; 90 base::HandlesToInheritVector handles = handles_to_inherit;
690 if (!handles_to_inherit.empty()) { 91 if (!handles_to_inherit.empty()) {
691 options.inherit_handles = true; 92 options.inherit_handles = true;
692 options.handles_to_inherit = &handles; 93 options.handles_to_inherit = &handles;
693 }
694 base::Process process = base::LaunchProcess(*cmd_line, options);
695
696 // TODO(rvargas) crbug.com/417532: Don't share a raw handle.
697 g_broker_services->AddTargetPeer(process.Handle());
698 return process;
699 } 94 }
700 95
701 sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy(); 96 base::Process process = base::LaunchProcess(*cmd_line, options);
702 97
703 // Add any handles to be inherited to the policy. 98 return process;
704 for (HANDLE handle : handles_to_inherit)
705 policy->AddHandleToShare(handle);
706
707 // Pre-startup mitigations.
708 sandbox::MitigationFlags mitigations =
709 sandbox::MITIGATION_HEAP_TERMINATE |
710 sandbox::MITIGATION_BOTTOM_UP_ASLR |
711 sandbox::MITIGATION_DEP |
712 sandbox::MITIGATION_DEP_NO_ATL_THUNK |
713 sandbox::MITIGATION_SEHOP |
714 sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
715 sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
716 sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL;
717 #if !defined(NACL_WIN64)
718 // Don't block font loading with GDI.
719 if (!gfx::win::ShouldUseDirectWrite())
720 mitigations ^= sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE;
721 #endif
722
723 if (policy->SetProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK)
724 return base::Process();
725
726 #if !defined(NACL_WIN64)
727 if (type_str == switches::kRendererProcess &&
728 IsWin32kRendererLockdownEnabled()) {
729 if (!AddWin32kLockdownPolicy(policy))
730 return base::Process();
731 }
732 #endif
733
734 // Post-startup mitigations.
735 mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
736 sandbox::MITIGATION_DLL_SEARCH_ORDER;
737
738 if (policy->SetDelayedProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK)
739 return base::Process();
740
741 SetJobLevel(*cmd_line, sandbox::JOB_LOCKDOWN, 0, policy);
742
743 if (!delegate->DisableDefaultPolicy()) {
744 if (!AddPolicyForSandboxedProcess(policy))
745 return base::Process();
746 }
747
748 #if !defined(NACL_WIN64)
749 // NOTE: This is placed at function scope so that it stays alive through
750 // process launch.
751 base::SharedMemory direct_write_font_cache_section;
752 if (type_str == switches::kRendererProcess ||
753 type_str == switches::kPpapiPluginProcess) {
754 if (gfx::win::ShouldUseDirectWrite()) {
755 AddDirectory(base::DIR_WINDOWS_FONTS,
756 NULL,
757 true,
758 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
759 policy);
760 }
761 }
762 #endif
763
764 if (type_str != switches::kRendererProcess) {
765 // Hack for Google Desktop crash. Trick GD into not injecting its DLL into
766 // this subprocess. See
767 // http://code.google.com/p/chromium/issues/detail?id=25580
768 cmd_line->AppendSwitchASCII("ignored", " --type=renderer ");
769 }
770
771 if (!AddGenericPolicy(policy)) {
772 NOTREACHED();
773 return base::Process();
774 }
775
776 // Allow the renderer and gpu processes to access the log file.
777 if (type_str == switches::kRendererProcess ||
778 type_str == switches::kGpuProcess) {
779 if (logging::IsLoggingToFileEnabled()) {
780 DCHECK(base::FilePath(logging::GetLogFileFullPath()).IsAbsolute());
781 policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
782 sandbox::TargetPolicy::FILES_ALLOW_ANY,
783 logging::GetLogFileFullPath().c_str());
784 }
785 }
786
787 #if !defined(OFFICIAL_BUILD)
788 // If stdout/stderr point to a Windows console, these calls will
789 // have no effect.
790 policy->SetStdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE));
791 policy->SetStderrHandle(GetStdHandle(STD_ERROR_HANDLE));
792 #endif
793
794 if (!delegate->PreSpawnTarget(policy))
795 return base::Process();
796
797 TRACE_EVENT_BEGIN0("startup", "StartProcessWithAccess::LAUNCHPROCESS");
798
799 PROCESS_INFORMATION temp_process_info = {};
800 sandbox::ResultCode result = g_broker_services->SpawnTarget(
801 cmd_line->GetProgram().value().c_str(),
802 cmd_line->GetCommandLineString().c_str(), policy, &temp_process_info);
803 DWORD last_error = ::GetLastError();
804 base::win::ScopedProcessInformation target(temp_process_info);
805
806 TRACE_EVENT_END0("startup", "StartProcessWithAccess::LAUNCHPROCESS");
807
808 if (sandbox::SBOX_ALL_OK != result) {
809 if (result == sandbox::SBOX_ERROR_GENERIC)
810 DPLOG(ERROR) << "Failed to launch process";
811 else if (result == sandbox::SBOX_ERROR_CREATE_PROCESS) {
812 // TODO(shrikant): Remove this special case handling after determining
813 // cause for lowbox/createprocess errors.
814 sandbox::PolicyBase* policy_base =
815 static_cast<sandbox::PolicyBase*>(policy);
816 UMA_HISTOGRAM_SPARSE_SLOWLY(policy_base->GetLowBoxSid() ?
817 "Process.Sandbox.Lowbox.Launch.Error" :
818 "Process.Sandbox.Launch.Error",
819 last_error);
820 } else
821 DLOG(ERROR) << "Failed to launch process. Error: " << result;
822
823 return base::Process();
824 }
825
826 delegate->PostSpawnTarget(target.process_handle());
827
828 CHECK(ResumeThread(target.thread_handle()) != static_cast<DWORD>(-1));
829 return base::Process(target.TakeProcessHandle());
830 } 99 }
831 100
832 bool BrokerDuplicateHandle(HANDLE source_handle, 101 bool BrokerDuplicateHandle(HANDLE source_handle,
833 DWORD target_process_id, 102 DWORD target_process_id,
834 HANDLE* target_handle, 103 HANDLE* target_handle,
835 DWORD desired_access, 104 DWORD desired_access,
836 DWORD options) { 105 DWORD options) {
837 // If our process is the target just duplicate the handle. 106 // If our process is the target just duplicate the handle.
838 if (::GetCurrentProcessId() == target_process_id) { 107 if (::GetCurrentProcessId() == target_process_id) {
839 return !!::DuplicateHandle(::GetCurrentProcess(), source_handle, 108 return !!::DuplicateHandle(::GetCurrentProcess(), source_handle,
840 ::GetCurrentProcess(), target_handle, 109 ::GetCurrentProcess(), target_handle,
841 desired_access, FALSE, options); 110 desired_access, FALSE, options);
842 } 111 }
843 112
844 // Try the broker next
845 if (g_target_services &&
846 g_target_services->DuplicateHandle(source_handle, target_process_id,
847 target_handle, desired_access,
848 options) == sandbox::SBOX_ALL_OK) {
849 return true;
850 }
851
852 // Finally, see if we already have access to the process. 113 // Finally, see if we already have access to the process.
853 base::win::ScopedHandle target_process; 114 base::win::ScopedHandle target_process;
854 target_process.Set(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, 115 target_process.Set(::OpenProcess(PROCESS_DUP_HANDLE, FALSE,
855 target_process_id)); 116 target_process_id));
856 if (target_process.IsValid()) { 117 if (target_process.IsValid()) {
857 return !!::DuplicateHandle(::GetCurrentProcess(), source_handle, 118 return !!::DuplicateHandle(::GetCurrentProcess(), source_handle,
858 target_process.Get(), target_handle, 119 target_process.Get(), target_handle,
859 desired_access, FALSE, options); 120 desired_access, FALSE, options);
860 } 121 }
861 122
862 return false; 123 return false;
863 } 124 }
864 125
865 bool BrokerAddTargetPeer(HANDLE peer_process) {
866 return g_broker_services->AddTargetPeer(peer_process) == sandbox::SBOX_ALL_OK;
867 }
868
869 } // namespace content 126 } // namespace content
OLDNEW
« no previous file with comments | « content/common/sandbox_win.h ('k') | content/content.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698