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