Update V8 to version 4.3.37.
[chromium-blink-merge.git] / sandbox / win / src / sandbox_policy_base.cc
blobf5ed7e4d7325db58d8a76268050389545a81e5a9
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/win/windows_version.h"
13 #include "sandbox/win/src/app_container.h"
14 #include "sandbox/win/src/filesystem_dispatcher.h"
15 #include "sandbox/win/src/filesystem_policy.h"
16 #include "sandbox/win/src/handle_dispatcher.h"
17 #include "sandbox/win/src/handle_policy.h"
18 #include "sandbox/win/src/job.h"
19 #include "sandbox/win/src/interception.h"
20 #include "sandbox/win/src/process_mitigations.h"
21 #include "sandbox/win/src/named_pipe_dispatcher.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_win32k_dispatcher.h"
27 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
28 #include "sandbox/win/src/process_thread_dispatcher.h"
29 #include "sandbox/win/src/process_thread_policy.h"
30 #include "sandbox/win/src/registry_dispatcher.h"
31 #include "sandbox/win/src/registry_policy.h"
32 #include "sandbox/win/src/restricted_token_utils.h"
33 #include "sandbox/win/src/sandbox_policy.h"
34 #include "sandbox/win/src/sync_dispatcher.h"
35 #include "sandbox/win/src/sync_policy.h"
36 #include "sandbox/win/src/target_process.h"
37 #include "sandbox/win/src/window.h"
39 namespace {
41 // The standard windows size for one memory page.
42 const size_t kOneMemPage = 4096;
43 // The IPC and Policy shared memory sizes.
44 const size_t kIPCMemSize = kOneMemPage * 2;
45 const size_t kPolMemSize = kOneMemPage * 14;
47 // Helper function to allocate space (on the heap) for policy.
48 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
49 const size_t kTotalPolicySz = kPolMemSize;
50 sandbox::PolicyGlobal* policy = static_cast<sandbox::PolicyGlobal*>
51 (::operator new(kTotalPolicySz));
52 DCHECK(policy);
53 memset(policy, 0, kTotalPolicySz);
54 policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
55 return policy;
58 bool IsInheritableHandle(HANDLE handle) {
59 if (!handle)
60 return false;
61 if (handle == INVALID_HANDLE_VALUE)
62 return false;
63 // File handles (FILE_TYPE_DISK) and pipe handles are known to be
64 // inheritable. Console handles (FILE_TYPE_CHAR) are not
65 // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
66 DWORD handle_type = GetFileType(handle);
67 return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
72 namespace sandbox {
74 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
75 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
77 // Initializes static members.
78 HWINSTA PolicyBase::alternate_winstation_handle_ = NULL;
79 HDESK PolicyBase::alternate_desktop_handle_ = NULL;
80 IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
81 INTEGRITY_LEVEL_SYSTEM;
83 PolicyBase::PolicyBase()
84 : ref_count(1),
85 lockdown_level_(USER_LOCKDOWN),
86 initial_level_(USER_LOCKDOWN),
87 job_level_(JOB_LOCKDOWN),
88 ui_exceptions_(0),
89 memory_limit_(0),
90 use_alternate_desktop_(false),
91 use_alternate_winstation_(false),
92 file_system_init_(false),
93 relaxed_interceptions_(true),
94 stdout_handle_(INVALID_HANDLE_VALUE),
95 stderr_handle_(INVALID_HANDLE_VALUE),
96 integrity_level_(INTEGRITY_LEVEL_LAST),
97 delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
98 mitigations_(0),
99 delayed_mitigations_(0),
100 policy_maker_(NULL),
101 policy_(NULL),
102 lowbox_sid_(NULL) {
103 ::InitializeCriticalSection(&lock_);
104 // Initialize the IPC dispatcher array.
105 memset(&ipc_targets_, NULL, sizeof(ipc_targets_));
106 Dispatcher* dispatcher = NULL;
108 dispatcher = new FilesystemDispatcher(this);
109 ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher;
110 ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher;
111 ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher;
112 ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher;
113 ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher;
115 dispatcher = new NamedPipeDispatcher(this);
116 ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher;
118 dispatcher = new ThreadProcessDispatcher(this);
119 ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher;
120 ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher;
121 ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher;
122 ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher;
123 ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher;
125 dispatcher = new SyncDispatcher(this);
126 ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher;
127 ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
129 dispatcher = new RegistryDispatcher(this);
130 ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
131 ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
133 dispatcher = new HandleDispatcher(this);
134 ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
136 dispatcher = new ProcessMitigationsWin32KDispatcher(this);
137 ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
138 ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
139 ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
142 PolicyBase::~PolicyBase() {
143 TargetSet::iterator it;
144 for (it = targets_.begin(); it != targets_.end(); ++it) {
145 TargetProcess* target = (*it);
146 delete target;
148 delete ipc_targets_[IPC_NTCREATEFILE_TAG];
149 delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG];
150 delete ipc_targets_[IPC_NTOPENTHREAD_TAG];
151 delete ipc_targets_[IPC_CREATEEVENT_TAG];
152 delete ipc_targets_[IPC_NTCREATEKEY_TAG];
153 delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG];
154 delete policy_maker_;
155 delete policy_;
157 if (lowbox_sid_)
158 ::LocalFree(lowbox_sid_);
160 ::DeleteCriticalSection(&lock_);
163 void PolicyBase::AddRef() {
164 ::InterlockedIncrement(&ref_count);
167 void PolicyBase::Release() {
168 if (0 == ::InterlockedDecrement(&ref_count))
169 delete this;
172 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
173 if (initial < lockdown) {
174 return SBOX_ERROR_BAD_PARAMS;
176 initial_level_ = initial;
177 lockdown_level_ = lockdown;
178 return SBOX_ALL_OK;
181 TokenLevel PolicyBase::GetInitialTokenLevel() const {
182 return initial_level_;
185 TokenLevel PolicyBase::GetLockdownTokenLevel() const{
186 return lockdown_level_;
189 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
190 if (memory_limit_ && job_level == JOB_NONE) {
191 return SBOX_ERROR_BAD_PARAMS;
193 job_level_ = job_level;
194 ui_exceptions_ = ui_exceptions;
195 return SBOX_ALL_OK;
198 ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
199 if (memory_limit && job_level_ == JOB_NONE) {
200 return SBOX_ERROR_BAD_PARAMS;
202 memory_limit_ = memory_limit;
203 return SBOX_ALL_OK;
206 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
207 use_alternate_desktop_ = true;
208 use_alternate_winstation_ = alternate_winstation;
209 return CreateAlternateDesktop(alternate_winstation);
212 base::string16 PolicyBase::GetAlternateDesktop() const {
213 // No alternate desktop or winstation. Return an empty string.
214 if (!use_alternate_desktop_ && !use_alternate_winstation_) {
215 return base::string16();
218 // The desktop and winstation should have been created by now.
219 // If we hit this scenario, it means that the user ignored the failure
220 // during SetAlternateDesktop, so we ignore it here too.
221 if (use_alternate_desktop_ && !alternate_desktop_handle_) {
222 return base::string16();
224 if (use_alternate_winstation_ && (!alternate_desktop_handle_ ||
225 !alternate_winstation_handle_)) {
226 return base::string16();
229 return GetFullDesktopName(alternate_winstation_handle_,
230 alternate_desktop_handle_);
233 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
234 if (alternate_winstation) {
235 // Previously called with alternate_winstation = false?
236 if (!alternate_winstation_handle_ && alternate_desktop_handle_)
237 return SBOX_ERROR_UNSUPPORTED;
239 // Check if it's already created.
240 if (alternate_winstation_handle_ && alternate_desktop_handle_)
241 return SBOX_ALL_OK;
243 DCHECK(!alternate_winstation_handle_);
244 // Create the window station.
245 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
246 if (SBOX_ALL_OK != result)
247 return result;
249 // Verify that everything is fine.
250 if (!alternate_winstation_handle_ ||
251 GetWindowObjectName(alternate_winstation_handle_).empty())
252 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
254 // Create the destkop.
255 result = CreateAltDesktop(alternate_winstation_handle_,
256 &alternate_desktop_handle_);
257 if (SBOX_ALL_OK != result)
258 return result;
260 // Verify that everything is fine.
261 if (!alternate_desktop_handle_ ||
262 GetWindowObjectName(alternate_desktop_handle_).empty())
263 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
264 } else {
265 // Previously called with alternate_winstation = true?
266 if (alternate_winstation_handle_)
267 return SBOX_ERROR_UNSUPPORTED;
269 // Check if it already exists.
270 if (alternate_desktop_handle_)
271 return SBOX_ALL_OK;
273 // Create the destkop.
274 ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_);
275 if (SBOX_ALL_OK != result)
276 return result;
278 // Verify that everything is fine.
279 if (!alternate_desktop_handle_ ||
280 GetWindowObjectName(alternate_desktop_handle_).empty())
281 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
284 return SBOX_ALL_OK;
287 void PolicyBase::DestroyAlternateDesktop() {
288 if (alternate_desktop_handle_) {
289 ::CloseDesktop(alternate_desktop_handle_);
290 alternate_desktop_handle_ = NULL;
293 if (alternate_winstation_handle_) {
294 ::CloseWindowStation(alternate_winstation_handle_);
295 alternate_winstation_handle_ = NULL;
299 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
300 integrity_level_ = integrity_level;
301 return SBOX_ALL_OK;
304 IntegrityLevel PolicyBase::GetIntegrityLevel() const {
305 return integrity_level_;
308 ResultCode PolicyBase::SetDelayedIntegrityLevel(
309 IntegrityLevel integrity_level) {
310 delayed_integrity_level_ = integrity_level;
311 return SBOX_ALL_OK;
314 ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) {
315 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
316 return SBOX_ALL_OK;
318 // SetLowBox and SetAppContainer are mutually exclusive.
319 if (lowbox_sid_)
320 return SBOX_ERROR_UNSUPPORTED;
322 // Windows refuses to work with an impersonation token for a process inside
323 // an AppContainer. If the caller wants to use a more privileged initial
324 // token, or if the lockdown level will prevent the process from starting,
325 // we have to fail the operation.
326 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
327 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
329 DCHECK(!appcontainer_list_.get());
330 appcontainer_list_.reset(new AppContainerAttributes);
331 ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_);
332 if (rv != SBOX_ALL_OK)
333 return rv;
335 return SBOX_ALL_OK;
338 ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
339 capabilities_.push_back(sid);
340 return SBOX_ALL_OK;
343 ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
344 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
345 return SBOX_ERROR_UNSUPPORTED;
347 // SetLowBox and SetAppContainer are mutually exclusive.
348 if (appcontainer_list_.get())
349 return SBOX_ERROR_UNSUPPORTED;
351 DCHECK(sid);
353 if (lowbox_sid_)
354 return SBOX_ERROR_BAD_PARAMS;
356 if (!ConvertStringSidToSid(sid, &lowbox_sid_))
357 return SBOX_ERROR_GENERIC;
359 return SBOX_ALL_OK;
362 ResultCode PolicyBase::SetProcessMitigations(
363 MitigationFlags flags) {
364 if (!CanSetProcessMitigationsPreStartup(flags))
365 return SBOX_ERROR_BAD_PARAMS;
366 mitigations_ = flags;
367 return SBOX_ALL_OK;
370 MitigationFlags PolicyBase::GetProcessMitigations() {
371 return mitigations_;
374 ResultCode PolicyBase::SetDelayedProcessMitigations(
375 MitigationFlags flags) {
376 if (!CanSetProcessMitigationsPostStartup(flags))
377 return SBOX_ERROR_BAD_PARAMS;
378 delayed_mitigations_ = flags;
379 return SBOX_ALL_OK;
382 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
383 return delayed_mitigations_;
386 void PolicyBase::SetStrictInterceptions() {
387 relaxed_interceptions_ = false;
390 ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
391 if (!IsInheritableHandle(handle))
392 return SBOX_ERROR_BAD_PARAMS;
393 stdout_handle_ = handle;
394 return SBOX_ALL_OK;
397 ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
398 if (!IsInheritableHandle(handle))
399 return SBOX_ERROR_BAD_PARAMS;
400 stderr_handle_ = handle;
401 return SBOX_ALL_OK;
404 ResultCode PolicyBase::AddRule(SubSystem subsystem,
405 Semantics semantics,
406 const wchar_t* pattern) {
407 ResultCode result = AddRuleInternal(subsystem, semantics, pattern);
408 LOG_IF(ERROR, result != SBOX_ALL_OK) << "Failed to add sandbox rule."
409 << " error = " << result
410 << ", subsystem = " << subsystem
411 << ", semantics = " << semantics
412 << ", pattern = '" << pattern << "'";
413 return result;
416 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
417 blacklisted_dlls_.push_back(dll_name);
418 return SBOX_ALL_OK;
421 ResultCode PolicyBase::AddKernelObjectToClose(const base::char16* handle_type,
422 const base::char16* handle_name) {
423 return handle_closer_.AddHandle(handle_type, handle_name);
426 // When an IPC is ready in any of the targets we get called. We manage an array
427 // of IPC dispatchers which are keyed on the IPC tag so we normally delegate
428 // to the appropriate dispatcher unless we can handle the IPC call ourselves.
429 Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc,
430 CallbackGeneric* callback) {
431 DCHECK(callback);
432 static const IPCParams ping1 = {IPC_PING1_TAG, UINT32_TYPE};
433 static const IPCParams ping2 = {IPC_PING2_TAG, INOUTPTR_TYPE};
435 if (ping1.Matches(ipc) || ping2.Matches(ipc)) {
436 *callback = reinterpret_cast<CallbackGeneric>(
437 static_cast<Callback1>(&PolicyBase::Ping));
438 return this;
441 Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag);
442 if (!dispatch) {
443 NOTREACHED();
444 return NULL;
446 return dispatch->OnMessageReady(ipc, callback);
449 // Delegate to the appropriate dispatcher.
450 bool PolicyBase::SetupService(InterceptionManager* manager, int service) {
451 if (IPC_PING1_TAG == service || IPC_PING2_TAG == service)
452 return true;
454 Dispatcher* dispatch = GetDispatcher(service);
455 if (!dispatch) {
456 NOTREACHED();
457 return false;
459 return dispatch->SetupService(manager, service);
462 ResultCode PolicyBase::MakeJobObject(HANDLE* job) {
463 if (job_level_ != JOB_NONE) {
464 // Create the windows job object.
465 Job job_obj;
466 DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_,
467 memory_limit_);
468 if (ERROR_SUCCESS != result) {
469 return SBOX_ERROR_GENERIC;
471 *job = job_obj.Detach();
472 } else {
473 *job = NULL;
475 return SBOX_ALL_OK;
478 ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
479 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer() &&
480 lowbox_sid_) {
481 return SBOX_ERROR_BAD_PARAMS;
484 // Create the 'naked' token. This will be the permanent token associated
485 // with the process and therefore with any thread that is not impersonating.
486 DWORD result = CreateRestrictedToken(lockdown, lockdown_level_,
487 integrity_level_, PRIMARY);
488 if (ERROR_SUCCESS != result)
489 return SBOX_ERROR_GENERIC;
491 // If we're launching on the alternate desktop we need to make sure the
492 // integrity label on the object is no higher than the sandboxed process's
493 // integrity level. So, we lower the label on the desktop process if it's
494 // not already low enough for our process.
495 if (alternate_desktop_handle_ && use_alternate_desktop_ &&
496 integrity_level_ != INTEGRITY_LEVEL_LAST &&
497 alternate_desktop_integrity_level_label_ < integrity_level_ &&
498 base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
499 // Integrity label enum is reversed (higher level is a lower value).
500 static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED,
501 "Integrity level ordering reversed.");
502 result = SetObjectIntegrityLabel(alternate_desktop_handle_,
503 SE_WINDOW_OBJECT,
504 L"",
505 GetIntegrityLevelString(integrity_level_));
506 if (ERROR_SUCCESS != result)
507 return SBOX_ERROR_GENERIC;
509 alternate_desktop_integrity_level_label_ = integrity_level_;
512 // We are maintaining two mutually exclusive approaches. One is to start an
513 // AppContainer process through StartupInfoEx and other is replacing
514 // existing token with LowBox token after process creation.
515 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) {
516 // Windows refuses to work with an impersonation token. See SetAppContainer
517 // implementation for more details.
518 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
519 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
521 *initial = INVALID_HANDLE_VALUE;
522 return SBOX_ALL_OK;
523 } else if (lowbox_sid_) {
524 NtCreateLowBoxToken CreateLowBoxToken = NULL;
525 ResolveNTFunctionPtr("NtCreateLowBoxToken", &CreateLowBoxToken);
526 OBJECT_ATTRIBUTES obj_attr;
527 InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
528 HANDLE token_lowbox = NULL;
529 NTSTATUS status = CreateLowBoxToken(&token_lowbox, *lockdown,
530 TOKEN_ALL_ACCESS, &obj_attr,
531 lowbox_sid_, 0, NULL, 0, NULL);
532 if (!NT_SUCCESS(status))
533 return SBOX_ERROR_GENERIC;
535 DCHECK(token_lowbox);
536 ::CloseHandle(*lockdown);
537 *lockdown = token_lowbox;
540 // Create the 'better' token. We use this token as the one that the main
541 // thread uses when booting up the process. It should contain most of
542 // what we need (before reaching main( ))
543 result = CreateRestrictedToken(initial, initial_level_,
544 integrity_level_, IMPERSONATION);
545 if (ERROR_SUCCESS != result) {
546 ::CloseHandle(*lockdown);
547 return SBOX_ERROR_GENERIC;
549 return SBOX_ALL_OK;
552 const AppContainerAttributes* PolicyBase::GetAppContainer() const {
553 if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
554 return NULL;
556 return appcontainer_list_.get();
559 const PSID PolicyBase::GetLowBoxSid() const {
560 return lowbox_sid_;
563 bool PolicyBase::AddTarget(TargetProcess* target) {
564 if (NULL != policy_)
565 policy_maker_->Done();
567 if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
568 mitigations_)) {
569 return false;
572 if (!SetupAllInterceptions(target))
573 return false;
575 if (!SetupHandleCloser(target))
576 return false;
578 // Initialize the sandbox infrastructure for the target.
579 if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize))
580 return false;
582 g_shared_delayed_integrity_level = delayed_integrity_level_;
583 ResultCode ret = target->TransferVariable(
584 "g_shared_delayed_integrity_level",
585 &g_shared_delayed_integrity_level,
586 sizeof(g_shared_delayed_integrity_level));
587 g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
588 if (SBOX_ALL_OK != ret)
589 return false;
591 // Add in delayed mitigations and pseudo-mitigations enforced at startup.
592 g_shared_delayed_mitigations = delayed_mitigations_ |
593 FilterPostStartupProcessMitigations(mitigations_);
594 if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
595 return false;
597 ret = target->TransferVariable("g_shared_delayed_mitigations",
598 &g_shared_delayed_mitigations,
599 sizeof(g_shared_delayed_mitigations));
600 g_shared_delayed_mitigations = 0;
601 if (SBOX_ALL_OK != ret)
602 return false;
604 AutoLock lock(&lock_);
605 targets_.push_back(target);
606 return true;
609 bool PolicyBase::OnJobEmpty(HANDLE job) {
610 AutoLock lock(&lock_);
611 TargetSet::iterator it;
612 for (it = targets_.begin(); it != targets_.end(); ++it) {
613 if ((*it)->Job() == job)
614 break;
616 if (it == targets_.end()) {
617 return false;
619 TargetProcess* target = *it;
620 targets_.erase(it);
621 delete target;
622 return true;
625 EvalResult PolicyBase::EvalPolicy(int service,
626 CountedParameterSetBase* params) {
627 if (NULL != policy_) {
628 if (NULL == policy_->entry[service]) {
629 // There is no policy for this particular service. This is not a big
630 // deal.
631 return DENY_ACCESS;
633 for (int i = 0; i < params->count; i++) {
634 if (!params->parameters[i].IsValid()) {
635 NOTREACHED();
636 return SIGNAL_ALARM;
639 PolicyProcessor pol_evaluator(policy_->entry[service]);
640 PolicyResult result = pol_evaluator.Evaluate(kShortEval,
641 params->parameters,
642 params->count);
643 if (POLICY_MATCH == result) {
644 return pol_evaluator.GetAction();
646 DCHECK(POLICY_ERROR != result);
649 return DENY_ACCESS;
652 HANDLE PolicyBase::GetStdoutHandle() {
653 return stdout_handle_;
656 HANDLE PolicyBase::GetStderrHandle() {
657 return stderr_handle_;
660 // We service IPC_PING_TAG message which is a way to test a round trip of the
661 // IPC subsystem. We receive a integer cookie and we are expected to return the
662 // cookie times two (or three) and the current tick count.
663 bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) {
664 switch (ipc->ipc_tag) {
665 case IPC_PING1_TAG: {
666 IPCInt ipc_int(arg1);
667 uint32 cookie = ipc_int.As32Bit();
668 ipc->return_info.extended_count = 2;
669 ipc->return_info.extended[0].unsigned_int = ::GetTickCount();
670 ipc->return_info.extended[1].unsigned_int = 2 * cookie;
671 return true;
673 case IPC_PING2_TAG: {
674 CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1);
675 if (sizeof(uint32) != io_buffer->Size())
676 return false;
678 uint32* cookie = reinterpret_cast<uint32*>(io_buffer->Buffer());
679 *cookie = (*cookie) * 3;
680 return true;
682 default: return false;
686 Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) {
687 if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG)
688 return NULL;
690 return ipc_targets_[ipc_tag];
693 bool PolicyBase::SetupAllInterceptions(TargetProcess* target) {
694 InterceptionManager manager(target, relaxed_interceptions_);
696 if (policy_) {
697 for (int i = 0; i < IPC_LAST_TAG; i++) {
698 if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i))
699 return false;
703 if (!blacklisted_dlls_.empty()) {
704 std::vector<base::string16>::iterator it = blacklisted_dlls_.begin();
705 for (; it != blacklisted_dlls_.end(); ++it) {
706 manager.AddToUnloadModules(it->c_str());
710 if (!SetupBasicInterceptions(&manager))
711 return false;
713 if (!manager.InitializeInterceptions())
714 return false;
716 // Finally, setup imports on the target so the interceptions can work.
717 return SetupNtdllImports(target);
720 bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
721 return handle_closer_.InitializeTargetHandles(target);
724 ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
725 Semantics semantics,
726 const wchar_t* pattern) {
727 if (NULL == policy_) {
728 policy_ = MakeBrokerPolicyMemory();
729 DCHECK(policy_);
730 policy_maker_ = new LowLevelPolicy(policy_);
731 DCHECK(policy_maker_);
734 switch (subsystem) {
735 case SUBSYS_FILES: {
736 if (!file_system_init_) {
737 if (!FileSystemPolicy::SetInitialRules(policy_maker_))
738 return SBOX_ERROR_BAD_PARAMS;
739 file_system_init_ = true;
741 if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
742 NOTREACHED();
743 return SBOX_ERROR_BAD_PARAMS;
745 break;
747 case SUBSYS_SYNC: {
748 if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
749 NOTREACHED();
750 return SBOX_ERROR_BAD_PARAMS;
752 break;
754 case SUBSYS_PROCESS: {
755 if (lockdown_level_ < USER_INTERACTIVE &&
756 TargetPolicy::PROCESS_ALL_EXEC == semantics) {
757 // This is unsupported. This is a huge security risk to give full access
758 // to a process handle.
759 return SBOX_ERROR_UNSUPPORTED;
761 if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
762 NOTREACHED();
763 return SBOX_ERROR_BAD_PARAMS;
765 break;
767 case SUBSYS_NAMED_PIPES: {
768 if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
769 NOTREACHED();
770 return SBOX_ERROR_BAD_PARAMS;
772 break;
774 case SUBSYS_REGISTRY: {
775 if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
776 NOTREACHED();
777 return SBOX_ERROR_BAD_PARAMS;
779 break;
781 case SUBSYS_HANDLES: {
782 if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
783 NOTREACHED();
784 return SBOX_ERROR_BAD_PARAMS;
786 break;
789 case SUBSYS_WIN32K_LOCKDOWN: {
790 if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
791 pattern, semantics, policy_maker_)) {
792 NOTREACHED();
793 return SBOX_ERROR_BAD_PARAMS;
795 break;
798 default: { return SBOX_ERROR_UNSUPPORTED; }
801 return SBOX_ALL_OK;
804 } // namespace sandbox