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