Don't preload rarely seen large images
[chromium-blink-merge.git] / sandbox / win / src / sandbox_policy_base.cc
blob6df2cb3d3819d33c2e742efdc441192de16ca996
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/strings/stringprintf.h"
13 #include "base/win/windows_version.h"
14 #include "sandbox/win/src/app_container.h"
15 #include "sandbox/win/src/filesystem_dispatcher.h"
16 #include "sandbox/win/src/filesystem_policy.h"
17 #include "sandbox/win/src/handle_dispatcher.h"
18 #include "sandbox/win/src/handle_policy.h"
19 #include "sandbox/win/src/job.h"
20 #include "sandbox/win/src/interception.h"
21 #include "sandbox/win/src/process_mitigations.h"
22 #include "sandbox/win/src/named_pipe_dispatcher.h"
23 #include "sandbox/win/src/named_pipe_policy.h"
24 #include "sandbox/win/src/policy_broker.h"
25 #include "sandbox/win/src/policy_engine_processor.h"
26 #include "sandbox/win/src/policy_low_level.h"
27 #include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
28 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
29 #include "sandbox/win/src/process_thread_dispatcher.h"
30 #include "sandbox/win/src/process_thread_policy.h"
31 #include "sandbox/win/src/registry_dispatcher.h"
32 #include "sandbox/win/src/registry_policy.h"
33 #include "sandbox/win/src/restricted_token_utils.h"
34 #include "sandbox/win/src/sandbox_policy.h"
35 #include "sandbox/win/src/sandbox_utils.h"
36 #include "sandbox/win/src/sync_dispatcher.h"
37 #include "sandbox/win/src/sync_policy.h"
38 #include "sandbox/win/src/target_process.h"
39 #include "sandbox/win/src/window.h"
41 namespace {
43 // The standard windows size for one memory page.
44 const size_t kOneMemPage = 4096;
45 // The IPC and Policy shared memory sizes.
46 const size_t kIPCMemSize = kOneMemPage * 2;
47 const size_t kPolMemSize = kOneMemPage * 14;
49 // Helper function to allocate space (on the heap) for policy.
50 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
51 const size_t kTotalPolicySz = kPolMemSize;
52 sandbox::PolicyGlobal* policy = static_cast<sandbox::PolicyGlobal*>
53 (::operator new(kTotalPolicySz));
54 DCHECK(policy);
55 memset(policy, 0, kTotalPolicySz);
56 policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
57 return policy;
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;
72 HANDLE CreateLowBoxObjectDirectory(PSID lowbox_sid) {
73 DWORD session_id = 0;
74 if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id))
75 return NULL;
77 LPWSTR sid_string = NULL;
78 if (!::ConvertSidToStringSid(lowbox_sid, &sid_string))
79 return NULL;
81 base::string16 directory_path = base::StringPrintf(
82 L"\\Sessions\\%d\\AppContainerNamedObjects\\%ls",
83 session_id, sid_string).c_str();
84 ::LocalFree(sid_string);
86 NtCreateDirectoryObjectFunction CreateObjectDirectory = NULL;
87 ResolveNTFunctionPtr("NtCreateDirectoryObject", &CreateObjectDirectory);
89 OBJECT_ATTRIBUTES obj_attr;
90 UNICODE_STRING obj_name;
91 sandbox::InitObjectAttribs(directory_path,
92 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
93 NULL,
94 &obj_attr,
95 &obj_name,
96 NULL);
98 HANDLE handle = NULL;
99 NTSTATUS status = CreateObjectDirectory(&handle,
100 DIRECTORY_ALL_ACCESS,
101 &obj_attr);
103 if (!NT_SUCCESS(status))
104 return NULL;
106 return handle;
111 namespace sandbox {
113 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
114 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
116 // Initializes static members.
117 HWINSTA PolicyBase::alternate_winstation_handle_ = NULL;
118 HDESK PolicyBase::alternate_desktop_handle_ = NULL;
119 IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
120 INTEGRITY_LEVEL_SYSTEM;
122 PolicyBase::PolicyBase()
123 : ref_count(1),
124 lockdown_level_(USER_LOCKDOWN),
125 initial_level_(USER_LOCKDOWN),
126 job_level_(JOB_LOCKDOWN),
127 ui_exceptions_(0),
128 memory_limit_(0),
129 use_alternate_desktop_(false),
130 use_alternate_winstation_(false),
131 file_system_init_(false),
132 relaxed_interceptions_(true),
133 stdout_handle_(INVALID_HANDLE_VALUE),
134 stderr_handle_(INVALID_HANDLE_VALUE),
135 integrity_level_(INTEGRITY_LEVEL_LAST),
136 delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
137 mitigations_(0),
138 delayed_mitigations_(0),
139 policy_maker_(NULL),
140 policy_(NULL),
141 lowbox_sid_(NULL) {
142 ::InitializeCriticalSection(&lock_);
143 // Initialize the IPC dispatcher array.
144 memset(&ipc_targets_, NULL, sizeof(ipc_targets_));
145 Dispatcher* dispatcher = NULL;
147 dispatcher = new FilesystemDispatcher(this);
148 ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher;
149 ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher;
150 ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher;
151 ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher;
152 ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher;
154 dispatcher = new NamedPipeDispatcher(this);
155 ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher;
157 dispatcher = new ThreadProcessDispatcher(this);
158 ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher;
159 ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher;
160 ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher;
161 ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher;
162 ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher;
164 dispatcher = new SyncDispatcher(this);
165 ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher;
166 ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
168 dispatcher = new RegistryDispatcher(this);
169 ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
170 ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
172 dispatcher = new HandleDispatcher(this);
173 ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
175 dispatcher = new ProcessMitigationsWin32KDispatcher(this);
176 ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
177 ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
178 ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
181 PolicyBase::~PolicyBase() {
182 ClearSharedHandles();
184 TargetSet::iterator it;
185 for (it = targets_.begin(); it != targets_.end(); ++it) {
186 TargetProcess* target = (*it);
187 delete target;
189 delete ipc_targets_[IPC_NTCREATEFILE_TAG];
190 delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG];
191 delete ipc_targets_[IPC_NTOPENTHREAD_TAG];
192 delete ipc_targets_[IPC_CREATEEVENT_TAG];
193 delete ipc_targets_[IPC_NTCREATEKEY_TAG];
194 delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG];
195 delete policy_maker_;
196 delete policy_;
198 if (lowbox_sid_)
199 ::LocalFree(lowbox_sid_);
201 ::DeleteCriticalSection(&lock_);
204 void PolicyBase::AddRef() {
205 ::InterlockedIncrement(&ref_count);
208 void PolicyBase::Release() {
209 if (0 == ::InterlockedDecrement(&ref_count))
210 delete this;
213 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
214 if (initial < lockdown) {
215 return SBOX_ERROR_BAD_PARAMS;
217 initial_level_ = initial;
218 lockdown_level_ = lockdown;
219 return SBOX_ALL_OK;
222 TokenLevel PolicyBase::GetInitialTokenLevel() const {
223 return initial_level_;
226 TokenLevel PolicyBase::GetLockdownTokenLevel() const{
227 return lockdown_level_;
230 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
231 if (memory_limit_ && job_level == JOB_NONE) {
232 return SBOX_ERROR_BAD_PARAMS;
234 job_level_ = job_level;
235 ui_exceptions_ = ui_exceptions;
236 return SBOX_ALL_OK;
239 ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
240 if (memory_limit && job_level_ == JOB_NONE) {
241 return SBOX_ERROR_BAD_PARAMS;
243 memory_limit_ = memory_limit;
244 return SBOX_ALL_OK;
247 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
248 use_alternate_desktop_ = true;
249 use_alternate_winstation_ = alternate_winstation;
250 return CreateAlternateDesktop(alternate_winstation);
253 base::string16 PolicyBase::GetAlternateDesktop() const {
254 // No alternate desktop or winstation. Return an empty string.
255 if (!use_alternate_desktop_ && !use_alternate_winstation_) {
256 return base::string16();
259 // The desktop and winstation should have been created by now.
260 // If we hit this scenario, it means that the user ignored the failure
261 // during SetAlternateDesktop, so we ignore it here too.
262 if (use_alternate_desktop_ && !alternate_desktop_handle_) {
263 return base::string16();
265 if (use_alternate_winstation_ && (!alternate_desktop_handle_ ||
266 !alternate_winstation_handle_)) {
267 return base::string16();
270 return GetFullDesktopName(alternate_winstation_handle_,
271 alternate_desktop_handle_);
274 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
275 if (alternate_winstation) {
276 // Previously called with alternate_winstation = false?
277 if (!alternate_winstation_handle_ && alternate_desktop_handle_)
278 return SBOX_ERROR_UNSUPPORTED;
280 // Check if it's already created.
281 if (alternate_winstation_handle_ && alternate_desktop_handle_)
282 return SBOX_ALL_OK;
284 DCHECK(!alternate_winstation_handle_);
285 // Create the window station.
286 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
287 if (SBOX_ALL_OK != result)
288 return result;
290 // Verify that everything is fine.
291 if (!alternate_winstation_handle_ ||
292 GetWindowObjectName(alternate_winstation_handle_).empty())
293 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
295 // Create the destkop.
296 result = CreateAltDesktop(alternate_winstation_handle_,
297 &alternate_desktop_handle_);
298 if (SBOX_ALL_OK != result)
299 return result;
301 // Verify that everything is fine.
302 if (!alternate_desktop_handle_ ||
303 GetWindowObjectName(alternate_desktop_handle_).empty())
304 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
305 } else {
306 // Previously called with alternate_winstation = true?
307 if (alternate_winstation_handle_)
308 return SBOX_ERROR_UNSUPPORTED;
310 // Check if it already exists.
311 if (alternate_desktop_handle_)
312 return SBOX_ALL_OK;
314 // Create the destkop.
315 ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_);
316 if (SBOX_ALL_OK != result)
317 return result;
319 // Verify that everything is fine.
320 if (!alternate_desktop_handle_ ||
321 GetWindowObjectName(alternate_desktop_handle_).empty())
322 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
325 return SBOX_ALL_OK;
328 void PolicyBase::DestroyAlternateDesktop() {
329 if (alternate_desktop_handle_) {
330 ::CloseDesktop(alternate_desktop_handle_);
331 alternate_desktop_handle_ = NULL;
334 if (alternate_winstation_handle_) {
335 ::CloseWindowStation(alternate_winstation_handle_);
336 alternate_winstation_handle_ = NULL;
340 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
341 integrity_level_ = integrity_level;
342 return SBOX_ALL_OK;
345 IntegrityLevel PolicyBase::GetIntegrityLevel() const {
346 return integrity_level_;
349 ResultCode PolicyBase::SetDelayedIntegrityLevel(
350 IntegrityLevel integrity_level) {
351 delayed_integrity_level_ = integrity_level;
352 return SBOX_ALL_OK;
355 ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) {
356 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
357 return SBOX_ALL_OK;
359 // SetLowBox and SetAppContainer are mutually exclusive.
360 if (lowbox_sid_)
361 return SBOX_ERROR_UNSUPPORTED;
363 // Windows refuses to work with an impersonation token for a process inside
364 // an AppContainer. If the caller wants to use a more privileged initial
365 // token, or if the lockdown level will prevent the process from starting,
366 // we have to fail the operation.
367 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
368 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
370 DCHECK(!appcontainer_list_.get());
371 appcontainer_list_.reset(new AppContainerAttributes);
372 ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_);
373 if (rv != SBOX_ALL_OK)
374 return rv;
376 return SBOX_ALL_OK;
379 ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
380 capabilities_.push_back(sid);
381 return SBOX_ALL_OK;
384 ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
385 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
386 return SBOX_ERROR_UNSUPPORTED;
388 // SetLowBox and SetAppContainer are mutually exclusive.
389 if (appcontainer_list_.get())
390 return SBOX_ERROR_UNSUPPORTED;
392 DCHECK(sid);
394 if (lowbox_sid_)
395 return SBOX_ERROR_BAD_PARAMS;
397 if (!ConvertStringSidToSid(sid, &lowbox_sid_))
398 return SBOX_ERROR_GENERIC;
400 return SBOX_ALL_OK;
403 ResultCode PolicyBase::SetProcessMitigations(
404 MitigationFlags flags) {
405 if (!CanSetProcessMitigationsPreStartup(flags))
406 return SBOX_ERROR_BAD_PARAMS;
407 mitigations_ = flags;
408 return SBOX_ALL_OK;
411 MitigationFlags PolicyBase::GetProcessMitigations() {
412 return mitigations_;
415 ResultCode PolicyBase::SetDelayedProcessMitigations(
416 MitigationFlags flags) {
417 if (!CanSetProcessMitigationsPostStartup(flags))
418 return SBOX_ERROR_BAD_PARAMS;
419 delayed_mitigations_ = flags;
420 return SBOX_ALL_OK;
423 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
424 return delayed_mitigations_;
427 void PolicyBase::SetStrictInterceptions() {
428 relaxed_interceptions_ = false;
431 ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
432 if (!IsInheritableHandle(handle))
433 return SBOX_ERROR_BAD_PARAMS;
434 stdout_handle_ = handle;
435 return SBOX_ALL_OK;
438 ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
439 if (!IsInheritableHandle(handle))
440 return SBOX_ERROR_BAD_PARAMS;
441 stderr_handle_ = handle;
442 return SBOX_ALL_OK;
445 ResultCode PolicyBase::AddRule(SubSystem subsystem,
446 Semantics semantics,
447 const wchar_t* pattern) {
448 ResultCode result = AddRuleInternal(subsystem, semantics, pattern);
449 LOG_IF(ERROR, result != SBOX_ALL_OK) << "Failed to add sandbox rule."
450 << " error = " << result
451 << ", subsystem = " << subsystem
452 << ", semantics = " << semantics
453 << ", pattern = '" << pattern << "'";
454 return result;
457 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
458 blacklisted_dlls_.push_back(dll_name);
459 return SBOX_ALL_OK;
462 ResultCode PolicyBase::AddKernelObjectToClose(const base::char16* handle_type,
463 const base::char16* handle_name) {
464 return handle_closer_.AddHandle(handle_type, handle_name);
467 void* PolicyBase::AddHandleToShare(HANDLE handle) {
468 if (base::win::GetVersion() < base::win::VERSION_VISTA)
469 return NULL;
471 if (!handle)
472 return NULL;
474 HANDLE duped_handle = NULL;
475 ::DuplicateHandle(::GetCurrentProcess(),
476 handle,
477 ::GetCurrentProcess(),
478 &duped_handle,
480 TRUE,
481 DUPLICATE_SAME_ACCESS);
482 DCHECK(duped_handle);
483 handles_to_share_.push_back(duped_handle);
484 return duped_handle;
487 HandleList PolicyBase::GetHandlesBeingShared() {
488 return handles_to_share_;
491 void PolicyBase::ClearSharedHandles() {
492 for (auto handle : handles_to_share_) {
493 ::CloseHandle(handle);
495 handles_to_share_.clear();
498 // When an IPC is ready in any of the targets we get called. We manage an array
499 // of IPC dispatchers which are keyed on the IPC tag so we normally delegate
500 // to the appropriate dispatcher unless we can handle the IPC call ourselves.
501 Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc,
502 CallbackGeneric* callback) {
503 DCHECK(callback);
504 static const IPCParams ping1 = {IPC_PING1_TAG, {UINT32_TYPE}};
505 static const IPCParams ping2 = {IPC_PING2_TAG, {INOUTPTR_TYPE}};
507 if (ping1.Matches(ipc) || ping2.Matches(ipc)) {
508 *callback = reinterpret_cast<CallbackGeneric>(
509 static_cast<Callback1>(&PolicyBase::Ping));
510 return this;
513 Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag);
514 if (!dispatch) {
515 NOTREACHED();
516 return NULL;
518 return dispatch->OnMessageReady(ipc, callback);
521 // Delegate to the appropriate dispatcher.
522 bool PolicyBase::SetupService(InterceptionManager* manager, int service) {
523 if (IPC_PING1_TAG == service || IPC_PING2_TAG == service)
524 return true;
526 Dispatcher* dispatch = GetDispatcher(service);
527 if (!dispatch) {
528 NOTREACHED();
529 return false;
531 return dispatch->SetupService(manager, service);
534 ResultCode PolicyBase::MakeJobObject(HANDLE* job) {
535 if (job_level_ != JOB_NONE) {
536 // Create the windows job object.
537 Job job_obj;
538 DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_,
539 memory_limit_);
540 if (ERROR_SUCCESS != result) {
541 return SBOX_ERROR_GENERIC;
543 *job = job_obj.Detach();
544 } else {
545 *job = NULL;
547 return SBOX_ALL_OK;
550 ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
551 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer() &&
552 lowbox_sid_) {
553 return SBOX_ERROR_BAD_PARAMS;
556 // Create the 'naked' token. This will be the permanent token associated
557 // with the process and therefore with any thread that is not impersonating.
558 DWORD result = CreateRestrictedToken(lockdown, lockdown_level_,
559 integrity_level_, PRIMARY);
560 if (ERROR_SUCCESS != result)
561 return SBOX_ERROR_GENERIC;
563 // If we're launching on the alternate desktop we need to make sure the
564 // integrity label on the object is no higher than the sandboxed process's
565 // integrity level. So, we lower the label on the desktop process if it's
566 // not already low enough for our process.
567 if (alternate_desktop_handle_ && use_alternate_desktop_ &&
568 integrity_level_ != INTEGRITY_LEVEL_LAST &&
569 alternate_desktop_integrity_level_label_ < integrity_level_ &&
570 base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
571 // Integrity label enum is reversed (higher level is a lower value).
572 static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED,
573 "Integrity level ordering reversed.");
574 result = SetObjectIntegrityLabel(alternate_desktop_handle_,
575 SE_WINDOW_OBJECT,
576 L"",
577 GetIntegrityLevelString(integrity_level_));
578 if (ERROR_SUCCESS != result)
579 return SBOX_ERROR_GENERIC;
581 alternate_desktop_integrity_level_label_ = integrity_level_;
584 // We are maintaining two mutually exclusive approaches. One is to start an
585 // AppContainer process through StartupInfoEx and other is replacing
586 // existing token with LowBox token after process creation.
587 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) {
588 // Windows refuses to work with an impersonation token. See SetAppContainer
589 // implementation for more details.
590 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
591 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
593 *initial = INVALID_HANDLE_VALUE;
594 return SBOX_ALL_OK;
595 } else 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,
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 ::CloseHandle(*lockdown);
620 *lockdown = token_lowbox;
623 // Create the 'better' token. We use this token as the one that the main
624 // thread uses when booting up the process. It should contain most of
625 // what we need (before reaching main( ))
626 result = CreateRestrictedToken(initial, initial_level_,
627 integrity_level_, IMPERSONATION);
628 if (ERROR_SUCCESS != result) {
629 ::CloseHandle(*lockdown);
630 return SBOX_ERROR_GENERIC;
632 return SBOX_ALL_OK;
635 const AppContainerAttributes* PolicyBase::GetAppContainer() const {
636 if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
637 return NULL;
639 return appcontainer_list_.get();
642 const PSID PolicyBase::GetLowBoxSid() const {
643 return lowbox_sid_;
646 bool PolicyBase::AddTarget(TargetProcess* target) {
647 if (NULL != policy_)
648 policy_maker_->Done();
650 if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
651 mitigations_)) {
652 return false;
655 if (!SetupAllInterceptions(target))
656 return false;
658 if (!SetupHandleCloser(target))
659 return false;
661 // Initialize the sandbox infrastructure for the target.
662 if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize))
663 return false;
665 g_shared_delayed_integrity_level = delayed_integrity_level_;
666 ResultCode ret = target->TransferVariable(
667 "g_shared_delayed_integrity_level",
668 &g_shared_delayed_integrity_level,
669 sizeof(g_shared_delayed_integrity_level));
670 g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
671 if (SBOX_ALL_OK != ret)
672 return false;
674 // Add in delayed mitigations and pseudo-mitigations enforced at startup.
675 g_shared_delayed_mitigations = delayed_mitigations_ |
676 FilterPostStartupProcessMitigations(mitigations_);
677 if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
678 return false;
680 ret = target->TransferVariable("g_shared_delayed_mitigations",
681 &g_shared_delayed_mitigations,
682 sizeof(g_shared_delayed_mitigations));
683 g_shared_delayed_mitigations = 0;
684 if (SBOX_ALL_OK != ret)
685 return false;
687 AutoLock lock(&lock_);
688 targets_.push_back(target);
689 return true;
692 bool PolicyBase::OnJobEmpty(HANDLE job) {
693 AutoLock lock(&lock_);
694 TargetSet::iterator it;
695 for (it = targets_.begin(); it != targets_.end(); ++it) {
696 if ((*it)->Job() == job)
697 break;
699 if (it == targets_.end()) {
700 return false;
702 TargetProcess* target = *it;
703 targets_.erase(it);
704 delete target;
705 return true;
708 EvalResult PolicyBase::EvalPolicy(int service,
709 CountedParameterSetBase* params) {
710 if (NULL != policy_) {
711 if (NULL == policy_->entry[service]) {
712 // There is no policy for this particular service. This is not a big
713 // deal.
714 return DENY_ACCESS;
716 for (int i = 0; i < params->count; i++) {
717 if (!params->parameters[i].IsValid()) {
718 NOTREACHED();
719 return SIGNAL_ALARM;
722 PolicyProcessor pol_evaluator(policy_->entry[service]);
723 PolicyResult result = pol_evaluator.Evaluate(kShortEval,
724 params->parameters,
725 params->count);
726 if (POLICY_MATCH == result) {
727 return pol_evaluator.GetAction();
729 DCHECK(POLICY_ERROR != result);
732 return DENY_ACCESS;
735 HANDLE PolicyBase::GetStdoutHandle() {
736 return stdout_handle_;
739 HANDLE PolicyBase::GetStderrHandle() {
740 return stderr_handle_;
743 // We service IPC_PING_TAG message which is a way to test a round trip of the
744 // IPC subsystem. We receive a integer cookie and we are expected to return the
745 // cookie times two (or three) and the current tick count.
746 bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) {
747 switch (ipc->ipc_tag) {
748 case IPC_PING1_TAG: {
749 IPCInt ipc_int(arg1);
750 uint32 cookie = ipc_int.As32Bit();
751 ipc->return_info.extended_count = 2;
752 ipc->return_info.extended[0].unsigned_int = ::GetTickCount();
753 ipc->return_info.extended[1].unsigned_int = 2 * cookie;
754 return true;
756 case IPC_PING2_TAG: {
757 CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1);
758 if (sizeof(uint32) != io_buffer->Size())
759 return false;
761 uint32* cookie = reinterpret_cast<uint32*>(io_buffer->Buffer());
762 *cookie = (*cookie) * 3;
763 return true;
765 default: return false;
769 Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) {
770 if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG)
771 return NULL;
773 return ipc_targets_[ipc_tag];
776 bool PolicyBase::SetupAllInterceptions(TargetProcess* target) {
777 InterceptionManager manager(target, relaxed_interceptions_);
779 if (policy_) {
780 for (int i = 0; i < IPC_LAST_TAG; i++) {
781 if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i))
782 return false;
786 if (!blacklisted_dlls_.empty()) {
787 std::vector<base::string16>::iterator it = blacklisted_dlls_.begin();
788 for (; it != blacklisted_dlls_.end(); ++it) {
789 manager.AddToUnloadModules(it->c_str());
793 if (!SetupBasicInterceptions(&manager))
794 return false;
796 if (!manager.InitializeInterceptions())
797 return false;
799 // Finally, setup imports on the target so the interceptions can work.
800 return SetupNtdllImports(target);
803 bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
804 return handle_closer_.InitializeTargetHandles(target);
807 ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
808 Semantics semantics,
809 const wchar_t* pattern) {
810 if (NULL == policy_) {
811 policy_ = MakeBrokerPolicyMemory();
812 DCHECK(policy_);
813 policy_maker_ = new LowLevelPolicy(policy_);
814 DCHECK(policy_maker_);
817 switch (subsystem) {
818 case SUBSYS_FILES: {
819 if (!file_system_init_) {
820 if (!FileSystemPolicy::SetInitialRules(policy_maker_))
821 return SBOX_ERROR_BAD_PARAMS;
822 file_system_init_ = true;
824 if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
825 NOTREACHED();
826 return SBOX_ERROR_BAD_PARAMS;
828 break;
830 case SUBSYS_SYNC: {
831 if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
832 NOTREACHED();
833 return SBOX_ERROR_BAD_PARAMS;
835 break;
837 case SUBSYS_PROCESS: {
838 if (lockdown_level_ < USER_INTERACTIVE &&
839 TargetPolicy::PROCESS_ALL_EXEC == semantics) {
840 // This is unsupported. This is a huge security risk to give full access
841 // to a process handle.
842 return SBOX_ERROR_UNSUPPORTED;
844 if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
845 NOTREACHED();
846 return SBOX_ERROR_BAD_PARAMS;
848 break;
850 case SUBSYS_NAMED_PIPES: {
851 if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
852 NOTREACHED();
853 return SBOX_ERROR_BAD_PARAMS;
855 break;
857 case SUBSYS_REGISTRY: {
858 if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
859 NOTREACHED();
860 return SBOX_ERROR_BAD_PARAMS;
862 break;
864 case SUBSYS_HANDLES: {
865 if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
866 NOTREACHED();
867 return SBOX_ERROR_BAD_PARAMS;
869 break;
872 case SUBSYS_WIN32K_LOCKDOWN: {
873 if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
874 pattern, semantics, policy_maker_)) {
875 NOTREACHED();
876 return SBOX_ERROR_BAD_PARAMS;
878 break;
881 default: { return SBOX_ERROR_UNSUPPORTED; }
884 return SBOX_ALL_OK;
887 } // namespace sandbox