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