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);