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