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.
4
5 #include "services/service_manager/sandbox/win/sandbox_win.h"
6
7 #include <stddef.h>
8
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/command_line.h"
14 #include "base/debug/activity_tracker.h"
15 #include "base/feature_list.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/hash/hash.h"
19 #include "base/hash/sha1.h"
20 #include "base/logging.h"
21 #include "base/metrics/field_trial.h"
22 #include "base/metrics/histogram_functions.h"
23 #include "base/metrics/histogram_macros.h"
24 #include "base/no_destructor.h"
25 #include "base/path_service.h"
26 #include "base/process/launch.h"
27 #include "base/stl_util.h"
28 #include "base/strings/strcat.h"
29 #include "base/strings/string16.h"
30 #include "base/strings/string_number_conversions.h"
31 #include "base/strings/string_split.h"
32 #include "base/strings/string_util.h"
33 #include "base/strings/stringprintf.h"
34 #include "base/strings/utf_string_conversions.h"
35 #include "base/system/sys_info.h"
36 #include "base/trace_event/trace_event.h"
37 #include "base/win/iat_patch_function.h"
38 #include "base/win/scoped_handle.h"
39 #include "base/win/win_util.h"
40 #include "base/win/windows_version.h"
41 #include "sandbox/win/src/app_container_profile.h"
42 #include "sandbox/win/src/job.h"
43 #include "sandbox/win/src/process_mitigations.h"
44 #include "sandbox/win/src/sandbox.h"
45 #include "sandbox/win/src/sandbox_nt_util.h"
46 #include "sandbox/win/src/sandbox_policy_base.h"
47 #include "sandbox/win/src/win_utils.h"
48 #include "services/service_manager/sandbox/features.h"
49 #include "services/service_manager/sandbox/sandbox_type.h"
50 #include "services/service_manager/sandbox/switches.h"
51 #include "services/service_manager/sandbox/win/sandbox_diagnostics.h"
52
53 namespace service_manager {
54 namespace {
55
56 sandbox::BrokerServices* g_broker_services = NULL;
57
58 HANDLE g_job_object_handle = NULL;
59
60 // The DLLs listed here are known (or under strong suspicion) of causing crashes
61 // when they are loaded in the renderer. Note: at runtime we generate short
62 // versions of the dll name only if the dll has an extension.
63 // For more information about how this list is generated, and how to get off
64 // of it, see:
65 // https://sites.google.com/a/chromium.org/dev/Home/third-party-developers
66 const wchar_t* const kTroublesomeDlls[] = {
67 L"adialhk.dll", // Kaspersky Internet Security.
68 L"acpiz.dll", // Unknown.
69 L"activedetect32.dll", // Lenovo One Key Theater (crbug.com/536056).
70 L"activedetect64.dll", // Lenovo One Key Theater (crbug.com/536056).
71 L"airfoilinject3.dll", // Airfoil.
72 L"akinsofthook32.dll", // Akinsoft Software Engineering.
73 L"assistant_x64.dll", // Unknown.
74 L"atcuf64.dll", // Bit Defender Internet Security x64.
75 L"avcuf64.dll", // Bit Defender Internet Security x64.
76 L"avgrsstx.dll", // AVG 8.
77 L"babylonchromepi.dll", // Babylon translator.
78 L"btkeyind.dll", // Widcomm Bluetooth.
79 L"cmcsyshk.dll", // CMC Internet Security.
80 L"cmsetac.dll", // Unknown (suspected malware).
81 L"cooliris.dll", // CoolIris.
82 L"cplushook.dll", // Unknown (suspected malware).
83 L"dockshellhook.dll", // Stardock Objectdock.
84 L"easyhook32.dll", // GDIPP and others.
85 L"easyhook64.dll", // Symantec BlueCoat and others.
86 L"esspd.dll", // Samsung Smart Security ESCORT.
87 L"googledesktopnetwork3.dll", // Google Desktop Search v5.
88 L"fwhook.dll", // PC Tools Firewall Plus.
89 L"guard64.dll", // Comodo Internet Security x64.
90 L"hookprocesscreation.dll", // Blumentals Program protector.
91 L"hookterminateapis.dll", // Blumentals and Cyberprinter.
92 L"hookprintapis.dll", // Cyberprinter.
93 L"imon.dll", // NOD32 Antivirus.
94 L"icatcdll.dll", // Samsung Smart Security ESCORT.
95 L"icdcnl.dll", // Samsung Smart Security ESCORT.
96 L"ioloHL.dll", // Iolo (System Mechanic).
97 L"kloehk.dll", // Kaspersky Internet Security.
98 L"lawenforcer.dll", // Spyware-Browser AntiSpyware (Spybro).
99 L"libdivx.dll", // DivX.
100 L"lvprcinj01.dll", // Logitech QuickCam.
101 L"madchook.dll", // Madshi (generic hooking library).
102 L"mdnsnsp.dll", // Bonjour.
103 L"moonsysh.dll", // Moon Secure Antivirus.
104 L"mpk.dll", // KGB Spy.
105 L"n64hooks.dll", // Neilsen//NetRatings NetSight.
106 L"npdivx32.dll", // DivX.
107 L"npggNT.des", // GameGuard 2008.
108 L"npggNT.dll", // GameGuard (older).
109 L"nphooks.dll", // Neilsen//NetRatings NetSight.
110 L"oawatch.dll", // Online Armor.
111 L"pastali32.dll", // PastaLeads.
112 L"pavhook.dll", // Panda Internet Security.
113 L"pavlsphook.dll", // Panda Antivirus.
114 L"pavshook.dll", // Panda Antivirus.
115 L"pavshookwow.dll", // Panda Antivirus.
116 L"pctavhook.dll", // PC Tools Antivirus.
117 L"pctgmhk.dll", // PC Tools Spyware Doctor.
118 L"picrmi32.dll", // PicRec.
119 L"picrmi64.dll", // PicRec.
120 L"prntrack.dll", // Pharos Systems.
121 L"prochook.dll", // Unknown (GBill-Tools?) (crbug.com/974722).
122 L"protector.dll", // Unknown (suspected malware).
123 L"radhslib.dll", // Radiant Naomi Internet Filter.
124 L"radprlib.dll", // Radiant Naomi Internet Filter.
125 L"rapportnikko.dll", // Trustware Rapport.
126 L"rlhook.dll", // Trustware Bufferzone.
127 L"rooksdol.dll", // Trustware Rapport.
128 L"rndlpepperbrowserrecordhelper.dll", // RealPlayer.
129 L"rpchromebrowserrecordhelper.dll", // RealPlayer.
130 L"r3hook.dll", // Kaspersky Internet Security.
131 L"sahook.dll", // McAfee Site Advisor.
132 L"sbrige.dll", // Unknown.
133 L"sc2hook.dll", // Supercopier 2.
134 L"sdhook32.dll", // Spybot - Search & Destroy Live Protection.
135 L"sguard.dll", // Iolo (System Guard).
136 L"smum32.dll", // Spyware Doctor version 6.
137 L"smumhook.dll", // Spyware Doctor version 5.
138 L"ssldivx.dll", // DivX.
139 L"syncor11.dll", // SynthCore Midi interface.
140 L"systools.dll", // Panda Antivirus.
141 L"tfwah.dll", // Threatfire (PC tools).
142 L"wblind.dll", // Stardock Object desktop.
143 L"wbhelp.dll", // Stardock Object desktop.
144 L"windowsapihookdll32.dll", // Lenovo One Key Theater (crbug.com/536056).
145 L"windowsapihookdll64.dll", // Lenovo One Key Theater (crbug.com/536056).
146 L"winstylerthemehelper.dll" // Tuneup utilities 2006.
147 };
148
149 // This is for finch. See also crbug.com/464430 for details.
150 const base::Feature kEnableCsrssLockdownFeature{
151 "EnableCsrssLockdown", base::FEATURE_DISABLED_BY_DEFAULT};
152
153 #if !defined(NACL_WIN64)
154 // Adds the policy rules for the path and path\ with the semantic |access|.
155 // If |children| is set to true, we need to add the wildcard rules to also
156 // 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)157 bool AddDirectory(int path,
158 const wchar_t* sub_dir,
159 bool children,
160 sandbox::TargetPolicy::Semantics access,
161 sandbox::TargetPolicy* policy) {
162 base::FilePath directory;
163 if (!base::PathService::Get(path, &directory))
164 return false;
165
166 if (sub_dir)
167 directory = base::MakeAbsoluteFilePath(directory.Append(sub_dir));
168
169 sandbox::ResultCode result;
170 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
171 directory.value().c_str());
172 if (result != sandbox::SBOX_ALL_OK)
173 return false;
174
175 std::wstring directory_str = directory.value() + L"\\";
176 if (children)
177 directory_str += L"*";
178 // Otherwise, add the version of the path that ends with a separator.
179
180 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, access,
181 directory_str.c_str());
182 if (result != sandbox::SBOX_ALL_OK)
183 return false;
184
185 return true;
186 }
187 #endif // !defined(NACL_WIN64)
188
189 // Compares the loaded |module| file name matches |module_name|.
IsExpandedModuleName(HMODULE module,const wchar_t * module_name)190 bool IsExpandedModuleName(HMODULE module, const wchar_t* module_name) {
191 wchar_t path[MAX_PATH];
192 DWORD sz = ::GetModuleFileNameW(module, path, base::size(path));
193 if ((sz == base::size(path)) || (sz == 0)) {
194 // XP does not set the last error properly, so we bail out anyway.
195 return false;
196 }
197 if (!::GetLongPathName(path, path, base::size(path)))
198 return false;
199 base::FilePath fname(path);
200 return (fname.BaseName().value() == module_name);
201 }
202
GetShortNameVariants(const std::wstring & name)203 std::vector<std::wstring> GetShortNameVariants(const std::wstring& name) {
204 std::vector<std::wstring> alt_names;
205 size_t period = name.rfind(L'.');
206 DCHECK_NE(std::string::npos, period);
207 DCHECK_LE(3U, (name.size() - period));
208 if (period <= 8)
209 return alt_names;
210
211 // The module could have been loaded with a 8.3 short name. We check
212 // the three most common cases: 'thelongname.dll' becomes
213 // 'thelon~1.dll', 'thelon~2.dll' and 'thelon~3.dll'.
214 alt_names.reserve(3);
215 for (wchar_t ix = '1'; ix <= '3'; ++ix) {
216 const wchar_t suffix[] = {'~', ix, 0};
217 alt_names.push_back(
218 base::StrCat({name.substr(0, 6), suffix, name.substr(period)}));
219 }
220 return alt_names;
221 }
222
223 // Adds a single dll by |module_name| into the |policy| blocklist.
224 // If |check_in_browser| is true we only add an unload policy only if the dll
225 // is also loaded in this process.
BlocklistAddOneDll(const wchar_t * module_name,bool check_in_browser,sandbox::TargetPolicy * policy)226 void BlocklistAddOneDll(const wchar_t* module_name,
227 bool check_in_browser,
228 sandbox::TargetPolicy* policy) {
229 if (check_in_browser) {
230 HMODULE module = ::GetModuleHandleW(module_name);
231 if (module) {
232 policy->AddDllToUnload(module_name);
233 DVLOG(1) << "dll to unload found: " << module_name;
234 } else {
235 for (const auto& alt_name : GetShortNameVariants(module_name)) {
236 module = ::GetModuleHandleW(alt_name.c_str());
237 // We found it, but because it only has 6 significant letters, we
238 // want to make sure it is the right one.
239 if (module && IsExpandedModuleName(module, module_name)) {
240 // Found a match. We add both forms to the policy.
241 policy->AddDllToUnload(alt_name.c_str());
242 policy->AddDllToUnload(module_name);
243 return;
244 }
245 }
246 }
247 } else {
248 policy->AddDllToUnload(module_name);
249 for (const auto& alt_name : GetShortNameVariants(module_name)) {
250 policy->AddDllToUnload(alt_name.c_str());
251 }
252 }
253 }
254
255 // Adds policy rules for unloaded the known dlls that cause chrome to crash.
256 // Eviction of injected DLLs is done by the sandbox so that the injected module
257 // does not get a chance to execute any code.
AddGenericDllEvictionPolicy(sandbox::TargetPolicy * policy)258 void AddGenericDllEvictionPolicy(sandbox::TargetPolicy* policy) {
259 for (int ix = 0; ix != base::size(kTroublesomeDlls); ++ix)
260 BlocklistAddOneDll(kTroublesomeDlls[ix], true, policy);
261 }
262
263 // Returns the object path prepended with the current logon session.
PrependWindowsSessionPath(const base::char16 * object)264 base::string16 PrependWindowsSessionPath(const base::char16* object) {
265 // Cache this because it can't change after process creation.
266 static DWORD s_session_id = 0;
267 if (s_session_id == 0) {
268 HANDLE token;
269 DWORD session_id_length;
270 DWORD session_id = 0;
271
272 CHECK(::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token));
273 CHECK(::GetTokenInformation(token, TokenSessionId, &session_id,
274 sizeof(session_id), &session_id_length));
275 CloseHandle(token);
276 if (session_id)
277 s_session_id = session_id;
278 }
279
280 return base::StringPrintf(L"\\Sessions\\%lu%ls", s_session_id, object);
281 }
282
283 // Checks if the sandbox can be let to run without a job object assigned.
284 // Returns true if the job object has to be applied to the sandbox and false
285 // otherwise.
ShouldSetJobLevel(const base::CommandLine & cmd_line)286 bool ShouldSetJobLevel(const base::CommandLine& cmd_line) {
287 // Windows 8 allows nested jobs so we don't need to check if we are in other
288 // job.
289 if (base::win::GetVersion() >= base::win::Version::WIN8)
290 return true;
291
292 BOOL in_job = true;
293 // Either there is no job yet associated so we must add our job,
294 if (!::IsProcessInJob(::GetCurrentProcess(), NULL, &in_job))
295 NOTREACHED() << "IsProcessInJob failed. " << GetLastError();
296 if (!in_job)
297 return true;
298
299 // ...or there is a job but the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit is set.
300 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {};
301 if (!::QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation,
302 &job_info, sizeof(job_info), NULL)) {
303 NOTREACHED() << "QueryInformationJobObject failed. " << GetLastError();
304 return true;
305 }
306 if (job_info.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)
307 return true;
308
309 // Lastly in place of the flag which was supposed to be used only for running
310 // Chrome in remote sessions we do this check explicitly here.
311 // According to MS this flag can be false for a remote session only on Windows
312 // Server 2012 and newer so if we do the check last we should be on the safe
313 // side. See: https://msdn.microsoft.com/en-us/library/aa380798.aspx.
314 if (!::GetSystemMetrics(SM_REMOTESESSION)) {
315 // Measure how often we would have decided to apply the sandbox but the
316 // user actually wanted to avoid it.
317 // TODO(pastarmovj): Remove this check and the flag altogether once we are
318 // convinced that the automatic logic is good enough.
319 bool set_job =
320 !cmd_line.HasSwitch(service_manager::switches::kAllowNoSandboxJob);
321 UMA_HISTOGRAM_BOOLEAN("Process.Sandbox.FlagOverrodeRemoteSessionCheck",
322 !set_job);
323 return set_job;
324 }
325
326 // Allow running without the sandbox in this case. This slightly reduces the
327 // ability of the sandbox to protect its children from spawning new processes
328 // or preventing them from shutting down Windows or accessing the clipboard.
329 return false;
330 }
331
332 // Adds the generic policy rules to a sandbox TargetPolicy.
AddGenericPolicy(sandbox::TargetPolicy * policy)333 sandbox::ResultCode AddGenericPolicy(sandbox::TargetPolicy* policy) {
334 sandbox::ResultCode result;
335
336 // Add the policy for the client side of a pipe. It is just a file
337 // in the \pipe\ namespace. We restrict it to pipes that start with
338 // "chrome." so the sandboxed process cannot connect to system services.
339 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
340 sandbox::TargetPolicy::FILES_ALLOW_ANY,
341 L"\\??\\pipe\\chrome.*");
342 if (result != sandbox::SBOX_ALL_OK)
343 return result;
344
345 // Allow the server side of sync sockets, which are pipes that have
346 // the "chrome.sync" namespace and a randomly generated suffix.
347 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
348 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
349 L"\\\\.\\pipe\\chrome.sync.*");
350 if (result != sandbox::SBOX_ALL_OK)
351 return result;
352
353 // Add the policy for debug message only in debug
354 #ifndef NDEBUG
355 base::FilePath app_dir;
356 if (!base::PathService::Get(base::DIR_MODULE, &app_dir))
357 return sandbox::SBOX_ERROR_GENERIC;
358
359 wchar_t long_path_buf[MAX_PATH];
360 DWORD long_path_return_value =
361 GetLongPathName(app_dir.value().c_str(), long_path_buf, MAX_PATH);
362 if (long_path_return_value == 0 || long_path_return_value >= MAX_PATH)
363 return sandbox::SBOX_ERROR_NO_SPACE;
364
365 base::FilePath debug_message(long_path_buf);
366 debug_message = debug_message.AppendASCII("debug_message.exe");
367 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS,
368 sandbox::TargetPolicy::PROCESS_MIN_EXEC,
369 debug_message.value().c_str());
370 if (result != sandbox::SBOX_ALL_OK)
371 return result;
372 #endif // NDEBUG
373
374 // Add the policy for read-only PDB file access for stack traces.
375 #if !defined(OFFICIAL_BUILD)
376 base::FilePath exe;
377 if (!base::PathService::Get(base::FILE_EXE, &exe))
378 return sandbox::SBOX_ERROR_GENERIC;
379 base::FilePath pdb_path = exe.DirName().Append(L"*.pdb");
380 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
381 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
382 pdb_path.value().c_str());
383 if (result != sandbox::SBOX_ALL_OK)
384 return result;
385 #endif
386
387 #if defined(SANITIZER_COVERAGE)
388 DWORD coverage_dir_size =
389 ::GetEnvironmentVariable(L"SANITIZER_COVERAGE_DIR", NULL, 0);
390 if (coverage_dir_size == 0) {
391 LOG(WARNING) << "SANITIZER_COVERAGE_DIR was not set, coverage won't work.";
392 } else {
393 std::wstring coverage_dir;
394 wchar_t* coverage_dir_str =
395 base::WriteInto(&coverage_dir, coverage_dir_size);
396 coverage_dir_size = ::GetEnvironmentVariable(
397 L"SANITIZER_COVERAGE_DIR", coverage_dir_str, coverage_dir_size);
398 CHECK(coverage_dir.size() == coverage_dir_size);
399 base::FilePath sancov_path =
400 base::FilePath(coverage_dir).Append(L"*.sancov");
401 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
402 sandbox::TargetPolicy::FILES_ALLOW_ANY,
403 sancov_path.value().c_str());
404 if (result != sandbox::SBOX_ALL_OK)
405 return result;
406 }
407 #endif
408
409 AddGenericDllEvictionPolicy(policy);
410 return sandbox::SBOX_ALL_OK;
411 }
412
LogLaunchWarning(sandbox::ResultCode last_warning,DWORD last_error)413 void LogLaunchWarning(sandbox::ResultCode last_warning, DWORD last_error) {
414 base::UmaHistogramSparse("Process.Sandbox.Launch.WarningResultCode",
415 last_warning);
416 base::UmaHistogramSparse("Process.Sandbox.Launch.Warning", last_error);
417 }
418
AddPolicyForSandboxedProcess(sandbox::TargetPolicy * policy)419 sandbox::ResultCode AddPolicyForSandboxedProcess(
420 sandbox::TargetPolicy* policy) {
421 sandbox::ResultCode result = sandbox::SBOX_ALL_OK;
422
423 // Win8+ adds a device DeviceApi that we don't need.
424 if (base::win::GetVersion() >= base::win::Version::WIN8)
425 result = policy->AddKernelObjectToClose(L"File", L"\\Device\\DeviceApi");
426 if (result != sandbox::SBOX_ALL_OK)
427 return result;
428
429 // On 2003/Vista+ the initial token has to be restricted if the main
430 // token is restricted.
431 result = policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
432 sandbox::USER_LOCKDOWN);
433 if (result != sandbox::SBOX_ALL_OK)
434 return result;
435 // Prevents the renderers from manipulating low-integrity processes.
436 result = policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
437 if (result != sandbox::SBOX_ALL_OK)
438 return result;
439 result = policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
440 if (result != sandbox::SBOX_ALL_OK)
441 return result;
442 policy->SetLockdownDefaultDacl();
443
444 #ifdef TOOLKIT_QT
445 // Disable alternate window station due to QTBUG-83300
446 result = policy->SetAlternateDesktop(false);
447 #else
448 result = policy->SetAlternateDesktop(true);
449 #endif
450 if (result != sandbox::SBOX_ALL_OK) {
451 // We ignore the result of setting the alternate desktop, however log
452 // a launch warning.
453 LogLaunchWarning(result, ::GetLastError());
454 DLOG(WARNING) << "Failed to apply desktop security to the renderer";
455 result = sandbox::SBOX_ALL_OK;
456 }
457
458 return result;
459 }
460
461 // This code is test only, and attempts to catch unsafe uses of
462 // DuplicateHandle() that copy privileged handles into sandboxed processes.
463 #if !defined(OFFICIAL_BUILD) && !defined(COMPONENT_BUILD)
GetIATPatchFunctionHandle()464 base::win::IATPatchFunction& GetIATPatchFunctionHandle() {
465 static base::NoDestructor<base::win::IATPatchFunction>
466 iat_patch_duplicate_handle;
467 return *iat_patch_duplicate_handle;
468 }
469
470 typedef BOOL(WINAPI* DuplicateHandleFunctionPtr)(HANDLE source_process_handle,
471 HANDLE source_handle,
472 HANDLE target_process_handle,
473 LPHANDLE target_handle,
474 DWORD desired_access,
475 BOOL inherit_handle,
476 DWORD options);
477
478 DuplicateHandleFunctionPtr g_iat_orig_duplicate_handle;
479
480 NtQueryObject g_QueryObject = NULL;
481
482 static const char* kDuplicateHandleWarning =
483 "You are attempting to duplicate a privileged handle into a sandboxed"
484 " process.\n Please contact security@chromium.org for assistance.";
485
CheckDuplicateHandle(HANDLE handle)486 void CheckDuplicateHandle(HANDLE handle) {
487 // Get the object type (32 characters is safe; current max is 14).
488 BYTE buffer[sizeof(OBJECT_TYPE_INFORMATION) + 32 * sizeof(wchar_t)];
489 OBJECT_TYPE_INFORMATION* type_info =
490 reinterpret_cast<OBJECT_TYPE_INFORMATION*>(buffer);
491 ULONG size = sizeof(buffer) - sizeof(wchar_t);
492 NTSTATUS error;
493 error = g_QueryObject(handle, ObjectTypeInformation, type_info, size, &size);
494 CHECK(NT_SUCCESS(error));
495 type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
496
497 // Get the object basic information.
498 OBJECT_BASIC_INFORMATION basic_info;
499 size = sizeof(basic_info);
500 error =
501 g_QueryObject(handle, ObjectBasicInformation, &basic_info, size, &size);
502 CHECK(NT_SUCCESS(error));
503
504 CHECK(!(basic_info.GrantedAccess & WRITE_DAC)) << kDuplicateHandleWarning;
505
506 if (0 == _wcsicmp(type_info->Name.Buffer, L"Process")) {
507 const ACCESS_MASK kDangerousMask =
508 ~static_cast<DWORD>(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE);
509 CHECK(!(basic_info.GrantedAccess & kDangerousMask))
510 << kDuplicateHandleWarning;
511 }
512 }
513
DuplicateHandlePatch(HANDLE source_process_handle,HANDLE source_handle,HANDLE target_process_handle,LPHANDLE target_handle,DWORD desired_access,BOOL inherit_handle,DWORD options)514 BOOL WINAPI DuplicateHandlePatch(HANDLE source_process_handle,
515 HANDLE source_handle,
516 HANDLE target_process_handle,
517 LPHANDLE target_handle,
518 DWORD desired_access,
519 BOOL inherit_handle,
520 DWORD options) {
521 // Duplicate the handle so we get the final access mask.
522 if (!g_iat_orig_duplicate_handle(source_process_handle, source_handle,
523 target_process_handle, target_handle,
524 desired_access, inherit_handle, options))
525 return FALSE;
526
527 // We're not worried about broker handles or not crossing process boundaries.
528 if (source_process_handle == target_process_handle ||
529 target_process_handle == ::GetCurrentProcess())
530 return TRUE;
531
532 // Only sandboxed children are placed in jobs, so just check them.
533 BOOL is_in_job = FALSE;
534 if (!::IsProcessInJob(target_process_handle, NULL, &is_in_job)) {
535 // We need a handle with permission to check the job object.
536 if (ERROR_ACCESS_DENIED == ::GetLastError()) {
537 HANDLE temp_handle;
538 CHECK(g_iat_orig_duplicate_handle(
539 ::GetCurrentProcess(), target_process_handle, ::GetCurrentProcess(),
540 &temp_handle, PROCESS_QUERY_INFORMATION, FALSE, 0));
541 base::win::ScopedHandle process(temp_handle);
542 CHECK(::IsProcessInJob(process.Get(), NULL, &is_in_job));
543 }
544 }
545
546 if (is_in_job) {
547 // We never allow inheritable child handles.
548 CHECK(!inherit_handle) << kDuplicateHandleWarning;
549
550 // Duplicate the handle again, to get the final permissions.
551 HANDLE temp_handle;
552 CHECK(g_iat_orig_duplicate_handle(target_process_handle, *target_handle,
553 ::GetCurrentProcess(), &temp_handle, 0,
554 FALSE, DUPLICATE_SAME_ACCESS));
555 base::win::ScopedHandle handle(temp_handle);
556
557 // Callers use CHECK macro to make sure we get the right stack.
558 CheckDuplicateHandle(handle.Get());
559 }
560
561 return TRUE;
562 }
563 #endif
564
IsAppContainerEnabled()565 bool IsAppContainerEnabled() {
566 if (base::win::GetVersion() < base::win::Version::WIN8)
567 return false;
568
569 static const base::Feature kRendererAppContainer {
570 "RendererAppContainer", base::FEATURE_DISABLED_BY_DEFAULT
571 };
572
573 return base::FeatureList::IsEnabled(kRendererAppContainer);
574 }
575
SetJobMemoryLimit(const base::CommandLine & cmd_line,sandbox::TargetPolicy * policy)576 sandbox::ResultCode SetJobMemoryLimit(const base::CommandLine& cmd_line,
577 sandbox::TargetPolicy* policy) {
578 DCHECK_NE(policy->GetJobLevel(), sandbox::JOB_NONE);
579
580 #ifdef _WIN64
581 size_t memory_limit = static_cast<size_t>(sandbox::kDataSizeLimit);
582
583 // Note that this command line flag hasn't been fetched by all
584 // callers of SetJobLevel, only those in this file.
585 SandboxType sandbox_type =
586 service_manager::SandboxTypeFromCommandLine(cmd_line);
587 if (sandbox_type == SandboxType::kGpu ||
588 sandbox_type == SandboxType::kRenderer) {
589 int64_t GB = 1024 * 1024 * 1024;
590 // Allow the GPU/RENDERER process's sandbox to access more physical memory
591 // if it's available on the system.
592 int64_t physical_memory = base::SysInfo::AmountOfPhysicalMemory();
593 if (physical_memory > 16 * GB) {
594 memory_limit = 16 * GB;
595 } else if (physical_memory > 8 * GB) {
596 memory_limit = 8 * GB;
597 }
598 }
599 return policy->SetJobMemoryLimit(memory_limit);
600 #else
601 return sandbox::SBOX_ALL_OK;
602 #endif
603 }
604
605 // Generate a unique sandbox AC profile for the appcontainer based on the SHA1
606 // hash of the appcontainer_id. This does not need to be secure so using SHA1
607 // isn't a security concern.
GetAppContainerProfileName(const std::string & appcontainer_id,service_manager::SandboxType sandbox_type)608 base::string16 GetAppContainerProfileName(
609 const std::string& appcontainer_id,
610 service_manager::SandboxType sandbox_type) {
611 DCHECK(sandbox_type == SandboxType::kGpu ||
612 sandbox_type == SandboxType::kXrCompositing);
613 auto sha1 = base::SHA1HashString(appcontainer_id);
614 std::string sandbox_base_name = (sandbox_type == SandboxType::kXrCompositing)
615 ? std::string("chrome.sandbox.xrdevice")
616 : std::string("chrome.sandbox.gpu");
617 std::string profile_name = base::StrCat(
618 {sandbox_base_name, base::HexEncode(sha1.data(), sha1.size())});
619 // CreateAppContainerProfile requires that the profile name is at most 64
620 // characters. The size of sha1 is a constant 40, so validate that the base
621 // names are sufficiently short that the total length is valid.
622 DCHECK_LE(profile_name.length(), 64U);
623 return base::UTF8ToWide(profile_name);
624 }
625
SetupAppContainerProfile(sandbox::AppContainerProfile * profile,const base::CommandLine & command_line,service_manager::SandboxType sandbox_type)626 sandbox::ResultCode SetupAppContainerProfile(
627 sandbox::AppContainerProfile* profile,
628 const base::CommandLine& command_line,
629 service_manager::SandboxType sandbox_type) {
630 if (sandbox_type != SandboxType::kGpu &&
631 sandbox_type != SandboxType::kXrCompositing)
632 return sandbox::SBOX_ERROR_UNSUPPORTED;
633
634 if (sandbox_type == SandboxType::kGpu &&
635 !profile->AddImpersonationCapability(L"chromeInstallFiles")) {
636 DLOG(ERROR) << "AppContainerProfile::AddImpersonationCapability("
637 "chromeInstallFiles) failed";
638 return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY;
639 }
640
641 if ((sandbox_type == SandboxType::kXrCompositing ||
642 sandbox_type == SandboxType::kGpu) &&
643 !profile->AddCapability(L"lpacPnpNotifications")) {
644 DLOG(ERROR)
645 << "AppContainerProfile::AddCapability(lpacPnpNotifications) failed";
646 return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY;
647 }
648
649 if (sandbox_type == SandboxType::kXrCompositing &&
650 !profile->AddCapability(L"chromeInstallFiles")) {
651 DLOG(ERROR)
652 << "AppContainerProfile::AddCapability(chromeInstallFiles) failed";
653 return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY;
654 }
655
656 std::vector<base::string16> base_caps = {
657 L"lpacChromeInstallFiles", L"registryRead",
658 };
659
660 if (sandbox_type == SandboxType::kGpu) {
661 auto cmdline_caps = base::SplitString(
662 command_line.GetSwitchValueNative(
663 service_manager::switches::kAddGpuAppContainerCaps),
664 L",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
665 base_caps.insert(base_caps.end(), cmdline_caps.begin(), cmdline_caps.end());
666 }
667
668 if (sandbox_type == SandboxType::kXrCompositing) {
669 auto cmdline_caps = base::SplitString(
670 command_line.GetSwitchValueNative(
671 service_manager::switches::kAddXrAppContainerCaps),
672 L",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
673 base_caps.insert(base_caps.end(), cmdline_caps.begin(), cmdline_caps.end());
674 }
675
676 for (const auto& cap : base_caps) {
677 if (!profile->AddCapability(cap.c_str())) {
678 DLOG(ERROR) << "AppContainerProfile::AddCapability() failed";
679 return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY;
680 }
681 }
682
683 // Enable LPAC for GPU process, but not for XRCompositor service.
684 if (sandbox_type == SandboxType::kGpu &&
685 base::FeatureList::IsEnabled(service_manager::features::kGpuLPAC)) {
686 profile->SetEnableLowPrivilegeAppContainer(true);
687 }
688
689 return sandbox::SBOX_ALL_OK;
690 }
691
692 } // namespace
693
694 // static
SetJobLevel(const base::CommandLine & cmd_line,sandbox::JobLevel job_level,uint32_t ui_exceptions,sandbox::TargetPolicy * policy)695 sandbox::ResultCode SandboxWin::SetJobLevel(const base::CommandLine& cmd_line,
696 sandbox::JobLevel job_level,
697 uint32_t ui_exceptions,
698 sandbox::TargetPolicy* policy) {
699 if (!ShouldSetJobLevel(cmd_line))
700 return policy->SetJobLevel(sandbox::JOB_NONE, 0);
701
702 sandbox::ResultCode ret = policy->SetJobLevel(job_level, ui_exceptions);
703 if (ret != sandbox::SBOX_ALL_OK)
704 return ret;
705
706 return SetJobMemoryLimit(cmd_line, policy);
707 }
708
709 // TODO(jschuh): Need get these restrictions applied to NaCl and Pepper.
710 // Just have to figure out what needs to be warmed up first.
711 // static
AddBaseHandleClosePolicy(sandbox::TargetPolicy * policy)712 sandbox::ResultCode SandboxWin::AddBaseHandleClosePolicy(
713 sandbox::TargetPolicy* policy) {
714 if (base::FeatureList::IsEnabled(kEnableCsrssLockdownFeature)) {
715 // Close all ALPC ports.
716 sandbox::ResultCode ret = policy->SetDisconnectCsrss();
717 if (ret != sandbox::SBOX_ALL_OK) {
718 return ret;
719 }
720 }
721
722 // TODO(cpu): Add back the BaseNamedObjects policy.
723 base::string16 object_path = PrependWindowsSessionPath(
724 L"\\BaseNamedObjects\\windows_shell_global_counters");
725 return policy->AddKernelObjectToClose(L"Section", object_path.data());
726 }
727
728 // static
AddAppContainerPolicy(sandbox::TargetPolicy * policy,const wchar_t * sid)729 sandbox::ResultCode SandboxWin::AddAppContainerPolicy(
730 sandbox::TargetPolicy* policy,
731 const wchar_t* sid) {
732 if (IsAppContainerEnabled())
733 return policy->SetLowBox(sid);
734 return sandbox::SBOX_ALL_OK;
735 }
736
737 // static
AddWin32kLockdownPolicy(sandbox::TargetPolicy * policy,bool enable_opm)738 sandbox::ResultCode SandboxWin::AddWin32kLockdownPolicy(
739 sandbox::TargetPolicy* policy,
740 bool enable_opm) {
741 #if !defined(NACL_WIN64)
742 if (!service_manager::IsWin32kLockdownEnabled())
743 return sandbox::SBOX_ALL_OK;
744
745 sandbox::MitigationFlags flags = policy->GetProcessMitigations();
746 // Check not enabling twice. Should not happen.
747 DCHECK_EQ(0U, flags & sandbox::MITIGATION_WIN32K_DISABLE);
748
749 flags |= sandbox::MITIGATION_WIN32K_DISABLE;
750 sandbox::ResultCode result = policy->SetProcessMitigations(flags);
751 if (result != sandbox::SBOX_ALL_OK)
752 return result;
753
754 result =
755 policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
756 enable_opm ? sandbox::TargetPolicy::IMPLEMENT_OPM_APIS
757 : sandbox::TargetPolicy::FAKE_USER_GDI_INIT,
758 nullptr);
759 if (result != sandbox::SBOX_ALL_OK)
760 return result;
761 if (enable_opm)
762 policy->SetEnableOPMRedirection();
763
764 return result;
765 #else
766 return sandbox::SBOX_ALL_OK;
767 #endif
768 }
769
770 // static
AddAppContainerProfileToPolicy(const base::CommandLine & command_line,service_manager::SandboxType sandbox_type,const std::string & appcontainer_id,sandbox::TargetPolicy * policy)771 sandbox::ResultCode SandboxWin::AddAppContainerProfileToPolicy(
772 const base::CommandLine& command_line,
773 service_manager::SandboxType sandbox_type,
774 const std::string& appcontainer_id,
775 sandbox::TargetPolicy* policy) {
776 if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
777 return sandbox::SBOX_ALL_OK;
778 base::string16 profile_name =
779 GetAppContainerProfileName(appcontainer_id, sandbox_type);
780 sandbox::ResultCode result =
781 policy->AddAppContainerProfile(profile_name.c_str(), true);
782 if (result != sandbox::SBOX_ALL_OK)
783 return result;
784
785 scoped_refptr<sandbox::AppContainerProfile> profile =
786 policy->GetAppContainerProfile();
787 result = SetupAppContainerProfile(profile.get(), command_line, sandbox_type);
788 if (result != sandbox::SBOX_ALL_OK)
789 return result;
790
791 DWORD granted_access;
792 BOOL granted_access_status;
793 bool access_check =
794 profile->AccessCheck(command_line.GetProgram().value().c_str(),
795 SE_FILE_OBJECT, GENERIC_READ | GENERIC_EXECUTE,
796 &granted_access, &granted_access_status) &&
797 granted_access_status;
798 if (!access_check)
799 return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_ACCESS_CHECK;
800
801 return sandbox::SBOX_ALL_OK;
802 }
803
804 // static
IsAppContainerEnabledForSandbox(const base::CommandLine & command_line,SandboxType sandbox_type)805 bool SandboxWin::IsAppContainerEnabledForSandbox(
806 const base::CommandLine& command_line,
807 SandboxType sandbox_type) {
808 if (sandbox_type != SandboxType::kGpu)
809 return false;
810 if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
811 return false;
812 return base::FeatureList::IsEnabled(
813 service_manager::features::kGpuAppContainer);
814 }
815
816 // static
InitBrokerServices(sandbox::BrokerServices * broker_services)817 bool SandboxWin::InitBrokerServices(sandbox::BrokerServices* broker_services) {
818 // TODO(abarth): DCHECK(CalledOnValidThread());
819 // See <http://b/1287166>.
820 DCHECK(broker_services);
821 DCHECK(!g_broker_services);
822 sandbox::ResultCode result = broker_services->Init();
823 g_broker_services = broker_services;
824
825 // In non-official builds warn about dangerous uses of DuplicateHandle. This
826 // isn't useful under a component build, since there will be multiple modules,
827 // each of which may have a slot to patch (if the symbol is even present).
828 #if !defined(OFFICIAL_BUILD) && !defined(COMPONENT_BUILD)
829 BOOL is_in_job = FALSE;
830 CHECK(::IsProcessInJob(::GetCurrentProcess(), NULL, &is_in_job));
831 if (!is_in_job && !GetIATPatchFunctionHandle().is_patched()) {
832 HMODULE module = NULL;
833 wchar_t module_name[MAX_PATH];
834 CHECK(::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
835 reinterpret_cast<LPCWSTR>(InitBrokerServices),
836 &module));
837 DWORD result = ::GetModuleFileNameW(module, module_name, MAX_PATH);
838 if (result && (result != MAX_PATH)) {
839 ResolveNTFunctionPtr("NtQueryObject", &g_QueryObject);
840 result = GetIATPatchFunctionHandle().Patch(
841 module_name, "kernel32.dll", "DuplicateHandle",
842 reinterpret_cast<void*>(DuplicateHandlePatch));
843 CHECK_EQ(0u, result);
844 g_iat_orig_duplicate_handle =
845 reinterpret_cast<DuplicateHandleFunctionPtr>(
846 GetIATPatchFunctionHandle().original_function());
847 }
848 }
849 #endif
850
851 return sandbox::SBOX_ALL_OK == result;
852 }
853
854 // static
InitTargetServices(sandbox::TargetServices * target_services)855 bool SandboxWin::InitTargetServices(sandbox::TargetServices* target_services) {
856 DCHECK(target_services);
857 sandbox::ResultCode result = target_services->Init();
858 return sandbox::SBOX_ALL_OK == result;
859 }
860
StartSandboxedProcess(base::CommandLine * cmd_line,const std::string & process_type,const base::HandlesToInheritVector & handles_to_inherit,service_manager::SandboxDelegate * delegate,base::Process * process)861 sandbox::ResultCode SandboxWin::StartSandboxedProcess(
862 base::CommandLine* cmd_line,
863 const std::string& process_type,
864 const base::HandlesToInheritVector& handles_to_inherit,
865 service_manager::SandboxDelegate* delegate,
866 base::Process* process) {
867 const base::CommandLine& launcher_process_command_line =
868 *base::CommandLine::ForCurrentProcess();
869
870 // Propagate the --allow-no-job flag if present.
871 if (launcher_process_command_line.HasSwitch(
872 service_manager::switches::kAllowNoSandboxJob) &&
873 !cmd_line->HasSwitch(service_manager::switches::kAllowNoSandboxJob)) {
874 cmd_line->AppendSwitch(service_manager::switches::kAllowNoSandboxJob);
875 }
876
877 service_manager::SandboxType sandbox_type = delegate->GetSandboxType();
878 if (service_manager::IsUnsandboxedSandboxType(sandbox_type) ||
879 cmd_line->HasSwitch(service_manager::switches::kNoSandbox) ||
880 launcher_process_command_line.HasSwitch(
881 service_manager::switches::kNoSandbox)) {
882 base::LaunchOptions options;
883 options.handles_to_inherit = handles_to_inherit;
884 BOOL in_job = true;
885 // Prior to Windows 8 nested jobs aren't possible.
886 if (sandbox_type == SandboxType::kNetwork &&
887 (base::win::GetVersion() >= base::win::Version::WIN8 ||
888 (::IsProcessInJob(::GetCurrentProcess(), nullptr, &in_job) &&
889 !in_job))) {
890 // Launch the process in a job to ensure that the network process doesn't
891 // outlive the browser. This could happen if there is a lot of I/O on
892 // process shutdown, in which case TerminateProcess would fail.
893 // https://crbug.com/820996
894 if (!g_job_object_handle) {
895 sandbox::Job job_obj;
896 DWORD result = job_obj.Init(sandbox::JOB_UNPROTECTED, nullptr, 0, 0);
897 if (result != ERROR_SUCCESS)
898 return sandbox::SBOX_ERROR_CANNOT_INIT_JOB;
899 g_job_object_handle = job_obj.Take().Take();
900 }
901 options.job_handle = g_job_object_handle;
902 }
903 *process = base::LaunchProcess(*cmd_line, options);
904 return sandbox::SBOX_ALL_OK;
905 }
906
907 scoped_refptr<sandbox::TargetPolicy> policy =
908 g_broker_services->CreatePolicy();
909
910 // Add any handles to be inherited to the policy.
911 for (HANDLE handle : handles_to_inherit)
912 policy->AddHandleToShare(handle);
913
914 // Pre-startup mitigations.
915 sandbox::MitigationFlags mitigations =
916 sandbox::MITIGATION_HEAP_TERMINATE |
917 sandbox::MITIGATION_BOTTOM_UP_ASLR |
918 sandbox::MITIGATION_DEP |
919 sandbox::MITIGATION_DEP_NO_ATL_THUNK |
920 sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
921 sandbox::MITIGATION_SEHOP |
922 sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
923 sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
924 sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL |
925 sandbox::MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION;
926
927 sandbox::ResultCode result = policy->SetProcessMitigations(mitigations);
928 if (result != sandbox::SBOX_ALL_OK)
929 return result;
930
931 #if !defined(NACL_WIN64)
932 if (process_type == service_manager::switches::kRendererProcess &&
933 service_manager::IsWin32kLockdownEnabled()) {
934 result = SandboxWin::AddWin32kLockdownPolicy(policy.get(), false);
935 if (result != sandbox::SBOX_ALL_OK)
936 return result;
937 }
938 #endif
939
940 // Post-startup mitigations.
941 mitigations = sandbox::MITIGATION_DLL_SEARCH_ORDER;
942 if (!cmd_line->HasSwitch(switches::kAllowThirdPartyModules))
943 mitigations |= sandbox::MITIGATION_FORCE_MS_SIGNED_BINS;
944 if (sandbox_type == SandboxType::kNetwork ||
945 sandbox_type == SandboxType::kAudio) {
946 mitigations |= sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
947 }
948 // TODO(wfh): Relax strict handle checks for network process until root cause
949 // for this crash can be resolved. See https://crbug.com/939590.
950 if (sandbox_type != SandboxType::kNetwork)
951 mitigations |= sandbox::MITIGATION_STRICT_HANDLE_CHECKS;
952
953 result = policy->SetDelayedProcessMitigations(mitigations);
954 if (result != sandbox::SBOX_ALL_OK)
955 return result;
956
957 result = SetJobLevel(*cmd_line, sandbox::JOB_LOCKDOWN, 0, policy.get());
958 if (result != sandbox::SBOX_ALL_OK)
959 return result;
960
961 if (!delegate->DisableDefaultPolicy()) {
962 result = AddPolicyForSandboxedProcess(policy.get());
963 if (result != sandbox::SBOX_ALL_OK)
964 return result;
965 }
966
967 if (process_type == service_manager::switches::kGpuProcess &&
968 base::FeatureList::IsEnabled(
969 {"GpuLockdownDefaultDacl", base::FEATURE_ENABLED_BY_DEFAULT})) {
970 policy->SetLockdownDefaultDacl();
971 policy->AddRestrictingRandomSid();
972 }
973
974 #if !defined(NACL_WIN64)
975 if (process_type == service_manager::switches::kRendererProcess ||
976 process_type == service_manager::switches::kPpapiPluginProcess ||
977 sandbox_type == SandboxType::kPrintCompositor) {
978 AddDirectory(base::DIR_WINDOWS_FONTS, NULL, true,
979 sandbox::TargetPolicy::FILES_ALLOW_READONLY, policy.get());
980 }
981 #endif
982
983 result = AddGenericPolicy(policy.get());
984 if (result != sandbox::SBOX_ALL_OK) {
985 NOTREACHED();
986 return result;
987 }
988
989 std::string appcontainer_id;
990 if (IsAppContainerEnabledForSandbox(*cmd_line, sandbox_type) &&
991 delegate->GetAppContainerId(&appcontainer_id)) {
992 result = AddAppContainerProfileToPolicy(*cmd_line, sandbox_type,
993 appcontainer_id, policy.get());
994 DCHECK(result == sandbox::SBOX_ALL_OK);
995 if (result != sandbox::SBOX_ALL_OK)
996 return result;
997 }
998
999 // Allow the renderer, gpu and utility processes to access the log file.
1000 if (process_type == service_manager::switches::kRendererProcess ||
1001 process_type == service_manager::switches::kGpuProcess ||
1002 process_type == service_manager::switches::kUtilityProcess) {
1003 if (logging::IsLoggingToFileEnabled()) {
1004 DCHECK(base::FilePath(logging::GetLogFileFullPath()).IsAbsolute());
1005 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
1006 sandbox::TargetPolicy::FILES_ALLOW_ANY,
1007 logging::GetLogFileFullPath().c_str());
1008 if (result != sandbox::SBOX_ALL_OK)
1009 return result;
1010 }
1011 }
1012
1013 #if !defined(OFFICIAL_BUILD)
1014 // If stdout/stderr point to a Windows console, these calls will
1015 // have no effect. These calls can fail with SBOX_ERROR_BAD_PARAMS.
1016 policy->SetStdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE));
1017 policy->SetStderrHandle(GetStdHandle(STD_ERROR_HANDLE));
1018 #endif
1019
1020 if (!delegate->PreSpawnTarget(policy.get()))
1021 return sandbox::SBOX_ERROR_DELEGATE_PRE_SPAWN;
1022
1023 TRACE_EVENT_BEGIN0("startup", "StartProcessWithAccess::LAUNCHPROCESS");
1024
1025 PROCESS_INFORMATION temp_process_info = {};
1026 sandbox::ResultCode last_warning = sandbox::SBOX_ALL_OK;
1027 DWORD last_error = ERROR_SUCCESS;
1028 result = g_broker_services->SpawnTarget(
1029 cmd_line->GetProgram().value().c_str(),
1030 cmd_line->GetCommandLineString().c_str(), policy, &last_warning,
1031 &last_error, &temp_process_info);
1032
1033 // TODO(1059129) Remove logging and underlying plumbing on expiry.
1034 // This must be logged after spawning the process as the policy
1035 // memory is not committed until the target process is attached to
1036 // the sandbox policy. Max is kPolMemSize from sandbox_policy_base.cc.
1037 if (result == sandbox::SBOX_ALL_OK) {
1038 UMA_HISTOGRAM_CUSTOM_COUNTS("Process.Sandbox.PolicyGlobalSizeOnSuccess",
1039 policy->GetPolicyGlobalSize(), 16, 14 * 4096,
1040 50);
1041 }
1042
1043 base::win::ScopedProcessInformation target(temp_process_info);
1044
1045 TRACE_EVENT_END0("startup", "StartProcessWithAccess::LAUNCHPROCESS");
1046
1047 if (sandbox::SBOX_ALL_OK != result) {
1048 base::UmaHistogramSparse("Process.Sandbox.Launch.Error", last_error);
1049 if (result == sandbox::SBOX_ERROR_GENERIC)
1050 DPLOG(ERROR) << "Failed to launch process";
1051 else
1052 DLOG(ERROR) << "Failed to launch process. Error: " << result;
1053 return result;
1054 }
1055
1056 base::debug::GlobalActivityTracker* tracker =
1057 base::debug::GlobalActivityTracker::Get();
1058 if (tracker) {
1059 tracker->RecordProcessLaunch(target.process_id(),
1060 cmd_line->GetCommandLineString());
1061 }
1062
1063 if (sandbox::SBOX_ALL_OK != last_warning)
1064 LogLaunchWarning(last_warning, last_error);
1065
1066 delegate->PostSpawnTarget(target.process_handle());
1067 CHECK(ResumeThread(target.thread_handle()) != static_cast<DWORD>(-1));
1068
1069 *process = base::Process(target.TakeProcessHandle());
1070 return sandbox::SBOX_ALL_OK;
1071 }
1072
GetPolicyDiagnostics(base::OnceCallback<void (base::Value)> response)1073 sandbox::ResultCode SandboxWin::GetPolicyDiagnostics(
1074 base::OnceCallback<void(base::Value)> response) {
1075 CHECK(g_broker_services);
1076 CHECK(!response.is_null());
1077 auto receiver = std::make_unique<ServiceManagerDiagnosticsReceiver>(
1078 base::SequencedTaskRunnerHandle::Get(), std::move(response));
1079 return g_broker_services->GetPolicyDiagnostics(std::move(receiver));
1080 }
1081
BlocklistAddOneDllForTesting(const wchar_t * module_name,bool check_in_browser,sandbox::TargetPolicy * policy)1082 void BlocklistAddOneDllForTesting(const wchar_t* module_name,
1083 bool check_in_browser,
1084 sandbox::TargetPolicy* policy) {
1085 BlocklistAddOneDll(module_name, check_in_browser, policy);
1086 }
1087
1088 } // namespace service_manager
1089