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/target_services.h"
      6 
      7 #include <process.h>
      8 
      9 #include "base/basictypes.h"
     10 #include "sandbox/win/src/crosscall_client.h"
     11 #include "sandbox/win/src/handle_closer_agent.h"
     12 #include "sandbox/win/src/handle_interception.h"
     13 #include "sandbox/win/src/ipc_tags.h"
     14 #include "sandbox/win/src/process_mitigations.h"
     15 #include "sandbox/win/src/restricted_token_utils.h"
     16 #include "sandbox/win/src/sandbox.h"
     17 #include "sandbox/win/src/sandbox_types.h"
     18 #include "sandbox/win/src/sharedmem_ipc_client.h"
     19 #include "sandbox/win/src/sandbox_nt_util.h"
     20 
     21 namespace {
     22 
     23 // Flushing a cached key is triggered by just opening the key and closing the
     24 // resulting handle. RegDisablePredefinedCache() is the documented way to flush
     25 // HKCU so do not use it with this function.
     26 bool FlushRegKey(HKEY root) {
     27   HKEY key;
     28   if (ERROR_SUCCESS == ::RegOpenKeyExW(root, NULL, 0, MAXIMUM_ALLOWED, &key)) {
     29     if (ERROR_SUCCESS != ::RegCloseKey(key))
     30       return false;
     31   }
     32   return true;
     33 }
     34 
     35 // This function forces advapi32.dll to release some internally cached handles
     36 // that were made during calls to RegOpenkey and RegOpenKeyEx if it is called
     37 // with a more restrictive token. Returns true if the flushing is succesful
     38 // although this behavior is undocumented and there is no guarantee that in
     39 // fact this will happen in future versions of windows.
     40 bool FlushCachedRegHandles() {
     41   return (FlushRegKey(HKEY_LOCAL_MACHINE) &&
     42           FlushRegKey(HKEY_CLASSES_ROOT) &&
     43           FlushRegKey(HKEY_USERS));
     44 }
     45 
     46 // Checks if we have handle entries pending and runs the closer.
     47 bool CloseOpenHandles() {
     48   if (sandbox::HandleCloserAgent::NeedsHandlesClosed()) {
     49     sandbox::HandleCloserAgent handle_closer;
     50 
     51     handle_closer.InitializeHandlesToClose();
     52     if (!handle_closer.CloseHandles())
     53       return false;
     54   }
     55 
     56   return true;
     57 }
     58 
     59 }  // namespace
     60 
     61 namespace sandbox {
     62 
     63 SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level =
     64     INTEGRITY_LEVEL_LAST;
     65 SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations = 0;
     66 
     67 TargetServicesBase::TargetServicesBase() {
     68 }
     69 
     70 ResultCode TargetServicesBase::Init() {
     71   process_state_.SetInitCalled();
     72   return SBOX_ALL_OK;
     73 }
     74 
     75 // Failure here is a breach of security so the process is terminated.
     76 void TargetServicesBase::LowerToken() {
     77   if (ERROR_SUCCESS !=
     78       SetProcessIntegrityLevel(g_shared_delayed_integrity_level))
     79     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_INTEGRITY);
     80   process_state_.SetRevertedToSelf();
     81   // If the client code as called RegOpenKey, advapi32.dll has cached some
     82   // handles. The following code gets rid of them.
     83   if (!::RevertToSelf())
     84     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_DROPTOKEN);
     85   if (!FlushCachedRegHandles())
     86     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES);
     87   if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
     88     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
     89   if (!CloseOpenHandles())
     90     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
     91   // Enabling mitigations must happen last otherwise handle closing breaks
     92   if (g_shared_delayed_mitigations &&
     93       !ApplyProcessMitigationsToCurrentProcess(g_shared_delayed_mitigations))
     94     ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_MITIGATION);
     95 }
     96 
     97 ProcessState* TargetServicesBase::GetState() {
     98   return &process_state_;
     99 }
    100 
    101 TargetServicesBase* TargetServicesBase::GetInstance() {
    102   static TargetServicesBase instance;
    103   return &instance;
    104 }
    105 
    106 // The broker services a 'test' IPC service with the IPC_PING_TAG tag.
    107 bool TargetServicesBase::TestIPCPing(int version) {
    108   void* memory = GetGlobalIPCMemory();
    109   if (NULL == memory) {
    110     return false;
    111   }
    112   SharedMemIPCClient ipc(memory);
    113   CrossCallReturn answer = {0};
    114 
    115   if (1 == version) {
    116     uint32 tick1 = ::GetTickCount();
    117     uint32 cookie = 717115;
    118     ResultCode code = CrossCall(ipc, IPC_PING1_TAG, cookie, &answer);
    119 
    120     if (SBOX_ALL_OK != code) {
    121       return false;
    122     }
    123     // We should get two extended returns values from the IPC, one is the
    124     // tick count on the broker and the other is the cookie times two.
    125     if ((answer.extended_count != 2)) {
    126       return false;
    127     }
    128     // We test the first extended answer to be within the bounds of the tick
    129     // count only if there was no tick count wraparound.
    130     uint32 tick2 = ::GetTickCount();
    131     if (tick2 >= tick1) {
    132       if ((answer.extended[0].unsigned_int < tick1) ||
    133           (answer.extended[0].unsigned_int > tick2)) {
    134         return false;
    135       }
    136     }
    137 
    138     if (answer.extended[1].unsigned_int != cookie * 2) {
    139       return false;
    140     }
    141   } else if (2 == version) {
    142     uint32 cookie = 717111;
    143     InOutCountedBuffer counted_buffer(&cookie, sizeof(cookie));
    144     ResultCode code = CrossCall(ipc, IPC_PING2_TAG, counted_buffer, &answer);
    145 
    146     if (SBOX_ALL_OK != code) {
    147       return false;
    148     }
    149     if (cookie != 717111 * 3) {
    150       return false;
    151     }
    152   } else {
    153     return false;
    154   }
    155   return true;
    156 }
    157 
    158 bool ProcessState::IsKernel32Loaded() {
    159   return process_state_ != 0;
    160 }
    161 
    162 bool ProcessState::InitCalled() {
    163   return process_state_ > 1;
    164 }
    165 
    166 bool ProcessState::RevertedToSelf() {
    167   return process_state_ > 2;
    168 }
    169 
    170 void ProcessState::SetKernel32Loaded() {
    171   if (!process_state_)
    172     process_state_ = 1;
    173 }
    174 
    175 void ProcessState::SetInitCalled() {
    176   if (process_state_ < 2)
    177     process_state_ = 2;
    178 }
    179 
    180 void ProcessState::SetRevertedToSelf() {
    181   if (process_state_ < 3)
    182     process_state_ = 3;
    183 }
    184 
    185 ResultCode TargetServicesBase::DuplicateHandle(HANDLE source_handle,
    186                                                DWORD target_process_id,
    187                                                HANDLE* target_handle,
    188                                                DWORD desired_access,
    189                                                DWORD options) {
    190   return sandbox::DuplicateHandleProxy(source_handle, target_process_id,
    191                                        target_handle, desired_access, options);
    192 }
    193 
    194 }  // namespace sandbox
    195