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