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