15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/target_services.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <process.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/crosscall_client.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/handle_closer_agent.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/handle_interception.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/ipc_tags.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/process_mitigations.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/restricted_token_utils.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sandbox.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sandbox_types.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sharedmem_ipc_client.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sandbox_nt_util.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Flushing a cached key is triggered by just opening the key and closing the
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resulting handle. RegDisablePredefinedCache() is the documented way to flush
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HKCU so do not use it with this function.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FlushRegKey(HKEY root) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HKEY key;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ERROR_SUCCESS == ::RegOpenKeyExW(root, NULL, 0, MAXIMUM_ALLOWED, &key)) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ERROR_SUCCESS != ::RegCloseKey(key))
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function forces advapi32.dll to release some internally cached handles
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that were made during calls to RegOpenkey and RegOpenKeyEx if it is called
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with a more restrictive token. Returns true if the flushing is succesful
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// although this behavior is undocumented and there is no guarantee that in
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fact this will happen in future versions of windows.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FlushCachedRegHandles() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (FlushRegKey(HKEY_LOCAL_MACHINE) &&
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FlushRegKey(HKEY_CLASSES_ROOT) &&
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FlushRegKey(HKEY_USERS));
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks if we have handle entries pending and runs the closer.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CloseOpenHandles() {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sandbox::HandleCloserAgent::NeedsHandlesClosed()) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sandbox::HandleCloserAgent handle_closer;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handle_closer.InitializeHandlesToClose();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!handle_closer.CloseHandles())
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sandbox {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level =
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    INTEGRITY_LEVEL_LAST;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations = 0;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TargetServicesBase::TargetServicesBase() {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ResultCode TargetServicesBase::Init() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  process_state_.SetInitCalled();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SBOX_ALL_OK;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Failure here is a breach of security so the process is terminated.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TargetServicesBase::LowerToken() {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ERROR_SUCCESS !=
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetProcessIntegrityLevel(g_shared_delayed_integrity_level))
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_INTEGRITY);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  process_state_.SetRevertedToSelf();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the client code as called RegOpenKey, advapi32.dll has cached some
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handles. The following code gets rid of them.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::RevertToSelf())
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_DROPTOKEN);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!FlushCachedRegHandles())
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CloseOpenHandles())
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enabling mitigations must happen last otherwise handle closing breaks
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_shared_delayed_mitigations &&
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !ApplyProcessMitigationsToCurrentProcess(g_shared_delayed_mitigations))
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_MITIGATION);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProcessState* TargetServicesBase::GetState() {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &process_state_;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TargetServicesBase* TargetServicesBase::GetInstance() {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static TargetServicesBase instance;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &instance;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The broker services a 'test' IPC service with the IPC_PING_TAG tag.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TargetServicesBase::TestIPCPing(int version) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* memory = GetGlobalIPCMemory();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == memory) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SharedMemIPCClient ipc(memory);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CrossCallReturn answer = {0};
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (1 == version) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 tick1 = ::GetTickCount();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 cookie = 717115;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResultCode code = CrossCall(ipc, IPC_PING1_TAG, cookie, &answer);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SBOX_ALL_OK != code) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should get two extended returns values from the IPC, one is the
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // tick count on the broker and the other is the cookie times two.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((answer.extended_count != 2)) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We test the first extended answer to be within the bounds of the tick
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // count only if there was no tick count wraparound.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 tick2 = ::GetTickCount();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tick2 >= tick1) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((answer.extended[0].unsigned_int < tick1) ||
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (answer.extended[0].unsigned_int > tick2)) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (answer.extended[1].unsigned_int != cookie * 2) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (2 == version) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 cookie = 717111;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InOutCountedBuffer counted_buffer(&cookie, sizeof(cookie));
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResultCode code = CrossCall(ipc, IPC_PING2_TAG, counted_buffer, &answer);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (SBOX_ALL_OK != code) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cookie != 717111 * 3) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessState::IsKernel32Loaded() {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return process_state_ != 0;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessState::InitCalled() {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return process_state_ > 1;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProcessState::RevertedToSelf() {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return process_state_ > 2;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessState::SetKernel32Loaded() {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!process_state_)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process_state_ = 1;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessState::SetInitCalled() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_state_ < 2)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process_state_ = 2;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessState::SetRevertedToSelf() {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_state_ < 3)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process_state_ = 3;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ResultCode TargetServicesBase::DuplicateHandle(HANDLE source_handle,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               DWORD target_process_id,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               HANDLE* target_handle,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               DWORD desired_access,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               DWORD options) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sandbox::DuplicateHandleProxy(source_handle, target_process_id,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       target_handle, desired_access, options);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace sandbox
195