tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SandboxInitialization.cpp (7331B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "SandboxInitialization.h"
      8 
      9 #include "base/memory/ref_counted.h"
     10 #include "nsWindowsDllInterceptor.h"
     11 #include "sandbox/win/src/process_mitigations.h"
     12 #include "sandbox/win/src/sandbox_factory.h"
     13 #include "mozilla/DebugOnly.h"
     14 #include "mozilla/WindowsProcessMitigations.h"
     15 
     16 namespace mozilla {
     17 namespace sandboxing {
     18 
     19 typedef BOOL(WINAPI* CloseHandle_func)(HANDLE hObject);
     20 static WindowsDllInterceptor::FuncHookType<CloseHandle_func> stub_CloseHandle;
     21 
     22 typedef BOOL(WINAPI* DuplicateHandle_func)(
     23    HANDLE hSourceProcessHandle, HANDLE hSourceHandle,
     24    HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess,
     25    BOOL bInheritHandle, DWORD dwOptions);
     26 static WindowsDllInterceptor::FuncHookType<DuplicateHandle_func>
     27    stub_DuplicateHandle;
     28 
     29 static BOOL WINAPI patched_CloseHandle(HANDLE hObject) {
     30  // Check all handles being closed against the sandbox's tracked handles.
     31  base::win::OnHandleBeingClosed(hObject,
     32                                 base::win::HandleOperation::kCloseHandleHook);
     33  return stub_CloseHandle(hObject);
     34 }
     35 
     36 static BOOL WINAPI patched_DuplicateHandle(
     37    HANDLE hSourceProcessHandle, HANDLE hSourceHandle,
     38    HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess,
     39    BOOL bInheritHandle, DWORD dwOptions) {
     40  // If closing a source handle from our process check it against the sandbox's
     41  // tracked handles.
     42  if ((dwOptions & DUPLICATE_CLOSE_SOURCE) &&
     43      (GetProcessId(hSourceProcessHandle) == ::GetCurrentProcessId())) {
     44    base::win::OnHandleBeingClosed(
     45        hSourceHandle, base::win::HandleOperation::kDuplicateHandleHook);
     46  }
     47 
     48  return stub_DuplicateHandle(hSourceProcessHandle, hSourceHandle,
     49                              hTargetProcessHandle, lpTargetHandle,
     50                              dwDesiredAccess, bInheritHandle, dwOptions);
     51 }
     52 
     53 typedef BOOL(WINAPI* ApiSetQueryApiSetPresence_func)(PCUNICODE_STRING,
     54                                                     PBOOLEAN);
     55 static WindowsDllInterceptor::FuncHookType<ApiSetQueryApiSetPresence_func>
     56    stub_ApiSetQueryApiSetPresence;
     57 
     58 static const WCHAR gApiSetNtUserWindowStation[] =
     59    L"ext-ms-win-ntuser-windowstation-l1-1-0";
     60 
     61 static BOOL WINAPI patched_ApiSetQueryApiSetPresence(
     62    PCUNICODE_STRING aNamespace, PBOOLEAN aPresent) {
     63  if (aNamespace && aPresent &&
     64      !wcsncmp(aNamespace->Buffer, gApiSetNtUserWindowStation,
     65               aNamespace->Length / sizeof(WCHAR))) {
     66    *aPresent = FALSE;
     67    return TRUE;
     68  }
     69 
     70  return stub_ApiSetQueryApiSetPresence(aNamespace, aPresent);
     71 }
     72 
     73 MOZ_RUNINIT static WindowsDllInterceptor Kernel32Intercept;
     74 MOZ_RUNINIT static WindowsDllInterceptor gApiQueryIntercept;
     75 
     76 static bool EnableHandleCloseMonitoring() {
     77  Kernel32Intercept.Init("kernel32.dll");
     78  bool hooked = stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle",
     79                                     &patched_CloseHandle);
     80  if (!hooked) {
     81    return false;
     82  }
     83 
     84  hooked = stub_DuplicateHandle.Set(Kernel32Intercept, "DuplicateHandle",
     85                                    &patched_DuplicateHandle);
     86  if (!hooked) {
     87    return false;
     88  }
     89 
     90  return true;
     91 }
     92 
     93 /**
     94 * There is a bug in COM that causes its initialization to fail when user32.dll
     95 * is loaded but Win32k lockdown is enabled. COM uses ApiSetQueryApiSetPresence
     96 * to make this check. When we are under Win32k lockdown, we hook
     97 * ApiSetQueryApiSetPresence and force it to tell the caller that the DLL of
     98 * interest is not present.
     99 */
    100 static void EnableApiQueryInterception() {
    101  if (!IsWin32kLockedDown()) {
    102    return;
    103  }
    104 
    105  gApiQueryIntercept.Init(L"Api-ms-win-core-apiquery-l1-1-0.dll");
    106  DebugOnly<bool> hookSetOk = stub_ApiSetQueryApiSetPresence.Set(
    107      gApiQueryIntercept, "ApiSetQueryApiSetPresence",
    108      &patched_ApiSetQueryApiSetPresence);
    109  MOZ_ASSERT(hookSetOk);
    110 }
    111 
    112 static bool ShouldDisableHandleVerifier() {
    113 #if defined(_X86_) && (defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG))
    114  // Chromium only has the verifier enabled for 32-bit and our close monitoring
    115  // hooks cause debug assertions for 64-bit anyway.
    116  // For x86 keep the verifier enabled by default only for Nightly or debug.
    117  // The handle verifier uses thread local storage, which at least one gtest
    118  // manipulates causing it to crash, so we have to disable.
    119  return !!getenv("MOZ_RUN_GTEST");
    120 #else
    121  return !getenv("MOZ_ENABLE_HANDLE_VERIFIER");
    122 #endif
    123 }
    124 
    125 static void InitializeHandleVerifier() {
    126  // Disable the handle verifier if we don't want it or can't enable the close
    127  // monitoring hooks.
    128  if (ShouldDisableHandleVerifier() || !EnableHandleCloseMonitoring()) {
    129    base::win::DisableHandleVerifier();
    130  }
    131 }
    132 
    133 static sandbox::TargetServices* InitializeTargetServices() {
    134  // This might disable the verifier, so we want to do it before it is used.
    135  InitializeHandleVerifier();
    136 
    137  EnableApiQueryInterception();
    138 
    139  sandbox::TargetServices* targetServices =
    140      sandbox::SandboxFactory::GetTargetServices();
    141  if (!targetServices) {
    142    return nullptr;
    143  }
    144 
    145  if (targetServices->Init() != sandbox::SBOX_ALL_OK) {
    146    return nullptr;
    147  }
    148 
    149  return targetServices;
    150 }
    151 
    152 sandbox::TargetServices* GetInitializedTargetServices() {
    153  static sandbox::TargetServices* sInitializedTargetServices =
    154      InitializeTargetServices();
    155 
    156  return sInitializedTargetServices;
    157 }
    158 
    159 void LowerSandbox() { GetInitializedTargetServices()->LowerToken(); }
    160 
    161 static sandbox::BrokerServices* InitializeBrokerServices() {
    162  // This might disable the verifier, so we want to do it before it is used.
    163  InitializeHandleVerifier();
    164 
    165  sandbox::BrokerServices* brokerServices =
    166      sandbox::SandboxFactory::GetBrokerServices();
    167  if (!brokerServices) {
    168    return nullptr;
    169  }
    170 
    171  if (brokerServices->Init() != sandbox::SBOX_ALL_OK) {
    172    return nullptr;
    173  }
    174 
    175  // Comment below copied from Chromium code.
    176  // Precreate the desktop and window station used by the renderers.
    177  // IMPORTANT: This piece of code needs to run as early as possible in the
    178  // process because it will initialize the sandbox broker, which requires
    179  // the process to swap its window station. During this time all the UI
    180  // will be broken. This has to run before threads and windows are created.
    181  (void)brokerServices->CreateAlternateDesktop(
    182      sandbox::Desktop::kAlternateWinstation);
    183 
    184  // Ensure the relevant mitigations are enforced.
    185  mozilla::sandboxing::ApplyParentProcessMitigations();
    186 
    187  return brokerServices;
    188 }
    189 
    190 sandbox::BrokerServices* GetInitializedBrokerServices() {
    191  static sandbox::BrokerServices* sInitializedBrokerServices =
    192      InitializeBrokerServices();
    193 
    194  return sInitializedBrokerServices;
    195 }
    196 
    197 void ApplyParentProcessMitigations() {
    198  // The main reason for this call is for the token hardening, but chromium code
    199  // also ensures DEP without ATL thunk so we do the same.
    200  sandbox::RatchetDownSecurityMitigations(
    201      sandbox::MITIGATION_DEP | sandbox::MITIGATION_DEP_NO_ATL_THUNK |
    202      sandbox::MITIGATION_HARDEN_TOKEN_IL_POLICY);
    203 }
    204 
    205 }  // namespace sandboxing
    206 }  // namespace mozilla