security/sandbox/win/src/target_services.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial