• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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