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