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 "base/basictypes.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "base/win/windows_version.h"
11 #include "sandbox/win/src/app_container.h"
12 #include "sandbox/win/src/filesystem_dispatcher.h"
13 #include "sandbox/win/src/filesystem_policy.h"
14 #include "sandbox/win/src/handle_dispatcher.h"
15 #include "sandbox/win/src/handle_policy.h"
16 #include "sandbox/win/src/job.h"
17 #include "sandbox/win/src/interception.h"
18 #include "sandbox/win/src/process_mitigations.h"
19 #include "sandbox/win/src/named_pipe_dispatcher.h"
20 #include "sandbox/win/src/named_pipe_policy.h"
21 #include "sandbox/win/src/policy_broker.h"
22 #include "sandbox/win/src/policy_engine_processor.h"
23 #include "sandbox/win/src/policy_low_level.h"
24 #include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
25 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
26 #include "sandbox/win/src/process_thread_dispatcher.h"
27 #include "sandbox/win/src/process_thread_policy.h"
28 #include "sandbox/win/src/registry_dispatcher.h"
29 #include "sandbox/win/src/registry_policy.h"
30 #include "sandbox/win/src/restricted_token_utils.h"
31 #include "sandbox/win/src/sandbox_policy.h"
32 #include "sandbox/win/src/sync_dispatcher.h"
33 #include "sandbox/win/src/sync_policy.h"
34 #include "sandbox/win/src/target_process.h"
35 #include "sandbox/win/src/window.h"
36
37 namespace {
38
39 // The standard windows size for one memory page.
40 const size_t kOneMemPage = 4096;
41 // The IPC and Policy shared memory sizes.
42 const size_t kIPCMemSize = kOneMemPage * 2;
43 const size_t kPolMemSize = kOneMemPage * 14;
44
45 // Helper function to allocate space (on the heap) for policy.
MakeBrokerPolicyMemory()46 sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
47 const size_t kTotalPolicySz = kPolMemSize;
48 sandbox::PolicyGlobal* policy = static_cast<sandbox::PolicyGlobal*>
49 (::operator new(kTotalPolicySz));
50 DCHECK(policy);
51 memset(policy, 0, kTotalPolicySz);
52 policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
53 return policy;
54 }
55
IsInheritableHandle(HANDLE handle)56 bool IsInheritableHandle(HANDLE handle) {
57 if (!handle)
58 return false;
59 if (handle == INVALID_HANDLE_VALUE)
60 return false;
61 // File handles (FILE_TYPE_DISK) and pipe handles are known to be
62 // inheritable. Console handles (FILE_TYPE_CHAR) are not
63 // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
64 DWORD handle_type = GetFileType(handle);
65 return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
66 }
67
68 }
69
70 namespace sandbox {
71
72 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
73 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
74
75 // Initializes static members.
76 HWINSTA PolicyBase::alternate_winstation_handle_ = NULL;
77 HDESK PolicyBase::alternate_desktop_handle_ = NULL;
78
PolicyBase()79 PolicyBase::PolicyBase()
80 : ref_count(1),
81 lockdown_level_(USER_LOCKDOWN),
82 initial_level_(USER_LOCKDOWN),
83 job_level_(JOB_LOCKDOWN),
84 ui_exceptions_(0),
85 memory_limit_(0),
86 use_alternate_desktop_(false),
87 use_alternate_winstation_(false),
88 file_system_init_(false),
89 relaxed_interceptions_(true),
90 stdout_handle_(INVALID_HANDLE_VALUE),
91 stderr_handle_(INVALID_HANDLE_VALUE),
92 integrity_level_(INTEGRITY_LEVEL_LAST),
93 delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
94 mitigations_(0),
95 delayed_mitigations_(0),
96 policy_maker_(NULL),
97 policy_(NULL) {
98 ::InitializeCriticalSection(&lock_);
99 // Initialize the IPC dispatcher array.
100 memset(&ipc_targets_, NULL, sizeof(ipc_targets_));
101 Dispatcher* dispatcher = NULL;
102
103 dispatcher = new FilesystemDispatcher(this);
104 ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher;
105 ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher;
106 ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher;
107 ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher;
108 ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher;
109
110 dispatcher = new NamedPipeDispatcher(this);
111 ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher;
112
113 dispatcher = new ThreadProcessDispatcher(this);
114 ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher;
115 ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher;
116 ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher;
117 ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher;
118 ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher;
119
120 dispatcher = new SyncDispatcher(this);
121 ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher;
122 ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
123
124 dispatcher = new RegistryDispatcher(this);
125 ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
126 ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
127
128 dispatcher = new HandleDispatcher(this);
129 ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
130
131 dispatcher = new ProcessMitigationsWin32KDispatcher(this);
132 ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
133 ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
134 ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
135 }
136
~PolicyBase()137 PolicyBase::~PolicyBase() {
138 TargetSet::iterator it;
139 for (it = targets_.begin(); it != targets_.end(); ++it) {
140 TargetProcess* target = (*it);
141 delete target;
142 }
143 delete ipc_targets_[IPC_NTCREATEFILE_TAG];
144 delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG];
145 delete ipc_targets_[IPC_NTOPENTHREAD_TAG];
146 delete ipc_targets_[IPC_CREATEEVENT_TAG];
147 delete ipc_targets_[IPC_NTCREATEKEY_TAG];
148 delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG];
149 delete policy_maker_;
150 delete policy_;
151 ::DeleteCriticalSection(&lock_);
152 }
153
AddRef()154 void PolicyBase::AddRef() {
155 ::InterlockedIncrement(&ref_count);
156 }
157
Release()158 void PolicyBase::Release() {
159 if (0 == ::InterlockedDecrement(&ref_count))
160 delete this;
161 }
162
SetTokenLevel(TokenLevel initial,TokenLevel lockdown)163 ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
164 if (initial < lockdown) {
165 return SBOX_ERROR_BAD_PARAMS;
166 }
167 initial_level_ = initial;
168 lockdown_level_ = lockdown;
169 return SBOX_ALL_OK;
170 }
171
GetInitialTokenLevel() const172 TokenLevel PolicyBase::GetInitialTokenLevel() const {
173 return initial_level_;
174 }
175
GetLockdownTokenLevel() const176 TokenLevel PolicyBase::GetLockdownTokenLevel() const{
177 return lockdown_level_;
178 }
179
SetJobLevel(JobLevel job_level,uint32 ui_exceptions)180 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
181 if (memory_limit_ && job_level == JOB_NONE) {
182 return SBOX_ERROR_BAD_PARAMS;
183 }
184 job_level_ = job_level;
185 ui_exceptions_ = ui_exceptions;
186 return SBOX_ALL_OK;
187 }
188
SetJobMemoryLimit(size_t memory_limit)189 ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
190 if (memory_limit && job_level_ == JOB_NONE) {
191 return SBOX_ERROR_BAD_PARAMS;
192 }
193 memory_limit_ = memory_limit;
194 return SBOX_ALL_OK;
195 }
196
SetAlternateDesktop(bool alternate_winstation)197 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
198 use_alternate_desktop_ = true;
199 use_alternate_winstation_ = alternate_winstation;
200 return CreateAlternateDesktop(alternate_winstation);
201 }
202
GetAlternateDesktop() const203 base::string16 PolicyBase::GetAlternateDesktop() const {
204 // No alternate desktop or winstation. Return an empty string.
205 if (!use_alternate_desktop_ && !use_alternate_winstation_) {
206 return base::string16();
207 }
208
209 // The desktop and winstation should have been created by now.
210 // If we hit this scenario, it means that the user ignored the failure
211 // during SetAlternateDesktop, so we ignore it here too.
212 if (use_alternate_desktop_ && !alternate_desktop_handle_) {
213 return base::string16();
214 }
215 if (use_alternate_winstation_ && (!alternate_desktop_handle_ ||
216 !alternate_winstation_handle_)) {
217 return base::string16();
218 }
219
220 return GetFullDesktopName(alternate_winstation_handle_,
221 alternate_desktop_handle_);
222 }
223
CreateAlternateDesktop(bool alternate_winstation)224 ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
225 if (alternate_winstation) {
226 // Previously called with alternate_winstation = false?
227 if (!alternate_winstation_handle_ && alternate_desktop_handle_)
228 return SBOX_ERROR_UNSUPPORTED;
229
230 // Check if it's already created.
231 if (alternate_winstation_handle_ && alternate_desktop_handle_)
232 return SBOX_ALL_OK;
233
234 DCHECK(!alternate_winstation_handle_);
235 // Create the window station.
236 ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
237 if (SBOX_ALL_OK != result)
238 return result;
239
240 // Verify that everything is fine.
241 if (!alternate_winstation_handle_ ||
242 GetWindowObjectName(alternate_winstation_handle_).empty())
243 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
244
245 // Create the destkop.
246 result = CreateAltDesktop(alternate_winstation_handle_,
247 &alternate_desktop_handle_);
248 if (SBOX_ALL_OK != result)
249 return result;
250
251 // Verify that everything is fine.
252 if (!alternate_desktop_handle_ ||
253 GetWindowObjectName(alternate_desktop_handle_).empty())
254 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
255 } else {
256 // Previously called with alternate_winstation = true?
257 if (alternate_winstation_handle_)
258 return SBOX_ERROR_UNSUPPORTED;
259
260 // Check if it already exists.
261 if (alternate_desktop_handle_)
262 return SBOX_ALL_OK;
263
264 // Create the destkop.
265 ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_);
266 if (SBOX_ALL_OK != result)
267 return result;
268
269 // Verify that everything is fine.
270 if (!alternate_desktop_handle_ ||
271 GetWindowObjectName(alternate_desktop_handle_).empty())
272 return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
273 }
274
275 return SBOX_ALL_OK;
276 }
277
DestroyAlternateDesktop()278 void PolicyBase::DestroyAlternateDesktop() {
279 if (alternate_desktop_handle_) {
280 ::CloseDesktop(alternate_desktop_handle_);
281 alternate_desktop_handle_ = NULL;
282 }
283
284 if (alternate_winstation_handle_) {
285 ::CloseWindowStation(alternate_winstation_handle_);
286 alternate_winstation_handle_ = NULL;
287 }
288 }
289
SetIntegrityLevel(IntegrityLevel integrity_level)290 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
291 integrity_level_ = integrity_level;
292 return SBOX_ALL_OK;
293 }
294
GetIntegrityLevel() const295 IntegrityLevel PolicyBase::GetIntegrityLevel() const {
296 return integrity_level_;
297 }
298
SetDelayedIntegrityLevel(IntegrityLevel integrity_level)299 ResultCode PolicyBase::SetDelayedIntegrityLevel(
300 IntegrityLevel integrity_level) {
301 delayed_integrity_level_ = integrity_level;
302 return SBOX_ALL_OK;
303 }
304
SetAppContainer(const wchar_t * sid)305 ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) {
306 if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
307 return SBOX_ALL_OK;
308
309 // Windows refuses to work with an impersonation token for a process inside
310 // an AppContainer. If the caller wants to use a more privileged initial
311 // token, or if the lockdown level will prevent the process from starting,
312 // we have to fail the operation.
313 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
314 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
315
316 DCHECK(!appcontainer_list_.get());
317 appcontainer_list_.reset(new AppContainerAttributes);
318 ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_);
319 if (rv != SBOX_ALL_OK)
320 return rv;
321
322 return SBOX_ALL_OK;
323 }
324
SetCapability(const wchar_t * sid)325 ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
326 capabilities_.push_back(sid);
327 return SBOX_ALL_OK;
328 }
329
SetProcessMitigations(MitigationFlags flags)330 ResultCode PolicyBase::SetProcessMitigations(
331 MitigationFlags flags) {
332 if (!CanSetProcessMitigationsPreStartup(flags))
333 return SBOX_ERROR_BAD_PARAMS;
334 mitigations_ = flags;
335 return SBOX_ALL_OK;
336 }
337
GetProcessMitigations()338 MitigationFlags PolicyBase::GetProcessMitigations() {
339 return mitigations_;
340 }
341
SetDelayedProcessMitigations(MitigationFlags flags)342 ResultCode PolicyBase::SetDelayedProcessMitigations(
343 MitigationFlags flags) {
344 if (!CanSetProcessMitigationsPostStartup(flags))
345 return SBOX_ERROR_BAD_PARAMS;
346 delayed_mitigations_ = flags;
347 return SBOX_ALL_OK;
348 }
349
GetDelayedProcessMitigations() const350 MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
351 return delayed_mitigations_;
352 }
353
SetStrictInterceptions()354 void PolicyBase::SetStrictInterceptions() {
355 relaxed_interceptions_ = false;
356 }
357
SetStdoutHandle(HANDLE handle)358 ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
359 if (!IsInheritableHandle(handle))
360 return SBOX_ERROR_BAD_PARAMS;
361 stdout_handle_ = handle;
362 return SBOX_ALL_OK;
363 }
364
SetStderrHandle(HANDLE handle)365 ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
366 if (!IsInheritableHandle(handle))
367 return SBOX_ERROR_BAD_PARAMS;
368 stderr_handle_ = handle;
369 return SBOX_ALL_OK;
370 }
371
AddRule(SubSystem subsystem,Semantics semantics,const wchar_t * pattern)372 ResultCode PolicyBase::AddRule(SubSystem subsystem, Semantics semantics,
373 const wchar_t* pattern) {
374 if (NULL == policy_) {
375 policy_ = MakeBrokerPolicyMemory();
376 DCHECK(policy_);
377 policy_maker_ = new LowLevelPolicy(policy_);
378 DCHECK(policy_maker_);
379 }
380
381 switch (subsystem) {
382 case SUBSYS_FILES: {
383 if (!file_system_init_) {
384 if (!FileSystemPolicy::SetInitialRules(policy_maker_))
385 return SBOX_ERROR_BAD_PARAMS;
386 file_system_init_ = true;
387 }
388 if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
389 NOTREACHED();
390 return SBOX_ERROR_BAD_PARAMS;
391 }
392 break;
393 }
394 case SUBSYS_SYNC: {
395 if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
396 NOTREACHED();
397 return SBOX_ERROR_BAD_PARAMS;
398 }
399 break;
400 }
401 case SUBSYS_PROCESS: {
402 if (lockdown_level_ < USER_INTERACTIVE &&
403 TargetPolicy::PROCESS_ALL_EXEC == semantics) {
404 // This is unsupported. This is a huge security risk to give full access
405 // to a process handle.
406 return SBOX_ERROR_UNSUPPORTED;
407 }
408 if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
409 NOTREACHED();
410 return SBOX_ERROR_BAD_PARAMS;
411 }
412 break;
413 }
414 case SUBSYS_NAMED_PIPES: {
415 if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
416 NOTREACHED();
417 return SBOX_ERROR_BAD_PARAMS;
418 }
419 break;
420 }
421 case SUBSYS_REGISTRY: {
422 if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
423 NOTREACHED();
424 return SBOX_ERROR_BAD_PARAMS;
425 }
426 break;
427 }
428 case SUBSYS_HANDLES: {
429 if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
430 NOTREACHED();
431 return SBOX_ERROR_BAD_PARAMS;
432 }
433 break;
434 }
435
436 case SUBSYS_WIN32K_LOCKDOWN: {
437 if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
438 pattern, semantics,policy_maker_)) {
439 NOTREACHED();
440 return SBOX_ERROR_BAD_PARAMS;
441 }
442 break;
443 }
444
445 default: {
446 return SBOX_ERROR_UNSUPPORTED;
447 }
448 }
449
450 return SBOX_ALL_OK;
451 }
452
AddDllToUnload(const wchar_t * dll_name)453 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
454 blacklisted_dlls_.push_back(dll_name);
455 return SBOX_ALL_OK;
456 }
457
AddKernelObjectToClose(const base::char16 * handle_type,const base::char16 * handle_name)458 ResultCode PolicyBase::AddKernelObjectToClose(const base::char16* handle_type,
459 const base::char16* handle_name) {
460 return handle_closer_.AddHandle(handle_type, handle_name);
461 }
462
463 // When an IPC is ready in any of the targets we get called. We manage an array
464 // of IPC dispatchers which are keyed on the IPC tag so we normally delegate
465 // to the appropriate dispatcher unless we can handle the IPC call ourselves.
OnMessageReady(IPCParams * ipc,CallbackGeneric * callback)466 Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc,
467 CallbackGeneric* callback) {
468 DCHECK(callback);
469 static const IPCParams ping1 = {IPC_PING1_TAG, ULONG_TYPE};
470 static const IPCParams ping2 = {IPC_PING2_TAG, INOUTPTR_TYPE};
471
472 if (ping1.Matches(ipc) || ping2.Matches(ipc)) {
473 *callback = reinterpret_cast<CallbackGeneric>(
474 static_cast<Callback1>(&PolicyBase::Ping));
475 return this;
476 }
477
478 Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag);
479 if (!dispatch) {
480 NOTREACHED();
481 return NULL;
482 }
483 return dispatch->OnMessageReady(ipc, callback);
484 }
485
486 // Delegate to the appropriate dispatcher.
SetupService(InterceptionManager * manager,int service)487 bool PolicyBase::SetupService(InterceptionManager* manager, int service) {
488 if (IPC_PING1_TAG == service || IPC_PING2_TAG == service)
489 return true;
490
491 Dispatcher* dispatch = GetDispatcher(service);
492 if (!dispatch) {
493 NOTREACHED();
494 return false;
495 }
496 return dispatch->SetupService(manager, service);
497 }
498
MakeJobObject(HANDLE * job)499 ResultCode PolicyBase::MakeJobObject(HANDLE* job) {
500 if (job_level_ != JOB_NONE) {
501 // Create the windows job object.
502 Job job_obj;
503 DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_,
504 memory_limit_);
505 if (ERROR_SUCCESS != result) {
506 return SBOX_ERROR_GENERIC;
507 }
508 *job = job_obj.Detach();
509 } else {
510 *job = NULL;
511 }
512 return SBOX_ALL_OK;
513 }
514
MakeTokens(HANDLE * initial,HANDLE * lockdown)515 ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
516 // Create the 'naked' token. This will be the permanent token associated
517 // with the process and therefore with any thread that is not impersonating.
518 DWORD result = CreateRestrictedToken(lockdown, lockdown_level_,
519 integrity_level_, PRIMARY);
520 if (ERROR_SUCCESS != result) {
521 return SBOX_ERROR_GENERIC;
522 }
523
524 if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) {
525 // Windows refuses to work with an impersonation token. See SetAppContainer
526 // implementation for more details.
527 if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
528 return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
529
530 *initial = INVALID_HANDLE_VALUE;
531 return SBOX_ALL_OK;
532 }
533
534 // Create the 'better' token. We use this token as the one that the main
535 // thread uses when booting up the process. It should contain most of
536 // what we need (before reaching main( ))
537 result = CreateRestrictedToken(initial, initial_level_,
538 integrity_level_, IMPERSONATION);
539 if (ERROR_SUCCESS != result) {
540 ::CloseHandle(*lockdown);
541 return SBOX_ERROR_GENERIC;
542 }
543 return SBOX_ALL_OK;
544 }
545
GetAppContainer()546 const AppContainerAttributes* PolicyBase::GetAppContainer() {
547 if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
548 return NULL;
549
550 return appcontainer_list_.get();
551 }
552
AddTarget(TargetProcess * target)553 bool PolicyBase::AddTarget(TargetProcess* target) {
554 if (NULL != policy_)
555 policy_maker_->Done();
556
557 if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
558 mitigations_)) {
559 return false;
560 }
561
562 if (!SetupAllInterceptions(target))
563 return false;
564
565 if (!SetupHandleCloser(target))
566 return false;
567
568 // Initialize the sandbox infrastructure for the target.
569 if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize))
570 return false;
571
572 g_shared_delayed_integrity_level = delayed_integrity_level_;
573 ResultCode ret = target->TransferVariable(
574 "g_shared_delayed_integrity_level",
575 &g_shared_delayed_integrity_level,
576 sizeof(g_shared_delayed_integrity_level));
577 g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
578 if (SBOX_ALL_OK != ret)
579 return false;
580
581 // Add in delayed mitigations and pseudo-mitigations enforced at startup.
582 g_shared_delayed_mitigations = delayed_mitigations_ |
583 FilterPostStartupProcessMitigations(mitigations_);
584 if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
585 return false;
586
587 ret = target->TransferVariable("g_shared_delayed_mitigations",
588 &g_shared_delayed_mitigations,
589 sizeof(g_shared_delayed_mitigations));
590 g_shared_delayed_mitigations = 0;
591 if (SBOX_ALL_OK != ret)
592 return false;
593
594 AutoLock lock(&lock_);
595 targets_.push_back(target);
596 return true;
597 }
598
OnJobEmpty(HANDLE job)599 bool PolicyBase::OnJobEmpty(HANDLE job) {
600 AutoLock lock(&lock_);
601 TargetSet::iterator it;
602 for (it = targets_.begin(); it != targets_.end(); ++it) {
603 if ((*it)->Job() == job)
604 break;
605 }
606 if (it == targets_.end()) {
607 return false;
608 }
609 TargetProcess* target = *it;
610 targets_.erase(it);
611 delete target;
612 return true;
613 }
614
EvalPolicy(int service,CountedParameterSetBase * params)615 EvalResult PolicyBase::EvalPolicy(int service,
616 CountedParameterSetBase* params) {
617 if (NULL != policy_) {
618 if (NULL == policy_->entry[service]) {
619 // There is no policy for this particular service. This is not a big
620 // deal.
621 return DENY_ACCESS;
622 }
623 for (int i = 0; i < params->count; i++) {
624 if (!params->parameters[i].IsValid()) {
625 NOTREACHED();
626 return SIGNAL_ALARM;
627 }
628 }
629 PolicyProcessor pol_evaluator(policy_->entry[service]);
630 PolicyResult result = pol_evaluator.Evaluate(kShortEval,
631 params->parameters,
632 params->count);
633 if (POLICY_MATCH == result) {
634 return pol_evaluator.GetAction();
635 }
636 DCHECK(POLICY_ERROR != result);
637 }
638
639 return DENY_ACCESS;
640 }
641
GetStdoutHandle()642 HANDLE PolicyBase::GetStdoutHandle() {
643 return stdout_handle_;
644 }
645
GetStderrHandle()646 HANDLE PolicyBase::GetStderrHandle() {
647 return stderr_handle_;
648 }
649
650 // We service IPC_PING_TAG message which is a way to test a round trip of the
651 // IPC subsystem. We receive a integer cookie and we are expected to return the
652 // cookie times two (or three) and the current tick count.
Ping(IPCInfo * ipc,void * arg1)653 bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) {
654 switch (ipc->ipc_tag) {
655 case IPC_PING1_TAG: {
656 IPCInt ipc_int(arg1);
657 uint32 cookie = ipc_int.As32Bit();
658 ipc->return_info.extended_count = 2;
659 ipc->return_info.extended[0].unsigned_int = ::GetTickCount();
660 ipc->return_info.extended[1].unsigned_int = 2 * cookie;
661 return true;
662 }
663 case IPC_PING2_TAG: {
664 CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1);
665 if (sizeof(uint32) != io_buffer->Size())
666 return false;
667
668 uint32* cookie = reinterpret_cast<uint32*>(io_buffer->Buffer());
669 *cookie = (*cookie) * 3;
670 return true;
671 }
672 default: return false;
673 }
674 }
675
GetDispatcher(int ipc_tag)676 Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) {
677 if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG)
678 return NULL;
679
680 return ipc_targets_[ipc_tag];
681 }
682
SetupAllInterceptions(TargetProcess * target)683 bool PolicyBase::SetupAllInterceptions(TargetProcess* target) {
684 InterceptionManager manager(target, relaxed_interceptions_);
685
686 if (policy_) {
687 for (int i = 0; i < IPC_LAST_TAG; i++) {
688 if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i))
689 return false;
690 }
691 }
692
693 if (!blacklisted_dlls_.empty()) {
694 std::vector<base::string16>::iterator it = blacklisted_dlls_.begin();
695 for (; it != blacklisted_dlls_.end(); ++it) {
696 manager.AddToUnloadModules(it->c_str());
697 }
698 }
699
700 if (!SetupBasicInterceptions(&manager))
701 return false;
702
703 if (!manager.InitializeInterceptions())
704 return false;
705
706 // Finally, setup imports on the target so the interceptions can work.
707 return SetupNtdllImports(target);
708 }
709
SetupHandleCloser(TargetProcess * target)710 bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
711 return handle_closer_.InitializeTargetHandles(target);
712 }
713
714 } // namespace sandbox
715