Home | History | Annotate | Download | only in src
      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.
     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 
     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 
     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 
    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 
    146 void PolicyBase::AddRef() {
    147   ::InterlockedIncrement(&ref_count);
    148 }
    149 
    150 void PolicyBase::Release() {
    151   if (0 == ::InterlockedDecrement(&ref_count))
    152     delete this;
    153 }
    154 
    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 
    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 
    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 
    176 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 
    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 
    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 
    263 ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
    264   integrity_level_ = integrity_level;
    265   return SBOX_ALL_OK;
    266 }
    267 
    268 ResultCode PolicyBase::SetDelayedIntegrityLevel(
    269     IntegrityLevel integrity_level) {
    270   delayed_integrity_level_ = integrity_level;
    271   return SBOX_ALL_OK;
    272 }
    273 
    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 
    294 ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
    295   capabilities_.push_back(sid);
    296   return SBOX_ALL_OK;
    297 }
    298 
    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 
    307 MitigationFlags PolicyBase::GetProcessMitigations() {
    308   return mitigations_;
    309 }
    310 
    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 
    319 MitigationFlags PolicyBase::GetDelayedProcessMitigations() {
    320   return delayed_mitigations_;
    321 }
    322 
    323 void PolicyBase::SetStrictInterceptions() {
    324   relaxed_interceptions_ = false;
    325 }
    326 
    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 
    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 
    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 
    412 ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
    413   blacklisted_dlls_.push_back(dll_name);
    414   return SBOX_ALL_OK;
    415 }
    416 
    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.
    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.
    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 
    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 
    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 
    504 const AppContainerAttributes* PolicyBase::GetAppContainer() {
    505   if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
    506     return NULL;
    507 
    508   return appcontainer_list_.get();
    509 }
    510 
    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 
    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 
    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 
    600 HANDLE PolicyBase::GetStdoutHandle() {
    601   return stdout_handle_;
    602 }
    603 
    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.
    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 
    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 
    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 
    671 bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
    672   return handle_closer_.InitializeTargetHandles(target);
    673 }
    674 
    675 }  // namespace sandbox
    676