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 "sandbox/win/src/sandbox_policy_base.h"
6 
7 #include <sddl.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include "base/callback.h"
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "base/stl_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/win/win_util.h"
17 #include "base/win/windows_version.h"
18 #include "sandbox/win/src/acl.h"
19 #include "sandbox/win/src/filesystem_policy.h"
20 #include "sandbox/win/src/interception.h"
21 #include "sandbox/win/src/job.h"
22 #include "sandbox/win/src/named_pipe_policy.h"
23 #include "sandbox/win/src/policy_broker.h"
24 #include "sandbox/win/src/policy_engine_processor.h"
25 #include "sandbox/win/src/policy_low_level.h"
26 #include "sandbox/win/src/process_mitigations.h"
27 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
28 #include "sandbox/win/src/process_thread_policy.h"
29 #include "sandbox/win/src/registry_policy.h"
30 #include "sandbox/win/src/restricted_token_utils.h"
31 #include "sandbox/win/src/sandbox_policy.h"
32 #include "sandbox/win/src/sandbox_policy_diagnostic.h"
33 #include "sandbox/win/src/sandbox_utils.h"
34 #include "sandbox/win/src/security_capabilities.h"
35 #include "sandbox/win/src/signed_policy.h"
36 #include "sandbox/win/src/sync_policy.h"
37 #include "sandbox/win/src/target_process.h"
38 #include "sandbox/win/src/top_level_dispatcher.h"
39 #include "sandbox/win/src/window.h"
40 
41 namespace {
42 
43 // The standard windows size for one memory page.
44 constexpr size_t kOneMemPage = 4096;
45 // The IPC and Policy shared memory sizes.
46 constexpr size_t kIPCMemSize = kOneMemPage * 2;
47 constexpr size_t kPolMemSize = kOneMemPage * 6;
48 
49 // Helper function to allocate space (on the heap) for policy.
MakeBrokerPolicyMemory()50 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
51   const size_t kTotalPolicySz = kPolMemSize;
52   sandbox::PolicyGlobal* policy =
53       static_cast<sandbox::PolicyGlobal*>(::operator new(kTotalPolicySz));
54   DCHECK(policy);
55   memset(policy, 0, kTotalPolicySz);
56   policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
57   return policy;
58 }
59 
IsInheritableHandle(HANDLE handle)60 bool IsInheritableHandle(HANDLE handle) {
61   if (!handle)
62     return false;
63   if (handle == INVALID_HANDLE_VALUE)
64     return false;
65   // File handles (FILE_TYPE_DISK) and pipe handles are known to be
66   // inheritable.  Console handles (FILE_TYPE_CHAR) are not
67   // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
68   DWORD handle_type = GetFileType(handle);
69   return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
70 }
71 
72 }  // namespace
73 
74 namespace sandbox {
75 
76 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
77 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
78 
79 // Initializes static members. alternate_desktop_handle_ is a desktop on
80 // alternate_winstation_handle_, alternate_desktop_local_winstation_handle_ is a
81 // desktop on the same winstation as the parent process.
82 HWINSTA PolicyBase::alternate_winstation_handle_ = nullptr;
83 HDESK PolicyBase::alternate_desktop_handle_ = nullptr;
84 HDESK PolicyBase::alternate_desktop_local_winstation_handle_ = nullptr;
85 IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
86     INTEGRITY_LEVEL_SYSTEM;
87 IntegrityLevel
88     PolicyBase::alternate_desktop_local_winstation_integrity_level_label_ =
89         INTEGRITY_LEVEL_SYSTEM;
90 
PolicyBase()91 PolicyBase::PolicyBase()
92     : ref_count(1),
93       lockdown_level_(USER_LOCKDOWN),
94       initial_level_(USER_LOCKDOWN),
95       job_level_(JOB_LOCKDOWN),
96       ui_exceptions_(0),
97       memory_limit_(0),
98       use_alternate_desktop_(false),
99       use_alternate_winstation_(false),
100       file_system_init_(false),
101       relaxed_interceptions_(true),
102       stdout_handle_(INVALID_HANDLE_VALUE),
103       stderr_handle_(INVALID_HANDLE_VALUE),
104       integrity_level_(INTEGRITY_LEVEL_LAST),
105       delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
106       mitigations_(0),
107       delayed_mitigations_(0),
108       is_csrss_connected_(true),
109       policy_maker_(nullptr),
110       policy_(nullptr),
111       lowbox_sid_(nullptr),
112       lockdown_default_dacl_(false),
113       add_restricting_random_sid_(false),
114       enable_opm_redirection_(false),
115       effective_token_(nullptr) {
116   ::InitializeCriticalSection(&lock_);
117   dispatcher_.reset(new TopLevelDispatcher(this));
118 }
119 
~PolicyBase()120 PolicyBase::~PolicyBase() {
121   delete policy_maker_;
122   delete policy_;
123 
124   if (lowbox_sid_)
125     ::LocalFree(lowbox_sid_);
126 
127   ::DeleteCriticalSection(&lock_);
128 }
129 
AddRef()130 void PolicyBase::AddRef() {
131   // ref_count starts at 1 so cannot increase from 0 to 1.
132   CHECK(::InterlockedIncrement(&ref_count) > 1);
133 }
134 
Release()135 void PolicyBase::Release() {
136   LONG result = ::InterlockedDecrement(&ref_count);
137   CHECK(result >= 0);
138   if (result == 0)
139     delete this;
140 }
141 
SetTokenLevel(TokenLevel initial,TokenLevel lockdown)142 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
143   if (initial < lockdown) {
144     return SBOX_ERROR_BAD_PARAMS;
145   }
146   initial_level_ = initial;
147   lockdown_level_ = lockdown;
148   return SBOX_ALL_OK;
149 }
150 
GetInitialTokenLevel() const151 TokenLevel PolicyBase::GetInitialTokenLevel() const {
152   return initial_level_;
153 }
154 
GetLockdownTokenLevel() const155 TokenLevel PolicyBase::GetLockdownTokenLevel() const {
156   return lockdown_level_;
157 }
158 
SetJobLevel(JobLevel job_level,uint32_t ui_exceptions)159 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) {
160   if (memory_limit_ && job_level == JOB_NONE) {
161     return SBOX_ERROR_BAD_PARAMS;
162   }
163   job_level_ = job_level;
164   ui_exceptions_ = ui_exceptions;
165   return SBOX_ALL_OK;
166 }
167 
GetJobLevel() const168 JobLevel PolicyBase::GetJobLevel() const {
169   return job_level_;
170 }
171 
SetJobMemoryLimit(size_t memory_limit)172 ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
173   memory_limit_ = memory_limit;
174   return SBOX_ALL_OK;
175 }
176 
SetAlternateDesktop(bool alternate_winstation)177 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
178   use_alternate_desktop_ = true;
179   use_alternate_winstation_ = alternate_winstation;
180   return CreateAlternateDesktop(alternate_winstation);
181 }
182 
GetAlternateDesktop() const183 std::wstring PolicyBase::GetAlternateDesktop() const {
184   // No alternate desktop or winstation. Return an empty string.
185   if (!use_alternate_desktop_ && !use_alternate_winstation_) {
186     return std::wstring();
187   }
188 
189   if (use_alternate_winstation_) {
190     // The desktop and winstation should have been created by now.
191     // If we hit this scenario, it means that the user ignored the failure
192     // during SetAlternateDesktop, so we ignore it here too.
193     if (!alternate_desktop_handle_ || !alternate_winstation_handle_)
194       return std::wstring();
195 
196     return GetFullDesktopName(alternate_winstation_handle_,
197                               alternate_desktop_handle_);
198   }
199 
200   if (!alternate_desktop_local_winstation_handle_)
201     return std::wstring();
202 
203   return GetFullDesktopName(nullptr,
204                             alternate_desktop_local_winstation_handle_);
205 }
206 
CreateAlternateDesktop(bool alternate_winstation)207 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
208   if (alternate_winstation) {
209     // Check if it's already created.
210     if (alternate_winstation_handle_ && alternate_desktop_handle_)
211       return SBOX_ALL_OK;
212 
213     DCHECK(!alternate_winstation_handle_);
214     // Create the window station.
215     ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
216     if (SBOX_ALL_OK != result)
217       return result;
218 
219     // Verify that everything is fine.
220     if (!alternate_winstation_handle_ ||
221         base::win::GetWindowObjectName(alternate_winstation_handle_).empty())
222       return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
223 
224     // Create the destkop.
225     result = CreateAltDesktop(alternate_winstation_handle_,
226                               &alternate_desktop_handle_);
227     if (SBOX_ALL_OK != result)
228       return result;
229 
230     // Verify that everything is fine.
231     if (!alternate_desktop_handle_ ||
232         base::win::GetWindowObjectName(alternate_desktop_handle_).empty()) {
233       return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
234     }
235   } else {
236     // Check if it already exists.
237     if (alternate_desktop_local_winstation_handle_)
238       return SBOX_ALL_OK;
239 
240     // Create the destkop.
241     ResultCode result =
242         CreateAltDesktop(nullptr, &alternate_desktop_local_winstation_handle_);
243     if (SBOX_ALL_OK != result)
244       return result;
245 
246     // Verify that everything is fine.
247     if (!alternate_desktop_local_winstation_handle_ ||
248         base::win::GetWindowObjectName(
249             alternate_desktop_local_winstation_handle_)
250             .empty()) {
251       return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
252     }
253   }
254 
255   return SBOX_ALL_OK;
256 }
257 
DestroyAlternateDesktop()258 void PolicyBase::DestroyAlternateDesktop() {
259   if (use_alternate_winstation_) {
260     if (alternate_desktop_handle_) {
261       ::CloseDesktop(alternate_desktop_handle_);
262       alternate_desktop_handle_ = nullptr;
263     }
264 
265     if (alternate_winstation_handle_) {
266       ::CloseWindowStation(alternate_winstation_handle_);
267       alternate_winstation_handle_ = nullptr;
268     }
269   } else {
270     if (alternate_desktop_local_winstation_handle_) {
271       ::CloseDesktop(alternate_desktop_local_winstation_handle_);
272       alternate_desktop_local_winstation_handle_ = nullptr;
273     }
274   }
275 }
276 
SetIntegrityLevel(IntegrityLevel integrity_level)277 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
278   if (app_container_profile_)
279     return SBOX_ERROR_BAD_PARAMS;
280   integrity_level_ = integrity_level;
281   return SBOX_ALL_OK;
282 }
283 
GetIntegrityLevel() const284 IntegrityLevel PolicyBase::GetIntegrityLevel() const {
285   return integrity_level_;
286 }
287 
SetDelayedIntegrityLevel(IntegrityLevel integrity_level)288 ResultCode PolicyBase::SetDelayedIntegrityLevel(
289     IntegrityLevel integrity_level) {
290   delayed_integrity_level_ = integrity_level;
291   return SBOX_ALL_OK;
292 }
293 
SetLowBox(const wchar_t * sid)294 ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
295   if (base::win::GetVersion() < base::win::Version::WIN8)
296     return SBOX_ERROR_UNSUPPORTED;
297 
298   DCHECK(sid);
299   if (lowbox_sid_ || app_container_profile_)
300     return SBOX_ERROR_BAD_PARAMS;
301 
302   if (!ConvertStringSidToSid(sid, &lowbox_sid_))
303     return SBOX_ERROR_INVALID_LOWBOX_SID;
304 
305   return SBOX_ALL_OK;
306 }
307 
SetProcessMitigations(MitigationFlags flags)308 ResultCode PolicyBase::SetProcessMitigations(MitigationFlags flags) {
309   // Prior to Win10 RS5 CreateProcess fails when AppContainer and mitigation
310   // flags are enabled. Return an error on downlevel platforms if trying to
311   // set new mitigations.
312   if (app_container_profile_ &&
313       base::win::GetVersion() < base::win::Version::WIN10_RS5) {
314     return SBOX_ERROR_BAD_PARAMS;
315   }
316   if (!CanSetProcessMitigationsPreStartup(flags))
317     return SBOX_ERROR_BAD_PARAMS;
318   mitigations_ = flags;
319   return SBOX_ALL_OK;
320 }
321 
GetProcessMitigations()322 MitigationFlags PolicyBase::GetProcessMitigations() {
323   return mitigations_;
324 }
325 
SetDelayedProcessMitigations(MitigationFlags flags)326 ResultCode PolicyBase::SetDelayedProcessMitigations(MitigationFlags flags) {
327   if (!CanSetProcessMitigationsPostStartup(flags))
328     return SBOX_ERROR_BAD_PARAMS;
329   delayed_mitigations_ = flags;
330   return SBOX_ALL_OK;
331 }
332 
GetDelayedProcessMitigations() const333 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
334   return delayed_mitigations_;
335 }
336 
SetStrictInterceptions()337 void PolicyBase::SetStrictInterceptions() {
338   relaxed_interceptions_ = false;
339 }
340 
SetStdoutHandle(HANDLE handle)341 ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
342   if (!IsInheritableHandle(handle))
343     return SBOX_ERROR_BAD_PARAMS;
344   stdout_handle_ = handle;
345   return SBOX_ALL_OK;
346 }
347 
SetStderrHandle(HANDLE handle)348 ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
349   if (!IsInheritableHandle(handle))
350     return SBOX_ERROR_BAD_PARAMS;
351   stderr_handle_ = handle;
352   return SBOX_ALL_OK;
353 }
354 
AddRule(SubSystem subsystem,Semantics semantics,const wchar_t * pattern)355 ResultCode PolicyBase::AddRule(SubSystem subsystem,
356                                Semantics semantics,
357                                const wchar_t* pattern) {
358   ResultCode result = AddRuleInternal(subsystem, semantics, pattern);
359   LOG_IF(ERROR, result != SBOX_ALL_OK)
360       << "Failed to add sandbox rule."
361       << " error = " << result << ", subsystem = " << subsystem
362       << ", semantics = " << semantics << ", pattern = '" << pattern << "'";
363   return result;
364 }
365 
AddDllToUnload(const wchar_t * dll_name)366 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
367   blocklisted_dlls_.push_back(dll_name);
368   return SBOX_ALL_OK;
369 }
370 
AddKernelObjectToClose(const wchar_t * handle_type,const wchar_t * handle_name)371 ResultCode PolicyBase::AddKernelObjectToClose(const wchar_t* handle_type,
372                                               const wchar_t* handle_name) {
373   return handle_closer_.AddHandle(handle_type, handle_name);
374 }
375 
AddHandleToShare(HANDLE handle)376 void PolicyBase::AddHandleToShare(HANDLE handle) {
377   CHECK(handle);
378   CHECK_NE(handle, INVALID_HANDLE_VALUE);
379 
380   // Ensure the handle can be inherited.
381   bool result =
382       SetHandleInformation(handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
383   PCHECK(result);
384 
385   handles_to_share_.push_back(handle);
386 }
387 
SetLockdownDefaultDacl()388 void PolicyBase::SetLockdownDefaultDacl() {
389   lockdown_default_dacl_ = true;
390 }
391 
AddRestrictingRandomSid()392 void PolicyBase::AddRestrictingRandomSid() {
393   add_restricting_random_sid_ = true;
394 }
395 
GetHandlesBeingShared()396 const base::HandlesToInheritVector& PolicyBase::GetHandlesBeingShared() {
397   return handles_to_share_;
398 }
399 
MakeJobObject(base::win::ScopedHandle * job)400 ResultCode PolicyBase::MakeJobObject(base::win::ScopedHandle* job) {
401   if (job_level_ == JOB_NONE) {
402     job->Close();
403     return SBOX_ALL_OK;
404   }
405 
406   // Create the windows job object.
407   Job job_obj;
408   DWORD result =
409       job_obj.Init(job_level_, nullptr, ui_exceptions_, memory_limit_);
410   if (ERROR_SUCCESS != result)
411     return SBOX_ERROR_CANNOT_INIT_JOB;
412 
413   *job = job_obj.Take();
414   return SBOX_ALL_OK;
415 }
416 
DropActiveProcessLimit(base::win::ScopedHandle * job)417 ResultCode PolicyBase::DropActiveProcessLimit(base::win::ScopedHandle* job) {
418   if (job_level_ >= JOB_INTERACTIVE)
419     return SBOX_ALL_OK;
420 
421   if (ERROR_SUCCESS != Job::SetActiveProcessLimit(job, 0))
422     return SBOX_ERROR_CANNOT_UPDATE_JOB_PROCESS_LIMIT;
423 
424   return SBOX_ALL_OK;
425 }
426 
MakeTokens(base::win::ScopedHandle * initial,base::win::ScopedHandle * lockdown,base::win::ScopedHandle * lowbox)427 ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
428                                   base::win::ScopedHandle* lockdown,
429                                   base::win::ScopedHandle* lowbox) {
430   Sid random_sid = Sid::GenerateRandomSid();
431   PSID random_sid_ptr = nullptr;
432   if (add_restricting_random_sid_)
433     random_sid_ptr = random_sid.GetPSID();
434 
435   // Create the 'naked' token. This will be the permanent token associated
436   // with the process and therefore with any thread that is not impersonating.
437   DWORD result = CreateRestrictedToken(
438       effective_token_, lockdown_level_, integrity_level_, PRIMARY,
439       lockdown_default_dacl_, random_sid_ptr, lockdown);
440   if (ERROR_SUCCESS != result)
441     return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN;
442 
443   // If we're launching on the alternate desktop we need to make sure the
444   // integrity label on the object is no higher than the sandboxed process's
445   // integrity level. So, we lower the label on the desktop process if it's
446   // not already low enough for our process.
447   if (use_alternate_desktop_ && integrity_level_ != INTEGRITY_LEVEL_LAST) {
448     // Integrity label enum is reversed (higher level is a lower value).
449     static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED,
450                   "Integrity level ordering reversed.");
451     HDESK desktop_handle = nullptr;
452     IntegrityLevel desktop_integrity_level_label;
453     if (use_alternate_winstation_) {
454       desktop_handle = alternate_desktop_handle_;
455       desktop_integrity_level_label = alternate_desktop_integrity_level_label_;
456     } else {
457       desktop_handle = alternate_desktop_local_winstation_handle_;
458       desktop_integrity_level_label =
459           alternate_desktop_local_winstation_integrity_level_label_;
460     }
461     // If the desktop_handle hasn't been created for any reason, skip this.
462     if (desktop_handle && desktop_integrity_level_label < integrity_level_) {
463       result =
464           SetObjectIntegrityLabel(desktop_handle, SE_WINDOW_OBJECT, L"",
465                                   GetIntegrityLevelString(integrity_level_));
466       if (ERROR_SUCCESS != result)
467         return SBOX_ERROR_CANNOT_SET_DESKTOP_INTEGRITY;
468 
469       if (use_alternate_winstation_) {
470         alternate_desktop_integrity_level_label_ = integrity_level_;
471       } else {
472         alternate_desktop_local_winstation_integrity_level_label_ =
473             integrity_level_;
474       }
475     }
476   }
477 
478   if (lowbox_sid_) {
479     if (!lowbox_directory_.IsValid()) {
480       result =
481           CreateLowBoxObjectDirectory(lowbox_sid_, true, &lowbox_directory_);
482       DCHECK(result == ERROR_SUCCESS);
483     }
484 
485     // The order of handles isn't important in the CreateLowBoxToken call.
486     // The kernel will maintain a reference to the object directory handle.
487     HANDLE saved_handles[1] = {lowbox_directory_.Get()};
488     DWORD saved_handles_count = lowbox_directory_.IsValid() ? 1 : 0;
489 
490     Sid package_sid(lowbox_sid_);
491     SecurityCapabilities caps(package_sid);
492     if (CreateLowBoxToken(lockdown->Get(), PRIMARY, &caps, saved_handles,
493                           saved_handles_count, lowbox) != ERROR_SUCCESS) {
494       return SBOX_ERROR_CANNOT_CREATE_LOWBOX_TOKEN;
495     }
496 
497     if (!ReplacePackageSidInDacl(lowbox->Get(), SE_KERNEL_OBJECT, package_sid,
498                                  TOKEN_ALL_ACCESS)) {
499       return SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL;
500     }
501   }
502 
503   // Create the 'better' token. We use this token as the one that the main
504   // thread uses when booting up the process. It should contain most of
505   // what we need (before reaching main( ))
506   result = CreateRestrictedToken(
507       effective_token_, initial_level_, integrity_level_, IMPERSONATION,
508       lockdown_default_dacl_, random_sid_ptr, initial);
509   if (ERROR_SUCCESS != result)
510     return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN;
511 
512   return SBOX_ALL_OK;
513 }
514 
GetLowBoxSid() const515 PSID PolicyBase::GetLowBoxSid() const {
516   return lowbox_sid_;
517 }
518 
AddTarget(std::unique_ptr<TargetProcess> target)519 ResultCode PolicyBase::AddTarget(std::unique_ptr<TargetProcess> target) {
520   if (policy_) {
521     if (!policy_maker_->Done())
522       return SBOX_ERROR_NO_SPACE;
523   }
524 
525   if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
526                                                  mitigations_)) {
527     return SBOX_ERROR_APPLY_ASLR_MITIGATIONS;
528   }
529 
530   ResultCode ret = SetupAllInterceptions(*target);
531 
532   if (ret != SBOX_ALL_OK)
533     return ret;
534 
535   if (!SetupHandleCloser(*target))
536     return SBOX_ERROR_SETUP_HANDLE_CLOSER;
537 
538   DWORD win_error = ERROR_SUCCESS;
539   // Initialize the sandbox infrastructure for the target.
540   // TODO(wfh) do something with win_error code here.
541   ret = target->Init(dispatcher_.get(), policy_, kIPCMemSize, kPolMemSize,
542                      &win_error);
543 
544   if (ret != SBOX_ALL_OK)
545     return ret;
546 
547   g_shared_delayed_integrity_level = delayed_integrity_level_;
548   ret = target->TransferVariable("g_shared_delayed_integrity_level",
549                                  &g_shared_delayed_integrity_level,
550                                  sizeof(g_shared_delayed_integrity_level));
551   g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
552   if (SBOX_ALL_OK != ret)
553     return ret;
554 
555   // Add in delayed mitigations and pseudo-mitigations enforced at startup.
556   g_shared_delayed_mitigations =
557       delayed_mitigations_ | FilterPostStartupProcessMitigations(mitigations_);
558   if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
559     return SBOX_ERROR_BAD_PARAMS;
560 
561   ret = target->TransferVariable("g_shared_delayed_mitigations",
562                                  &g_shared_delayed_mitigations,
563                                  sizeof(g_shared_delayed_mitigations));
564   g_shared_delayed_mitigations = 0;
565   if (SBOX_ALL_OK != ret)
566     return ret;
567 
568   AutoLock lock(&lock_);
569   targets_.push_back(std::move(target));
570   return SBOX_ALL_OK;
571 }
572 
OnJobEmpty(HANDLE job)573 bool PolicyBase::OnJobEmpty(HANDLE job) {
574   AutoLock lock(&lock_);
575   targets_.erase(
576       std::remove_if(targets_.begin(), targets_.end(),
577                      [&](auto&& p) -> bool { return p->Job() == job; }),
578       targets_.end());
579   return true;
580 }
581 
OnProcessFinished(DWORD process_id)582 bool PolicyBase::OnProcessFinished(DWORD process_id) {
583   AutoLock lock(&lock_);
584   targets_.erase(std::remove_if(targets_.begin(), targets_.end(),
585                                 [&](auto&& p) -> bool {
586                                   return p->ProcessId() == process_id;
587                                 }),
588                  targets_.end());
589   return true;
590 }
591 
SetDisconnectCsrss()592 ResultCode PolicyBase::SetDisconnectCsrss() {
593 // Does not work on 32-bit, and the ASAN runtime falls over with the
594 // CreateThread EAT patch used when this is enabled.
595 // See https://crbug.com/783296#c27.
596 #if defined(_WIN64) && !defined(ADDRESS_SANITIZER)
597   if (base::win::GetVersion() >= base::win::Version::WIN10) {
598     is_csrss_connected_ = false;
599     return AddKernelObjectToClose(L"ALPC Port", nullptr);
600   }
601 #endif  // !defined(_WIN64)
602   return SBOX_ALL_OK;
603 }
604 
EvalPolicy(IpcTag service,CountedParameterSetBase * params)605 EvalResult PolicyBase::EvalPolicy(IpcTag service,
606                                   CountedParameterSetBase* params) {
607   if (policy_) {
608     if (!policy_->entry[static_cast<size_t>(service)]) {
609       // There is no policy for this particular service. This is not a big
610       // deal.
611       return DENY_ACCESS;
612     }
613     for (size_t i = 0; i < params->count; i++) {
614       if (!params->parameters[i].IsValid()) {
615         NOTREACHED();
616         return SIGNAL_ALARM;
617       }
618     }
619     PolicyProcessor pol_evaluator(policy_->entry[static_cast<size_t>(service)]);
620     PolicyResult result =
621         pol_evaluator.Evaluate(kShortEval, params->parameters, params->count);
622     if (POLICY_MATCH == result)
623       return pol_evaluator.GetAction();
624 
625     DCHECK(POLICY_ERROR != result);
626   }
627 
628   return DENY_ACCESS;
629 }
630 
GetStdoutHandle()631 HANDLE PolicyBase::GetStdoutHandle() {
632   return stdout_handle_;
633 }
634 
GetStderrHandle()635 HANDLE PolicyBase::GetStderrHandle() {
636   return stderr_handle_;
637 }
638 
SetEnableOPMRedirection()639 void PolicyBase::SetEnableOPMRedirection() {
640   enable_opm_redirection_ = true;
641 }
642 
GetEnableOPMRedirection()643 bool PolicyBase::GetEnableOPMRedirection() {
644   return enable_opm_redirection_;
645 }
646 
AddAppContainerProfile(const wchar_t * package_name,bool create_profile)647 ResultCode PolicyBase::AddAppContainerProfile(const wchar_t* package_name,
648                                               bool create_profile) {
649   if (base::win::GetVersion() < base::win::Version::WIN8)
650     return SBOX_ERROR_UNSUPPORTED;
651 
652   DCHECK(package_name);
653   if (lowbox_sid_ || app_container_profile_ ||
654       integrity_level_ != INTEGRITY_LEVEL_LAST) {
655     return SBOX_ERROR_BAD_PARAMS;
656   }
657 
658   if (create_profile) {
659     app_container_profile_ = AppContainerProfileBase::Create(
660         package_name, L"Chrome Sandbox", L"Profile for Chrome Sandbox");
661   } else {
662     app_container_profile_ = AppContainerProfileBase::Open(package_name);
663   }
664   if (!app_container_profile_)
665     return SBOX_ERROR_CREATE_APPCONTAINER_PROFILE;
666 
667   // A bug exists in CreateProcess where enabling an AppContainer profile and
668   // passing a set of mitigation flags will generate ERROR_INVALID_PARAMETER.
669   // Apply best efforts here and convert set mitigations to delayed mitigations.
670   // This bug looks to have been fixed in Win10 RS5, so exit early if possible.
671   if (base::win::GetVersion() >= base::win::Version::WIN10_RS5)
672     return SBOX_ALL_OK;
673 
674   delayed_mitigations_ =
675       mitigations_ & GetAllowedPostStartupProcessMitigations();
676   DCHECK(delayed_mitigations_ ==
677          (mitigations_ & ~(MITIGATION_SEHOP |
678                            MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION)));
679   mitigations_ = 0;
680   return SBOX_ALL_OK;
681 }
682 
GetAppContainerProfile()683 scoped_refptr<AppContainerProfile> PolicyBase::GetAppContainerProfile() {
684   return GetAppContainerProfileBase();
685 }
686 
SetEffectiveToken(HANDLE token)687 void PolicyBase::SetEffectiveToken(HANDLE token) {
688   CHECK(token);
689   effective_token_ = token;
690 }
691 
692 scoped_refptr<AppContainerProfileBase>
GetAppContainerProfileBase()693 PolicyBase::GetAppContainerProfileBase() {
694   return app_container_profile_;
695 }
696 
SetupAllInterceptions(TargetProcess & target)697 ResultCode PolicyBase::SetupAllInterceptions(TargetProcess& target) {
698   InterceptionManager manager(target, relaxed_interceptions_);
699 
700   if (policy_) {
701     for (size_t i = 0; i < kMaxIpcTag; i++) {
702       if (policy_->entry[i] &&
703           !dispatcher_->SetupService(&manager, static_cast<IpcTag>(i)))
704         return SBOX_ERROR_SETUP_INTERCEPTION_SERVICE;
705     }
706   }
707 
708   for (const std::wstring& dll : blocklisted_dlls_)
709     manager.AddToUnloadModules(dll.c_str());
710 
711   if (!SetupBasicInterceptions(&manager, is_csrss_connected_))
712     return SBOX_ERROR_SETUP_BASIC_INTERCEPTIONS;
713 
714   ResultCode rc = manager.InitializeInterceptions();
715   if (rc != SBOX_ALL_OK)
716     return rc;
717 
718   // Finally, setup imports on the target so the interceptions can work.
719   if (!SetupNtdllImports(target))
720     return SBOX_ERROR_SETUP_NTDLL_IMPORTS;
721 
722   return SBOX_ALL_OK;
723 }
724 
SetupHandleCloser(TargetProcess & target)725 bool PolicyBase::SetupHandleCloser(TargetProcess& target) {
726   return handle_closer_.InitializeTargetHandles(target);
727 }
728 
AddRuleInternal(SubSystem subsystem,Semantics semantics,const wchar_t * pattern)729 ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
730                                        Semantics semantics,
731                                        const wchar_t* pattern) {
732   if (!policy_) {
733     policy_ = MakeBrokerPolicyMemory();
734     DCHECK(policy_);
735     policy_maker_ = new LowLevelPolicy(policy_);
736     DCHECK(policy_maker_);
737   }
738 
739   switch (subsystem) {
740     case SUBSYS_FILES: {
741       if (!file_system_init_) {
742         if (!FileSystemPolicy::SetInitialRules(policy_maker_))
743           return SBOX_ERROR_BAD_PARAMS;
744         file_system_init_ = true;
745       }
746       if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
747         NOTREACHED();
748         return SBOX_ERROR_BAD_PARAMS;
749       }
750       break;
751     }
752     case SUBSYS_SYNC: {
753       if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
754         NOTREACHED();
755         return SBOX_ERROR_BAD_PARAMS;
756       }
757       break;
758     }
759     case SUBSYS_PROCESS: {
760       if (lockdown_level_ < USER_INTERACTIVE &&
761           TargetPolicy::PROCESS_ALL_EXEC == semantics) {
762         // This is unsupported. This is a huge security risk to give full access
763         // to a process handle.
764         return SBOX_ERROR_UNSUPPORTED;
765       }
766       if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
767         NOTREACHED();
768         return SBOX_ERROR_BAD_PARAMS;
769       }
770       break;
771     }
772     case SUBSYS_NAMED_PIPES: {
773       if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
774         NOTREACHED();
775         return SBOX_ERROR_BAD_PARAMS;
776       }
777       break;
778     }
779     case SUBSYS_REGISTRY: {
780       if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
781         NOTREACHED();
782         return SBOX_ERROR_BAD_PARAMS;
783       }
784       break;
785     }
786     case SUBSYS_WIN32K_LOCKDOWN: {
787       // Win32k intercept rules only supported on Windows 8 and above. This must
788       // match the version checks in process_mitigations.cc for consistency.
789       if (base::win::GetVersion() >= base::win::Version::WIN8) {
790         DCHECK_EQ(MITIGATION_WIN32K_DISABLE,
791                   mitigations_ & MITIGATION_WIN32K_DISABLE)
792             << "Enable MITIGATION_WIN32K_DISABLE before adding win32k policy "
793                "rules.";
794         if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
795                 pattern, semantics, policy_maker_)) {
796           NOTREACHED();
797           return SBOX_ERROR_BAD_PARAMS;
798         }
799       }
800       break;
801     }
802     case SUBSYS_SIGNED_BINARY: {
803       // Signed intercept rules only supported on Windows 10 TH2 and above. This
804       // must match the version checks in process_mitigations.cc for
805       // consistency.
806       if (base::win::GetVersion() >= base::win::Version::WIN10_TH2) {
807         DCHECK_EQ(MITIGATION_FORCE_MS_SIGNED_BINS,
808                   mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS)
809             << "Enable MITIGATION_FORCE_MS_SIGNED_BINS before adding signed "
810                "policy rules.";
811         if (!SignedPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
812           NOTREACHED();
813           return SBOX_ERROR_BAD_PARAMS;
814         }
815       }
816       break;
817     }
818 
819     default: { return SBOX_ERROR_UNSUPPORTED; }
820   }
821 
822   return SBOX_ALL_OK;
823 }
824 
GetPolicyInfo()825 std::unique_ptr<PolicyInfo> PolicyBase::GetPolicyInfo() {
826   auto diagnostic = std::make_unique<PolicyDiagnostic>(this);
827   return diagnostic;
828 }
829 
830 }  // namespace sandbox
831