Record MTU discovery packets in net-internals log.
[chromium-blink-merge.git] / sandbox / win / src / sandbox_policy_base.cc
blobfcc4a7c651acd5f600279d2e2290f77bf05aa0c9
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.
5 #include "sandbox/win/src/sandbox_policy_base.h"
7 #include <sddl.h>
9 #include "base/basictypes.h"
10 #include "base/callback.h"
11 #include "base/logging.h"
12 #include "base/stl_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/win/windows_version.h"
15 #include "sandbox/win/src/app_container.h"
16 #include "sandbox/win/src/filesystem_dispatcher.h"
17 #include "sandbox/win/src/filesystem_policy.h"
18 #include "sandbox/win/src/handle_dispatcher.h"
19 #include "sandbox/win/src/handle_policy.h"
20 #include "sandbox/win/src/job.h"
21 #include "sandbox/win/src/interception.h"
22 #include "sandbox/win/src/process_mitigations.h"
23 #include "sandbox/win/src/named_pipe_dispatcher.h"
24 #include "sandbox/win/src/named_pipe_policy.h"
25 #include "sandbox/win/src/policy_broker.h"
26 #include "sandbox/win/src/policy_engine_processor.h"
27 #include "sandbox/win/src/policy_low_level.h"
28 #include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
29 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
30 #include "sandbox/win/src/process_thread_dispatcher.h"
31 #include "sandbox/win/src/process_thread_policy.h"
32 #include "sandbox/win/src/registry_dispatcher.h"
33 #include "sandbox/win/src/registry_policy.h"
34 #include "sandbox/win/src/restricted_token_utils.h"
35 #include "sandbox/win/src/sandbox_policy.h"
36 #include "sandbox/win/src/sandbox_utils.h"
37 #include "sandbox/win/src/sync_dispatcher.h"
38 #include "sandbox/win/src/sync_policy.h"
39 #include "sandbox/win/src/target_process.h"
40 #include "sandbox/win/src/window.h"
42 namespace {
44 // The standard windows size for one memory page.
45 const size_t kOneMemPage = 4096;
46 // The IPC and Policy shared memory sizes.
47 const size_t kIPCMemSize = kOneMemPage * 2;
48 const size_t kPolMemSize = kOneMemPage * 14;
50 // Helper function to allocate space (on the heap) for policy.
51 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
52 const size_t kTotalPolicySz = kPolMemSize;
53 sandbox::PolicyGlobal* policy = static_cast<sandbox::PolicyGlobal*>
54 (::operator new(kTotalPolicySz));
55 DCHECK(policy);
56 memset(policy, 0, kTotalPolicySz);
57 policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
58 return policy;
61 bool IsInheritableHandle(HANDLE handle) {
62 if (!handle)
63 return false;
64 if (handle == INVALID_HANDLE_VALUE)
65 return false;
66 // File handles (FILE_TYPE_DISK) and pipe handles are known to be
67 // inheritable. Console handles (FILE_TYPE_CHAR) are not
68 // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
69 DWORD handle_type = GetFileType(handle);
70 return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
73 HANDLE CreateLowBoxObjectDirectory(PSID lowbox_sid) {
74 DWORD session_id = 0;
75 if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id))
76 return NULL;
78 LPWSTR sid_string = NULL;
79 if (!::ConvertSidToStringSid(lowbox_sid, &sid_string))
80 return NULL;
82 base::string16 directory_path = base::StringPrintf(
83 L"\\Sessions\\%d\\AppContainerNamedObjects\\%ls",
84 session_id, sid_string).c_str();
85 ::LocalFree(sid_string);
87 NtCreateDirectoryObjectFunction CreateObjectDirectory = NULL;
88 ResolveNTFunctionPtr("NtCreateDirectoryObject", &CreateObjectDirectory);
90 OBJECT_ATTRIBUTES obj_attr;
91 UNICODE_STRING obj_name;
92 sandbox::InitObjectAttribs(directory_path,
93 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
94 NULL,
95 &obj_attr,
96 &obj_name,
97 NULL);
99 HANDLE handle = NULL;
100 NTSTATUS status = CreateObjectDirectory(&handle,
101 DIRECTORY_ALL_ACCESS,
102 &obj_attr);
104 if (!NT_SUCCESS(status))
105 return NULL;
107 return handle;
112 namespace sandbox {
114 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
115 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
117 // Initializes static members.
118 HWINSTA PolicyBase::alternate_winstation_handle_ = NULL;
119 HDESK PolicyBase::alternate_desktop_handle_ = NULL;
120 IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
121 INTEGRITY_LEVEL_SYSTEM;
123 PolicyBase::PolicyBase()
124 : ref_count(1),
125 lockdown_level_(USER_LOCKDOWN),
126 initial_level_(USER_LOCKDOWN),
127 job_level_(JOB_LOCKDOWN),
128 ui_exceptions_(0),
129 memory_limit_(0),
130 use_alternate_desktop_(false),
131 use_alternate_winstation_(false),
132 file_system_init_(false),
133 relaxed_interceptions_(true),
134 stdout_handle_(INVALID_HANDLE_VALUE),
135 stderr_handle_(INVALID_HANDLE_VALUE),
136 integrity_level_(INTEGRITY_LEVEL_LAST),
137 delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
138 mitigations_(0),
139 delayed_mitigations_(0),
140 policy_maker_(NULL),
141 policy_(NULL),
142 lowbox_sid_(NULL) {
143 ::InitializeCriticalSection(&lock_);
144 // Initialize the IPC dispatcher array.
145 memset(&ipc_targets_, NULL, sizeof(ipc_targets_));
146 Dispatcher* dispatcher = NULL;
148 dispatcher = new FilesystemDispatcher(this);
149 ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher;
150 ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher;
151 ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher;
152 ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher;
153 ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher;
155 dispatcher = new NamedPipeDispatcher(this);
156 ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher;
158 dispatcher = new ThreadProcessDispatcher(this);
159 ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher;
160 ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher;
161 ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher;
162 ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher;
163 ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher;
165 dispatcher = new SyncDispatcher(this);
166 ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher;
167 ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
169 dispatcher = new RegistryDispatcher(this);
170 ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
171 ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
173 dispatcher = new HandleDispatcher(this);
174 ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
176 dispatcher = new ProcessMitigationsWin32KDispatcher(this);
177 ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
178 ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
179 ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
182 PolicyBase::~PolicyBase() {
183 ClearSharedHandles();
185 TargetSet::iterator it;
186 for (it = targets_.begin(); it != targets_.end(); ++it) {
187 TargetProcess* target = (*it);
188 delete target;
190 delete ipc_targets_[IPC_NTCREATEFILE_TAG];
191 delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG];
192 delete ipc_targets_[IPC_NTOPENTHREAD_TAG];
193 delete ipc_targets_[IPC_CREATEEVENT_TAG];
194 delete ipc_targets_[IPC_NTCREATEKEY_TAG];
195 delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG];
196 delete policy_maker_;
197 delete policy_;
199 if (lowbox_sid_)
200 ::LocalFree(lowbox_sid_);
202 ::DeleteCriticalSection(&lock_);
205 void PolicyBase::AddRef() {
206 ::InterlockedIncrement(&ref_count);
209 void PolicyBase::Release() {
210 if (0 == ::InterlockedDecrement(&ref_count))
211 delete this;
214 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
215 if (initial < lockdown) {
216 return SBOX_ERROR_BAD_PARAMS;
218 initial_level_ = initial;
219 lockdown_level_ = lockdown;
220 return SBOX_ALL_OK;
223 TokenLevel PolicyBase::GetInitialTokenLevel() const {
224 return initial_level_;
227 TokenLevel PolicyBase::GetLockdownTokenLevel() const{
228 return lockdown_level_;
231 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
232 if (memory_limit_ && job_level == JOB_NONE) {
233 return SBOX_ERROR_BAD_PARAMS;
235 job_level_ = job_level;
236 ui_exceptions_ = ui_exceptions;
237 return SBOX_ALL_OK;
240 ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
241 if (memory_limit && job_level_ == JOB_NONE) {
242 return SBOX_ERROR_BAD_PARAMS;
244 memory_limit_ = memory_limit;
245 return SBOX_ALL_OK;
248 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
249 use_alternate_desktop_ = true;
250 use_alternate_winstation_ = alternate_winstation;
251 return CreateAlternateDesktop(alternate_winstation);
254 base::string16 PolicyBase::GetAlternateDesktop() const {
255 // No alternate desktop or winstation. Return an empty string.
256 if (!use_alternate_desktop_ && !use_alternate_winstation_) {
257 return base::string16();
260 // The desktop and winstation should have been created by now.
261 // If we hit this scenario, it means that the user ignored the failure
262 // during SetAlternateDesktop, so we ignore it here too.
263 if (use_alternate_desktop_ && !alternate_desktop_handle_) {
264 return base::string16();
266 if (use_alternate_winstation_ && (!alternate_desktop_handle_ ||
267 !alternate_winstation_handle_)) {
268 return base::string16();
271 return GetFullDesktopName(alternate_winstation_handle_,
272 alternate_desktop_handle_);
275 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
276 if (alternate_winstation) {
277 // Previously called with alternate_winstation = false?
278 if (!alternate_winstation_handle_ && alternate_desktop_handle_)
279 return SBOX_ERROR_UNSUPPORTED;
281 // Check if it's already created.
282 if (alternate_winstation_handle_ && alternate_desktop_handle_)
283 return SBOX_ALL_OK;
285 DCHECK(!alternate_winstation_handle_);
286 // Create the window station.
287 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
288 if (SBOX_ALL_OK != result)
289 return result;
291 // Verify that everything is fine.
292 if (!alternate_winstation_handle_ ||
293 GetWindowObjectName(alternate_winstation_handle_).empty())
294 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
296 // Create the destkop.
297 result = CreateAltDesktop(alternate_winstation_handle_,
298 &alternate_desktop_handle_);
299 if (SBOX_ALL_OK != result)
300 return result;
302 // Verify that everything is fine.
303 if (!alternate_desktop_handle_ ||
304 GetWindowObjectName(alternate_desktop_handle_).empty())
305 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
306 } else {
307 // Previously called with alternate_winstation = true?
308 if (alternate_winstation_handle_)
309 return SBOX_ERROR_UNSUPPORTED;
311 // Check if it already exists.
312 if (alternate_desktop_handle_)
313 return SBOX_ALL_OK;
315 // Create the destkop.
316 ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_);
317 if (SBOX_ALL_OK != result)
318 return result;
320 // Verify that everything is fine.
321 if (!alternate_desktop_handle_ ||
322 GetWindowObjectName(alternate_desktop_handle_).empty())
323 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
326 return SBOX_ALL_OK;
329 void PolicyBase::DestroyAlternateDesktop() {
330 if (alternate_desktop_handle_) {
331 ::CloseDesktop(alternate_desktop_handle_);
332 alternate_desktop_handle_ = NULL;
335 if (alternate_winstation_handle_) {
336 ::CloseWindowStation(alternate_winstation_handle_);
337 alternate_winstation_handle_ = NULL;
341 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
342 integrity_level_ = integrity_level;
343 return SBOX_ALL_OK;
346 IntegrityLevel PolicyBase::GetIntegrityLevel() const {
347 return integrity_level_;
350 ResultCode PolicyBase::SetDelayedIntegrityLevel(
351 IntegrityLevel integrity_level) {
352 delayed_integrity_level_ = integrity_level;
353 return SBOX_ALL_OK;
356 ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) {
357 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
358 return SBOX_ALL_OK;
360 // SetLowBox and SetAppContainer are mutually exclusive.
361 if (lowbox_sid_)
362 return SBOX_ERROR_UNSUPPORTED;
364 // Windows refuses to work with an impersonation token for a process inside
365 // an AppContainer. If the caller wants to use a more privileged initial
366 // token, or if the lockdown level will prevent the process from starting,
367 // we have to fail the operation.
368 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
369 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
371 DCHECK(!appcontainer_list_.get());
372 appcontainer_list_.reset(new AppContainerAttributes);
373 ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_);
374 if (rv != SBOX_ALL_OK)
375 return rv;
377 return SBOX_ALL_OK;
380 ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
381 capabilities_.push_back(sid);
382 return SBOX_ALL_OK;
385 ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
386 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
387 return SBOX_ERROR_UNSUPPORTED;
389 // SetLowBox and SetAppContainer are mutually exclusive.
390 if (appcontainer_list_.get())
391 return SBOX_ERROR_UNSUPPORTED;
393 DCHECK(sid);
395 if (lowbox_sid_)
396 return SBOX_ERROR_BAD_PARAMS;
398 if (!ConvertStringSidToSid(sid, &lowbox_sid_))
399 return SBOX_ERROR_GENERIC;
401 return SBOX_ALL_OK;
404 ResultCode PolicyBase::SetProcessMitigations(
405 MitigationFlags flags) {
406 if (!CanSetProcessMitigationsPreStartup(flags))
407 return SBOX_ERROR_BAD_PARAMS;
408 mitigations_ = flags;
409 return SBOX_ALL_OK;
412 MitigationFlags PolicyBase::GetProcessMitigations() {
413 return mitigations_;
416 ResultCode PolicyBase::SetDelayedProcessMitigations(
417 MitigationFlags flags) {
418 if (!CanSetProcessMitigationsPostStartup(flags))
419 return SBOX_ERROR_BAD_PARAMS;
420 delayed_mitigations_ = flags;
421 return SBOX_ALL_OK;
424 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
425 return delayed_mitigations_;
428 void PolicyBase::SetStrictInterceptions() {
429 relaxed_interceptions_ = false;
432 ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
433 if (!IsInheritableHandle(handle))
434 return SBOX_ERROR_BAD_PARAMS;
435 stdout_handle_ = handle;
436 return SBOX_ALL_OK;
439 ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
440 if (!IsInheritableHandle(handle))
441 return SBOX_ERROR_BAD_PARAMS;
442 stderr_handle_ = handle;
443 return SBOX_ALL_OK;
446 ResultCode PolicyBase::AddRule(SubSystem subsystem,
447 Semantics semantics,
448 const wchar_t* pattern) {
449 ResultCode result = AddRuleInternal(subsystem, semantics, pattern);
450 LOG_IF(ERROR, result != SBOX_ALL_OK) << "Failed to add sandbox rule."
451 << " error = " << result
452 << ", subsystem = " << subsystem
453 << ", semantics = " << semantics
454 << ", pattern = '" << pattern << "'";
455 return result;
458 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
459 blacklisted_dlls_.push_back(dll_name);
460 return SBOX_ALL_OK;
463 ResultCode PolicyBase::AddKernelObjectToClose(const base::char16* handle_type,
464 const base::char16* handle_name) {
465 return handle_closer_.AddHandle(handle_type, handle_name);
468 void* PolicyBase::AddHandleToShare(HANDLE handle) {
469 if (base::win::GetVersion() < base::win::VERSION_VISTA)
470 return nullptr;
472 if (!handle)
473 return nullptr;
475 HANDLE duped_handle = nullptr;
476 if (!::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(),
477 &duped_handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
478 return nullptr;
480 handles_to_share_.push_back(new base::win::ScopedHandle(duped_handle));
481 return duped_handle;
484 const HandleList& PolicyBase::GetHandlesBeingShared() {
485 return handles_to_share_;
488 void PolicyBase::ClearSharedHandles() {
489 STLDeleteElements(&handles_to_share_);
492 // When an IPC is ready in any of the targets we get called. We manage an array
493 // of IPC dispatchers which are keyed on the IPC tag so we normally delegate
494 // to the appropriate dispatcher unless we can handle the IPC call ourselves.
495 Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc,
496 CallbackGeneric* callback) {
497 DCHECK(callback);
498 static const IPCParams ping1 = {IPC_PING1_TAG, {UINT32_TYPE}};
499 static const IPCParams ping2 = {IPC_PING2_TAG, {INOUTPTR_TYPE}};
501 if (ping1.Matches(ipc) || ping2.Matches(ipc)) {
502 *callback = reinterpret_cast<CallbackGeneric>(
503 static_cast<Callback1>(&PolicyBase::Ping));
504 return this;
507 Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag);
508 if (!dispatch) {
509 NOTREACHED();
510 return NULL;
512 return dispatch->OnMessageReady(ipc, callback);
515 // Delegate to the appropriate dispatcher.
516 bool PolicyBase::SetupService(InterceptionManager* manager, int service) {
517 if (IPC_PING1_TAG == service || IPC_PING2_TAG == service)
518 return true;
520 Dispatcher* dispatch = GetDispatcher(service);
521 if (!dispatch) {
522 NOTREACHED();
523 return false;
525 return dispatch->SetupService(manager, service);
528 ResultCode PolicyBase::MakeJobObject(HANDLE* job) {
529 if (job_level_ != JOB_NONE) {
530 // Create the windows job object.
531 Job job_obj;
532 DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_,
533 memory_limit_);
534 if (ERROR_SUCCESS != result) {
535 return SBOX_ERROR_GENERIC;
537 *job = job_obj.Detach();
538 } else {
539 *job = NULL;
541 return SBOX_ALL_OK;
544 ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
545 base::win::ScopedHandle* lockdown) {
546 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer() &&
547 lowbox_sid_) {
548 return SBOX_ERROR_BAD_PARAMS;
551 // Create the 'naked' token. This will be the permanent token associated
552 // with the process and therefore with any thread that is not impersonating.
553 HANDLE temp_handle;
554 DWORD result = CreateRestrictedToken(&temp_handle, lockdown_level_,
555 integrity_level_, PRIMARY);
556 if (ERROR_SUCCESS != result)
557 return SBOX_ERROR_GENERIC;
559 lockdown->Set(temp_handle);
561 // If we're launching on the alternate desktop we need to make sure the
562 // integrity label on the object is no higher than the sandboxed process's
563 // integrity level. So, we lower the label on the desktop process if it's
564 // not already low enough for our process.
565 if (alternate_desktop_handle_ && use_alternate_desktop_ &&
566 integrity_level_ != INTEGRITY_LEVEL_LAST &&
567 alternate_desktop_integrity_level_label_ < integrity_level_ &&
568 base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
569 // Integrity label enum is reversed (higher level is a lower value).
570 static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED,
571 "Integrity level ordering reversed.");
572 result = SetObjectIntegrityLabel(alternate_desktop_handle_,
573 SE_WINDOW_OBJECT,
574 L"",
575 GetIntegrityLevelString(integrity_level_));
576 if (ERROR_SUCCESS != result)
577 return SBOX_ERROR_GENERIC;
579 alternate_desktop_integrity_level_label_ = integrity_level_;
582 // We are maintaining two mutually exclusive approaches. One is to start an
583 // AppContainer process through StartupInfoEx and other is replacing
584 // existing token with LowBox token after process creation.
585 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) {
586 // Windows refuses to work with an impersonation token. See SetAppContainer
587 // implementation for more details.
588 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
589 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
591 *initial = base::win::ScopedHandle();
592 return SBOX_ALL_OK;
595 if (lowbox_sid_) {
596 NtCreateLowBoxToken CreateLowBoxToken = NULL;
597 ResolveNTFunctionPtr("NtCreateLowBoxToken", &CreateLowBoxToken);
598 OBJECT_ATTRIBUTES obj_attr;
599 InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
600 HANDLE token_lowbox = NULL;
602 if (!lowbox_directory_.IsValid())
603 lowbox_directory_.Set(CreateLowBoxObjectDirectory(lowbox_sid_));
604 DCHECK(lowbox_directory_.IsValid());
606 // The order of handles isn't important in the CreateLowBoxToken call.
607 // The kernel will maintain a reference to the object directory handle.
608 HANDLE saved_handles[1] = {lowbox_directory_.Get()};
609 DWORD saved_handles_count = lowbox_directory_.IsValid() ? 1 : 0;
611 NTSTATUS status = CreateLowBoxToken(&token_lowbox, lockdown->Get(),
612 TOKEN_ALL_ACCESS, &obj_attr,
613 lowbox_sid_, 0, NULL,
614 saved_handles_count, saved_handles);
615 if (!NT_SUCCESS(status))
616 return SBOX_ERROR_GENERIC;
618 DCHECK(token_lowbox);
619 lockdown->Set(token_lowbox);
622 // Create the 'better' token. We use this token as the one that the main
623 // thread uses when booting up the process. It should contain most of
624 // what we need (before reaching main( ))
625 result = CreateRestrictedToken(&temp_handle, initial_level_,
626 integrity_level_, IMPERSONATION);
627 if (ERROR_SUCCESS != result)
628 return SBOX_ERROR_GENERIC;
630 initial->Set(temp_handle);
631 return SBOX_ALL_OK;
634 const AppContainerAttributes* PolicyBase::GetAppContainer() const {
635 if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
636 return NULL;
638 return appcontainer_list_.get();
641 const PSID PolicyBase::GetLowBoxSid() const {
642 return lowbox_sid_;
645 bool PolicyBase::AddTarget(TargetProcess* target) {
646 if (NULL != policy_)
647 policy_maker_->Done();
649 if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
650 mitigations_)) {
651 return false;
654 if (!SetupAllInterceptions(target))
655 return false;
657 if (!SetupHandleCloser(target))
658 return false;
660 // Initialize the sandbox infrastructure for the target.
661 if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize))
662 return false;
664 g_shared_delayed_integrity_level = delayed_integrity_level_;
665 ResultCode ret = target->TransferVariable(
666 "g_shared_delayed_integrity_level",
667 &g_shared_delayed_integrity_level,
668 sizeof(g_shared_delayed_integrity_level));
669 g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
670 if (SBOX_ALL_OK != ret)
671 return false;
673 // Add in delayed mitigations and pseudo-mitigations enforced at startup.
674 g_shared_delayed_mitigations = delayed_mitigations_ |
675 FilterPostStartupProcessMitigations(mitigations_);
676 if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
677 return false;
679 ret = target->TransferVariable("g_shared_delayed_mitigations",
680 &g_shared_delayed_mitigations,
681 sizeof(g_shared_delayed_mitigations));
682 g_shared_delayed_mitigations = 0;
683 if (SBOX_ALL_OK != ret)
684 return false;
686 AutoLock lock(&lock_);
687 targets_.push_back(target);
688 return true;
691 bool PolicyBase::OnJobEmpty(HANDLE job) {
692 AutoLock lock(&lock_);
693 TargetSet::iterator it;
694 for (it = targets_.begin(); it != targets_.end(); ++it) {
695 if ((*it)->Job() == job)
696 break;
698 if (it == targets_.end()) {
699 return false;
701 TargetProcess* target = *it;
702 targets_.erase(it);
703 delete target;
704 return true;
707 EvalResult PolicyBase::EvalPolicy(int service,
708 CountedParameterSetBase* params) {
709 if (NULL != policy_) {
710 if (NULL == policy_->entry[service]) {
711 // There is no policy for this particular service. This is not a big
712 // deal.
713 return DENY_ACCESS;
715 for (int i = 0; i < params->count; i++) {
716 if (!params->parameters[i].IsValid()) {
717 NOTREACHED();
718 return SIGNAL_ALARM;
721 PolicyProcessor pol_evaluator(policy_->entry[service]);
722 PolicyResult result = pol_evaluator.Evaluate(kShortEval,
723 params->parameters,
724 params->count);
725 if (POLICY_MATCH == result) {
726 return pol_evaluator.GetAction();
728 DCHECK(POLICY_ERROR != result);
731 return DENY_ACCESS;
734 HANDLE PolicyBase::GetStdoutHandle() {
735 return stdout_handle_;
738 HANDLE PolicyBase::GetStderrHandle() {
739 return stderr_handle_;
742 // We service IPC_PING_TAG message which is a way to test a round trip of the
743 // IPC subsystem. We receive a integer cookie and we are expected to return the
744 // cookie times two (or three) and the current tick count.
745 bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) {
746 switch (ipc->ipc_tag) {
747 case IPC_PING1_TAG: {
748 IPCInt ipc_int(arg1);
749 uint32 cookie = ipc_int.As32Bit();
750 ipc->return_info.extended_count = 2;
751 ipc->return_info.extended[0].unsigned_int = ::GetTickCount();
752 ipc->return_info.extended[1].unsigned_int = 2 * cookie;
753 return true;
755 case IPC_PING2_TAG: {
756 CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1);
757 if (sizeof(uint32) != io_buffer->Size())
758 return false;
760 uint32* cookie = reinterpret_cast<uint32*>(io_buffer->Buffer());
761 *cookie = (*cookie) * 3;
762 return true;
764 default: return false;
768 Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) {
769 if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG)
770 return NULL;
772 return ipc_targets_[ipc_tag];
775 bool PolicyBase::SetupAllInterceptions(TargetProcess* target) {
776 InterceptionManager manager(target, relaxed_interceptions_);
778 if (policy_) {
779 for (int i = 0; i < IPC_LAST_TAG; i++) {
780 if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i))
781 return false;
785 if (!blacklisted_dlls_.empty()) {
786 std::vector<base::string16>::iterator it = blacklisted_dlls_.begin();
787 for (; it != blacklisted_dlls_.end(); ++it) {
788 manager.AddToUnloadModules(it->c_str());
792 if (!SetupBasicInterceptions(&manager))
793 return false;
795 if (!manager.InitializeInterceptions())
796 return false;
798 // Finally, setup imports on the target so the interceptions can work.
799 return SetupNtdllImports(target);
802 bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
803 return handle_closer_.InitializeTargetHandles(target);
806 ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
807 Semantics semantics,
808 const wchar_t* pattern) {
809 if (NULL == policy_) {
810 policy_ = MakeBrokerPolicyMemory();
811 DCHECK(policy_);
812 policy_maker_ = new LowLevelPolicy(policy_);
813 DCHECK(policy_maker_);
816 switch (subsystem) {
817 case SUBSYS_FILES: {
818 if (!file_system_init_) {
819 if (!FileSystemPolicy::SetInitialRules(policy_maker_))
820 return SBOX_ERROR_BAD_PARAMS;
821 file_system_init_ = true;
823 if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
824 NOTREACHED();
825 return SBOX_ERROR_BAD_PARAMS;
827 break;
829 case SUBSYS_SYNC: {
830 if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
831 NOTREACHED();
832 return SBOX_ERROR_BAD_PARAMS;
834 break;
836 case SUBSYS_PROCESS: {
837 if (lockdown_level_ < USER_INTERACTIVE &&
838 TargetPolicy::PROCESS_ALL_EXEC == semantics) {
839 // This is unsupported. This is a huge security risk to give full access
840 // to a process handle.
841 return SBOX_ERROR_UNSUPPORTED;
843 if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
844 NOTREACHED();
845 return SBOX_ERROR_BAD_PARAMS;
847 break;
849 case SUBSYS_NAMED_PIPES: {
850 if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
851 NOTREACHED();
852 return SBOX_ERROR_BAD_PARAMS;
854 break;
856 case SUBSYS_REGISTRY: {
857 if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
858 NOTREACHED();
859 return SBOX_ERROR_BAD_PARAMS;
861 break;
863 case SUBSYS_HANDLES: {
864 if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
865 NOTREACHED();
866 return SBOX_ERROR_BAD_PARAMS;
868 break;
871 case SUBSYS_WIN32K_LOCKDOWN: {
872 if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
873 pattern, semantics, policy_maker_)) {
874 NOTREACHED();
875 return SBOX_ERROR_BAD_PARAMS;
877 break;
880 default: { return SBOX_ERROR_UNSUPPORTED; }
883 return SBOX_ALL_OK;
886 } // namespace sandbox