target_services.cc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. #include "sandbox/win/src/target_services.h"
  5. #include <windows.h>
  6. #include <winsock2.h>
  7. #include <new>
  8. #include <process.h>
  9. #include <stdint.h>
  10. #include "base/logging.h"
  11. #include "base/win/windows_version.h"
  12. #include "sandbox/win/src/crosscall_client.h"
  13. #include "sandbox/win/src/handle_closer_agent.h"
  14. #include "sandbox/win/src/heap_helper.h"
  15. #include "sandbox/win/src/ipc_tags.h"
  16. #include "sandbox/win/src/process_mitigations.h"
  17. #include "sandbox/win/src/restricted_token_utils.h"
  18. #include "sandbox/win/src/sandbox.h"
  19. #include "sandbox/win/src/sandbox_nt_util.h"
  20. #include "sandbox/win/src/sandbox_types.h"
  21. #include "sandbox/win/src/sharedmem_ipc_client.h"
  22. namespace sandbox {
  23. namespace {
  24. // Flushing a cached key is triggered by just opening the key and closing the
  25. // resulting handle. RegDisablePredefinedCache() is the documented way to flush
  26. // HKCU so do not use it with this function.
  27. bool FlushRegKey(HKEY root) {
  28. HKEY key;
  29. if (ERROR_SUCCESS ==
  30. ::RegOpenKeyExW(root, nullptr, 0, MAXIMUM_ALLOWED, &key)) {
  31. if (ERROR_SUCCESS != ::RegCloseKey(key))
  32. return false;
  33. }
  34. return true;
  35. }
  36. // This function forces advapi32.dll to release some internally cached handles
  37. // that were made during calls to RegOpenkey and RegOpenKeyEx if it is called
  38. // with a more restrictive token. Returns true if the flushing is succesful
  39. // although this behavior is undocumented and there is no guarantee that in
  40. // fact this will happen in future versions of windows.
  41. bool FlushCachedRegHandles() {
  42. return (FlushRegKey(HKEY_LOCAL_MACHINE) && FlushRegKey(HKEY_CLASSES_ROOT) &&
  43. FlushRegKey(HKEY_USERS));
  44. }
  45. // Cleans up this process if CSRSS will be disconnected, as this disconnection
  46. // is not supported Windows behavior.
  47. // Currently, this step requires closing a heap that this shared with csrss.exe.
  48. // Closing the ALPC Port handle to csrss.exe leaves this heap in an invalid
  49. // state. This causes problems if anyone enumerates the heap.
  50. bool CsrssDisconnectCleanup() {
  51. HANDLE csr_port_heap = FindCsrPortHeap();
  52. if (!csr_port_heap) {
  53. DLOG(ERROR) << "Failed to find CSR Port heap handle";
  54. return false;
  55. }
  56. HeapDestroy(csr_port_heap);
  57. return true;
  58. }
  59. // Used by EnumSystemLocales for warming up.
  60. static BOOL CALLBACK EnumLocalesProcEx(LPWSTR lpLocaleString,
  61. DWORD dwFlags,
  62. LPARAM lParam) {
  63. return TRUE;
  64. }
  65. // Additional warmup done just when CSRSS is being disconnected.
  66. bool CsrssDisconnectWarmup() {
  67. return ::EnumSystemLocalesEx(EnumLocalesProcEx, LOCALE_WINDOWS, 0, 0);
  68. }
  69. // Checks if we have handle entries pending and runs the closer.
  70. // Updates is_csrss_connected based on which handle types are closed.
  71. bool CloseOpenHandles(bool* is_csrss_connected) {
  72. if (HandleCloserAgent::NeedsHandlesClosed()) {
  73. HandleCloserAgent handle_closer;
  74. handle_closer.InitializeHandlesToClose(is_csrss_connected);
  75. if (!*is_csrss_connected) {
  76. if (!CsrssDisconnectWarmup() || !CsrssDisconnectCleanup()) {
  77. return false;
  78. }
  79. }
  80. if (!handle_closer.CloseHandles())
  81. return false;
  82. }
  83. return true;
  84. }
  85. // Warm up language subsystems before the sandbox is turned on.
  86. // Tested on Win8.1 x64:
  87. // This needs to happen after RevertToSelf() is called, because (at least) in
  88. // the case of GetUserDefaultLCID() it checks the TEB to see if the process is
  89. // impersonating (TEB!IsImpersonating). If it is, the cached locale information
  90. // is not used, nor is it set. Therefore, calls after RevertToSelf() will not
  91. // have warmed-up values to use.
  92. bool WarmupWindowsLocales() {
  93. // NOTE(liamjm): When last checked (Win 8.1 x64) it wasn't necessary to
  94. // warmup all of these functions, but let's not assume that.
  95. ::GetUserDefaultLangID();
  96. ::GetUserDefaultLCID();
  97. wchar_t localeName[LOCALE_NAME_MAX_LENGTH] = {0};
  98. return (0 != ::GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH));
  99. }
  100. // Used as storage for g_target_services, because other allocation facilities
  101. // are not available early. We can't use a regular function static because on
  102. // VS2015, because the CRT tries to acquire a lock to guard initialization, but
  103. // this code runs before the CRT is initialized.
  104. char g_target_services_memory[sizeof(TargetServicesBase)];
  105. TargetServicesBase* g_target_services = nullptr;
  106. } // namespace
  107. SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level =
  108. INTEGRITY_LEVEL_LAST;
  109. SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations = 0;
  110. TargetServicesBase::TargetServicesBase() {}
  111. ResultCode TargetServicesBase::Init() {
  112. process_state_.SetInitCalled();
  113. return SBOX_ALL_OK;
  114. }
  115. // Failure here is a breach of security so the process is terminated.
  116. void TargetServicesBase::LowerToken() {
  117. if (ERROR_SUCCESS !=
  118. SetProcessIntegrityLevel(g_shared_delayed_integrity_level))
  119. ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_INTEGRITY);
  120. process_state_.SetRevertedToSelf();
  121. // If the client code as called RegOpenKey, advapi32.dll has cached some
  122. // handles. The following code gets rid of them.
  123. if (!::RevertToSelf())
  124. ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_DROPTOKEN);
  125. if (!FlushCachedRegHandles())
  126. ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES);
  127. if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
  128. ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
  129. if (!WarmupWindowsLocales())
  130. ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_WARMUP);
  131. bool is_csrss_connected = true;
  132. if (!CloseOpenHandles(&is_csrss_connected))
  133. ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
  134. process_state_.SetCsrssConnected(is_csrss_connected);
  135. // Enabling mitigations must happen last otherwise handle closing breaks
  136. if (g_shared_delayed_mitigations &&
  137. !ApplyProcessMitigationsToCurrentProcess(g_shared_delayed_mitigations))
  138. ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_MITIGATION);
  139. }
  140. ProcessState* TargetServicesBase::GetState() {
  141. return &process_state_;
  142. }
  143. TargetServicesBase* TargetServicesBase::GetInstance() {
  144. // Leak on purpose TargetServicesBase.
  145. if (!g_target_services)
  146. g_target_services = new (g_target_services_memory) TargetServicesBase;
  147. return g_target_services;
  148. }
  149. SOCKET TargetServicesBase::CreateBrokeredSocket(int af,
  150. int type,
  151. int protocol) {
  152. if (!GetState()->InitCalled())
  153. return INVALID_SOCKET;
  154. // IPC must be fully started.
  155. void* memory = GetGlobalIPCMemory();
  156. if (!memory)
  157. return INVALID_SOCKET;
  158. CrossCallReturn answer = {0};
  159. SharedMemIPCClient ipc(memory);
  160. WSAPROTOCOL_INFOW protocol_info = {};
  161. InOutCountedBuffer protocol_info_buffer(&protocol_info,
  162. sizeof(WSAPROTOCOL_INFOW));
  163. ResultCode code = CrossCall(ipc, IpcTag::WS2SOCKET, af, type, protocol,
  164. protocol_info_buffer, &answer);
  165. if (code != SBOX_ALL_OK)
  166. return INVALID_SOCKET;
  167. if (answer.extended_count == 1)
  168. WSASetLastError(static_cast<int>(answer.extended[0].unsigned_int));
  169. return ::WSASocket(af, type, protocol, &protocol_info, 0,
  170. WSA_FLAG_OVERLAPPED);
  171. }
  172. // The broker services a 'test' IPC service with the PING tag.
  173. bool TargetServicesBase::TestIPCPing(int version) {
  174. void* memory = GetGlobalIPCMemory();
  175. if (!memory)
  176. return false;
  177. SharedMemIPCClient ipc(memory);
  178. CrossCallReturn answer = {0};
  179. if (1 == version) {
  180. uint32_t tick1 = ::GetTickCount();
  181. uint32_t cookie = 717115;
  182. ResultCode code = CrossCall(ipc, IpcTag::PING1, cookie, &answer);
  183. if (SBOX_ALL_OK != code) {
  184. return false;
  185. }
  186. // We should get two extended returns values from the IPC, one is the
  187. // tick count on the broker and the other is the cookie times two.
  188. if ((answer.extended_count != 2)) {
  189. return false;
  190. }
  191. // We test the first extended answer to be within the bounds of the tick
  192. // count only if there was no tick count wraparound.
  193. uint32_t tick2 = ::GetTickCount();
  194. if (tick2 >= tick1) {
  195. if ((answer.extended[0].unsigned_int < tick1) ||
  196. (answer.extended[0].unsigned_int > tick2)) {
  197. return false;
  198. }
  199. }
  200. if (answer.extended[1].unsigned_int != cookie * 2) {
  201. return false;
  202. }
  203. } else if (2 == version) {
  204. uint32_t cookie = 717111;
  205. InOutCountedBuffer counted_buffer(&cookie, sizeof(cookie));
  206. ResultCode code = CrossCall(ipc, IpcTag::PING2, counted_buffer, &answer);
  207. if (SBOX_ALL_OK != code) {
  208. return false;
  209. }
  210. if (cookie != 717111 * 3) {
  211. return false;
  212. }
  213. } else {
  214. return false;
  215. }
  216. return true;
  217. }
  218. ProcessState::ProcessState()
  219. : process_state_(ProcessStateInternal::NONE), csrss_connected_(true) {}
  220. bool ProcessState::InitCalled() const {
  221. return process_state_ >= ProcessStateInternal::INIT_CALLED;
  222. }
  223. bool ProcessState::RevertedToSelf() const {
  224. return process_state_ >= ProcessStateInternal::REVERTED_TO_SELF;
  225. }
  226. bool ProcessState::IsCsrssConnected() const {
  227. return csrss_connected_;
  228. }
  229. void ProcessState::SetInitCalled() {
  230. if (process_state_ < ProcessStateInternal::INIT_CALLED)
  231. process_state_ = ProcessStateInternal::INIT_CALLED;
  232. }
  233. void ProcessState::SetRevertedToSelf() {
  234. if (process_state_ < ProcessStateInternal::REVERTED_TO_SELF)
  235. process_state_ = ProcessStateInternal::REVERTED_TO_SELF;
  236. }
  237. void ProcessState::SetCsrssConnected(bool csrss_connected) {
  238. csrss_connected_ = csrss_connected;
  239. }
  240. } // namespace sandbox