tor-browser

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

08_add_back_SANDBOX_EXPORTS.patch (12008B)


      1 # HG changeset patch
      2 # User Bob Owen <bobowencode@gmail.com>
      3 # Date 1730277955 0
      4 #      Wed Oct 30 08:45:55 2024 +0000
      5 Add back SANDBOX_EXPORTS because we still currently need this for plugin-container.exe
      6 
      7 diff --git a/sandbox/win/src/interception.cc b/sandbox/win/src/interception.cc
      8 --- a/sandbox/win/src/interception.cc
      9 +++ b/sandbox/win/src/interception.cc
     10 @@ -351,16 +351,26 @@ bool InterceptionManager::IsInterception
     11 }
     12 
     13 ResultCode InterceptionManager::PatchNtdll(bool hot_patch_needed) {
     14   // Maybe there is nothing to do
     15   if (!hot_patch_needed && interceptions_.empty())
     16     return SBOX_ALL_OK;
     17 
     18   if (hot_patch_needed) {
     19 +#if defined(SANDBOX_EXPORTS)
     20 +// Make sure the functions are not excluded by the linker.
     21 +#if defined(_WIN64)
     22 +#pragma comment(linker, "/include:TargetNtMapViewOfSection64")
     23 +#pragma comment(linker, "/include:TargetNtUnmapViewOfSection64")
     24 +#else
     25 +#pragma comment(linker, "/include:_TargetNtMapViewOfSection@44")
     26 +#pragma comment(linker, "/include:_TargetNtUnmapViewOfSection@12")
     27 +#endif
     28 +#endif  // defined(SANDBOX_EXPORTS)
     29     ADD_NT_INTERCEPTION(NtMapViewOfSection, MAP_VIEW_OF_SECTION_ID, 44);
     30     ADD_NT_INTERCEPTION(NtUnmapViewOfSection, UNMAP_VIEW_OF_SECTION_ID, 12);
     31   }
     32 
     33   // Reserve a full 64k memory range in the child process.
     34   HANDLE child = child_->Process();
     35   BYTE* thunk_base = reinterpret_cast<BYTE*>(::VirtualAllocEx(
     36       child, nullptr, kAllocGranularity, MEM_RESERVE, PAGE_NOACCESS));
     37 @@ -422,28 +432,53 @@ ResultCode InterceptionManager::PatchCli
     38     DllInterceptionData* dll_data) {
     39   DCHECK(thunks);
     40   DCHECK(dll_data);
     41 
     42   HMODULE ntdll_base = ::GetModuleHandle(kNtdllName);
     43   if (!ntdll_base)
     44     return SBOX_ERROR_NO_HANDLE;
     45 
     46 +  char* interceptor_base = nullptr;
     47 +
     48 +#if defined(SANDBOX_EXPORTS)
     49 +  interceptor_base = reinterpret_cast<char*>(child_->MainModule());
     50 +  base::ScopedNativeLibrary local_interceptor(::LoadLibrary(child_->Name()));
     51 +#endif  // defined(SANDBOX_EXPORTS)
     52 +
     53   ServiceResolverThunk thunk(child_->Process(), /*relaxed=*/true);
     54 
     55   for (auto interception : interceptions_) {
     56     const std::wstring ntdll(kNtdllName);
     57     if (interception.dll != ntdll)
     58       return SBOX_ERROR_BAD_PARAMS;
     59 
     60     if (INTERCEPTION_SERVICE_CALL != interception.type)
     61       return SBOX_ERROR_BAD_PARAMS;
     62 
     63 +#if defined(SANDBOX_EXPORTS)
     64 +    // We may be trying to patch by function name.
     65 +    if (!interception.interceptor_address) {
     66 +      const char* address;
     67 +      NTSTATUS ret = thunk.ResolveInterceptor(
     68 +          local_interceptor.get(), interception.interceptor.c_str(),
     69 +          reinterpret_cast<const void**>(&address));
     70 +      if (!NT_SUCCESS(ret)) {
     71 +        ::SetLastError(GetLastErrorFromNtStatus(ret));
     72 +        return SBOX_ERROR_CANNOT_RESOLVE_INTERCEPTION_THUNK;
     73 +      }
     74 +
     75 +      // Translate the local address to an address on the child.
     76 +      interception.interceptor_address =
     77 +          interceptor_base +
     78 +          (address - reinterpret_cast<char*>(local_interceptor.get()));
     79 +    }
     80 +#endif  // defined(SANDBOX_EXPORTS)
     81     NTSTATUS ret = thunk.Setup(
     82 -        ntdll_base, nullptr, interception.function.c_str(),
     83 +        ntdll_base, interceptor_base, interception.function.c_str(),
     84         interception.interceptor.c_str(), interception.interceptor_address,
     85         &thunks->thunks[dll_data->num_thunks],
     86         thunk_bytes - dll_data->used_bytes, nullptr);
     87     if (!NT_SUCCESS(ret)) {
     88       ::SetLastError(GetLastErrorFromNtStatus(ret));
     89       return SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_THUNK;
     90     }
     91 
     92 diff --git a/sandbox/win/src/interception.h b/sandbox/win/src/interception.h
     93 --- a/sandbox/win/src/interception.h
     94 +++ b/sandbox/win/src/interception.h
     95 @@ -218,16 +218,42 @@ class InterceptionManager {
     96 };
     97 
     98 // This macro simply calls interception_manager.AddToPatchedFunctions with
     99 // the given service to intercept (INTERCEPTION_SERVICE_CALL), and assumes that
    100 // the interceptor is called "TargetXXX", where XXX is the name of the service.
    101 // Note that num_params is the number of bytes to pop out of the stack for
    102 // the exported interceptor, following the calling convention of a service call
    103 // (WINAPI = with the "C" underscore).
    104 +#if SANDBOX_EXPORTS
    105 +#if defined(_WIN64)
    106 +#define MAKE_SERVICE_NAME(service, params) "Target" #service "64"
    107 +#else
    108 +#define MAKE_SERVICE_NAME(service, params) "_Target" #service "@" #params
    109 +#endif
    110 +
    111 +#define ADD_NT_INTERCEPTION(service, id, num_params)        \
    112 +  AddToPatchedFunctions(kNtdllName, #service,               \
    113 +                        sandbox::INTERCEPTION_SERVICE_CALL, \
    114 +                        MAKE_SERVICE_NAME(service, num_params), id)
    115 +
    116 +#define INTERCEPT_NT(manager, service, id, num_params)                        \
    117 +  ((&Target##service) ? manager->ADD_NT_INTERCEPTION(service, id, num_params) \
    118 +                      : false)
    119 +
    120 +// When intercepting the EAT it is important that the patched version of the
    121 +// function not call any functions imported from system libraries unless
    122 +// |TargetServices::InitCalled()| returns true, because it is only then that
    123 +// we are guaranteed that our IAT has been initialized.
    124 +#define INTERCEPT_EAT(manager, dll, function, id, num_params)             \
    125 +  ((&Target##function) ? manager->AddToPatchedFunctions(                  \
    126 +                             dll, #function, sandbox::INTERCEPTION_EAT,   \
    127 +                             MAKE_SERVICE_NAME(function, num_params), id) \
    128 +                       : false)
    129 +#else  // SANDBOX_EXPORTS
    130 #if defined(_WIN64)
    131 #define MAKE_SERVICE_NAME(service) &Target##service##64
    132 #else
    133 #define MAKE_SERVICE_NAME(service) &Target##service
    134 #endif
    135 
    136 #define ADD_NT_INTERCEPTION(service, id, num_params)            \
    137   AddToPatchedFunctions(                                        \
    138 @@ -240,12 +266,13 @@ class InterceptionManager {
    139 // When intercepting the EAT it is important that the patched version of the
    140 // function not call any functions imported from system libraries unless
    141 // |TargetServices::InitCalled()| returns true, because it is only then that
    142 // we are guaranteed that our IAT has been initialized.
    143 #define INTERCEPT_EAT(manager, dll, function, id, num_params) \
    144   manager->AddToPatchedFunctions(                             \
    145       dll, #function, sandbox::INTERCEPTION_EAT,              \
    146       reinterpret_cast<void*>(MAKE_SERVICE_NAME(function)), id)
    147 +#endif  // SANDBOX_EXPORTS
    148 
    149 }  // namespace sandbox
    150 
    151 #endif  // SANDBOX_WIN_SRC_INTERCEPTION_H_
    152 diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h
    153 --- a/sandbox/win/src/sandbox_types.h
    154 +++ b/sandbox/win/src/sandbox_types.h
    155 @@ -197,17 +197,21 @@ class BrokerServices;
    156 class TargetServices;
    157 
    158 // Contains the pointer to a target or broker service.
    159 struct SandboxInterfaceInfo {
    160   raw_ptr<BrokerServices> broker_services;
    161   raw_ptr<TargetServices> target_services;
    162 };
    163 
    164 +#if SANDBOX_EXPORTS
    165 +#define SANDBOX_INTERCEPT extern "C" __declspec(dllexport)
    166 +#else
    167 #define SANDBOX_INTERCEPT extern "C"
    168 +#endif
    169 
    170 enum InterceptionType {
    171   INTERCEPTION_INVALID = 0,
    172   INTERCEPTION_SERVICE_CALL,  // Trampoline of an NT native call
    173   INTERCEPTION_EAT,
    174   INTERCEPTION_UNLOAD_MODULE,  // Unload the module (don't patch)
    175   INTERCEPTION_LAST            // Placeholder for last item in the enumeration
    176 };
    177 diff --git a/sandbox/win/src/target_process.cc b/sandbox/win/src/target_process.cc
    178 --- a/sandbox/win/src/target_process.cc
    179 +++ b/sandbox/win/src/target_process.cc
    180 @@ -215,35 +215,60 @@ ResultCode TargetProcess::Create(
    181   base_address_ = GetProcessBaseAddress(process_info.process_handle());
    182   DCHECK(base_address_);
    183   if (!base_address_) {
    184     *win_error = ::GetLastError();
    185     ::TerminateProcess(process_info.process_handle(), 0);
    186     return SBOX_ERROR_CANNOT_FIND_BASE_ADDRESS;
    187   }
    188 
    189 +#if !defined(SANDBOX_EXPORTS)
    190   if (base_address_ != CURRENT_MODULE()) {
    191     ::TerminateProcess(process_info.process_handle(), 0);
    192     return SBOX_ERROR_INVALID_TARGET_BASE_ADDRESS;
    193   }
    194 +#endif
    195 
    196   sandbox_process_info_.Set(process_info.Take());
    197   return SBOX_ALL_OK;
    198 }
    199 
    200 +void* TargetProcess::GetChildAddress(const char* name, const void* address) {
    201 +#if SANDBOX_EXPORTS
    202 +  HMODULE module = ::LoadLibrary(exe_name_.get());
    203 +  if (!module) return nullptr;
    204 +
    205 +  void* child_addr = reinterpret_cast<void*>(::GetProcAddress(module, name));
    206 +  if (!child_addr) {
    207 +    return nullptr;
    208 +  }
    209 +
    210 +  size_t offset =
    211 +      reinterpret_cast<char*>(child_addr) - reinterpret_cast<char*>(module);
    212 +  ::FreeLibrary(module);
    213 +  return reinterpret_cast<char*>(MainModule()) + offset;
    214 +#else
    215 +  return const_cast<void*>(address);
    216 +#endif
    217 +}
    218 +
    219 ResultCode TargetProcess::TransferVariable(const char* name,
    220                                            const void* address,
    221                                            size_t size) {
    222   if (!sandbox_process_info_.IsValid())
    223     return SBOX_ERROR_UNEXPECTED_CALL;
    224 
    225 +  void* child_var = GetChildAddress(name, address);
    226 +  if (!child_var) {
    227 +    return SBOX_ERROR_CANNOT_FIND_VARIABLE_ADDRESS;
    228 +  }
    229 +
    230   SIZE_T written;
    231 -  if (!::WriteProcessMemory(sandbox_process_info_.process_handle(),
    232 -                            const_cast<void*>(address), address, size,
    233 -                            &written)) {
    234 +  if (!::WriteProcessMemory(sandbox_process_info_.process_handle(), child_var,
    235 +                            address, size, &written)) {
    236     return SBOX_ERROR_CANNOT_WRITE_VARIABLE_VALUE;
    237   }
    238   if (written != size)
    239     return SBOX_ERROR_INVALID_WRITE_VARIABLE_SIZE;
    240 
    241   return SBOX_ALL_OK;
    242 }
    243 
    244 @@ -379,29 +404,30 @@ void TargetProcess::Terminate() {
    245   ::TerminateProcess(sandbox_process_info_.process_handle(), 0);
    246 }
    247 
    248 ResultCode TargetProcess::VerifySentinels() {
    249   if (!sandbox_process_info_.IsValid())
    250     return SBOX_ERROR_UNEXPECTED_CALL;
    251   DWORD value = 0;
    252   SIZE_T read;
    253 -
    254 +  void* sentinel_start =
    255 +      GetChildAddress("g_sentinel_value_start", &g_sentinel_value_start);
    256   if (!::ReadProcessMemory(sandbox_process_info_.process_handle(),
    257 -                           &g_sentinel_value_start, &value, sizeof(DWORD),
    258 -                           &read)) {
    259 +                           sentinel_start, &value, sizeof(DWORD), &read)) {
    260     return SBOX_ERROR_CANNOT_READ_SENTINEL_VALUE;
    261   }
    262   if (read != sizeof(DWORD))
    263     return SBOX_ERROR_INVALID_READ_SENTINEL_SIZE;
    264   if (value != g_sentinel_value_start)
    265     return SBOX_ERROR_MISMATCH_SENTINEL_VALUE;
    266 -  if (!::ReadProcessMemory(sandbox_process_info_.process_handle(),
    267 -                           &g_sentinel_value_end, &value, sizeof(DWORD),
    268 -                           &read)) {
    269 +  void* sentinel_end =
    270 +      GetChildAddress("g_sentinel_value_end", &g_sentinel_value_end);
    271 +  if (!::ReadProcessMemory(sandbox_process_info_.process_handle(), sentinel_end,
    272 +                           &value, sizeof(DWORD), &read)) {
    273     return SBOX_ERROR_CANNOT_READ_SENTINEL_VALUE;
    274   }
    275   if (read != sizeof(DWORD))
    276     return SBOX_ERROR_INVALID_READ_SENTINEL_SIZE;
    277   if (value != g_sentinel_value_end)
    278     return SBOX_ERROR_MISMATCH_SENTINEL_VALUE;
    279 
    280   return SBOX_ALL_OK;
    281 diff --git a/sandbox/win/src/target_process.h b/sandbox/win/src/target_process.h
    282 --- a/sandbox/win/src/target_process.h
    283 +++ b/sandbox/win/src/target_process.h
    284 @@ -88,16 +88,20 @@ class TargetProcess {
    285 
    286   // Creates a mock TargetProcess used for testing interceptions.
    287   static std::unique_ptr<TargetProcess> MakeTargetProcessForTesting(
    288       HANDLE process,
    289       HMODULE base_address);
    290 
    291  private:
    292   FRIEND_TEST_ALL_PREFIXES(TargetProcessTest, FilterEnvironment);
    293 +
    294 +  // Get the address in the child for a given variable name.
    295 +  void* GetChildAddress(const char* name, const void* address);
    296 +
    297   // Verify the target process looks the same as the broker process.
    298   ResultCode VerifySentinels();
    299 
    300   // Filters an environment to only include those that have an entry in
    301   // `to_keep`.
    302   static std::wstring FilterEnvironment(
    303       const wchar_t* env,
    304       const base::span<const base::WStringPiece> to_keep);