26_broker_complex_line_breaks.patch (19372B)
1 # HG changeset patch 2 # User Bob Owen <bobowencode@gmail.com> 3 # Date 1632737723 -3600 4 # Mon Sep 27 11:15:23 2021 +0100 5 # Node ID 096696bc1648dbacdfab881c4ed8fe770ebe58b1 6 # Parent 254b1fc8768f67d208af199135276abae9aabc0c 7 Bug 1713973 p2: Add Uniscribe Line Breaking via chromium-sandbox IPC. r=toshi!,r=jfkthame! 8 9 This adds a new cross call using the chromium shared memory IPC to proxy use of 10 the Uniscribe line breaker, because it cannot be used in the content process 11 with win32k lockdown enabled. 12 13 If the text being processed is too long to fit into the IPC params then it is 14 processed in chunks. 15 16 This change implements an INPTR_TYPE in the sandbox, which appears to have 17 been removed at some point. 18 It also fixes a bug in OpcodeFactory::MakeOpAction, so that a null param is 19 passed and we can use an empty parameter set. 20 21 New files are in chromium-shim as these are most likely to require changes and 22 this means we will not have to update the main chromium patch. 23 24 diff --git a/sandbox/win/src/crosscall_client.h b/sandbox/win/src/crosscall_client.h 25 --- a/sandbox/win/src/crosscall_client.h 26 +++ b/sandbox/win/src/crosscall_client.h 27 @@ -39,20 +39,16 @@ 28 // interpretation of the answer is private to client and server. 29 // 30 // The return value is ALL_OK if the IPC was delivered to the server, other 31 // return codes indicate that the IPC transport failed to deliver it. 32 namespace sandbox { 33 34 enum class IpcTag; 35 36 -// this is the assumed channel size. This can be overridden in a given 37 -// IPC implementation. 38 -const uint32_t kIPCChannelSize = 1024; 39 - 40 // The copy helper uses templates to deduce the appropriate copy function to 41 // copy the input parameters in the buffer that is going to be send across the 42 // IPC. These template facility can be made more sophisticated as need arises. 43 44 // The default copy helper. It catches the general case where no other 45 // specialized template matches better. We set the type to UINT32_TYPE, so this 46 // only works with objects whose size is 32 bits. 47 template <typename T> 48 @@ -207,16 +203,42 @@ class CopyHelper<const wchar_t[n]> : pub 49 // parameters. 50 class InOutCountedBuffer : public CountedBuffer { 51 public: 52 InOutCountedBuffer(void* buffer, uint32_t size) 53 : CountedBuffer(buffer, size) {} 54 }; 55 56 // This copy helper template specialization catches the cases where the 57 +// parameter is a an input buffer. 58 +template <> 59 +class CopyHelper<CountedBuffer> { 60 + public: 61 + CopyHelper(const CountedBuffer t) : t_(t) {} 62 + 63 + // Returns the pointer to the start of the string. 64 + const void* GetStart() const { return t_.Buffer(); } 65 + 66 + // Update not required so just return true; 67 + bool Update(void* buffer) { return true; } 68 + 69 + // Returns the size of the string in bytes. We define a nullptr string to 70 + // be of zero length. 71 + uint32_t GetSize() const { return t_.Size(); } 72 + 73 + // Returns true if the current type is used as an In or InOut parameter. 74 + bool IsInOut() { return false; } 75 + 76 + ArgType GetType() { return INPTR_TYPE; } 77 + 78 + private: 79 + const CountedBuffer t_; 80 +}; 81 + 82 +// This copy helper template specialization catches the cases where the 83 // parameter is a an input/output buffer. 84 template <> 85 class CopyHelper<InOutCountedBuffer> { 86 public: 87 explicit CopyHelper(const InOutCountedBuffer t) : t_(t) {} 88 89 // Returns the pointer to the start of the string. 90 const void* GetStart() const { return t_.Buffer(); } 91 diff --git a/sandbox/win/src/crosscall_params.h b/sandbox/win/src/crosscall_params.h 92 --- a/sandbox/win/src/crosscall_params.h 93 +++ b/sandbox/win/src/crosscall_params.h 94 @@ -41,16 +41,20 @@ 95 // them are not supported. 96 // 97 // Another limitation of CrossCall is that the return value and output 98 // parameters can only be uint32_t integers. Returning complex structures or 99 // strings is not supported. 100 101 namespace sandbox { 102 103 +// this is the assumed channel size. This can be overridden in a given 104 +// IPC implementation. 105 +const uint32_t kIPCChannelSize = 1024; 106 + 107 // This is the list of all imported symbols from ntdll.dll. 108 SANDBOX_INTERCEPT NtExports g_nt; 109 110 namespace { 111 112 // Increases |value| until there is no need for padding given an int64_t 113 // alignment. Returns the increased value. 114 inline uint32_t Align(uint32_t value) { 115 @@ -216,16 +220,21 @@ class ActualCallParams : public CrossCal 116 : CrossCallParams(tag, number_params) { 117 param_info_[0].offset_ = 118 static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this)); 119 } 120 121 ActualCallParams(const ActualCallParams&) = delete; 122 ActualCallParams& operator=(const ActualCallParams&) = delete; 123 124 + static constexpr size_t MaxParamsSize() { 125 + return sizeof( 126 + ActualCallParams<NUMBER_PARAMS, kIPCChannelSize>::parameters_); 127 + } 128 + 129 // Testing-only method. Allows setting the apparent size to a wrong value. 130 // returns the previous size. 131 uint32_t OverrideSize(uint32_t new_size) { 132 uint32_t previous_size = param_info_[NUMBER_PARAMS].offset_; 133 param_info_[NUMBER_PARAMS].offset_ = new_size; 134 return previous_size; 135 } 136 137 diff --git a/sandbox/win/src/crosscall_server.cc b/sandbox/win/src/crosscall_server.cc 138 --- a/sandbox/win/src/crosscall_server.cc 139 +++ b/sandbox/win/src/crosscall_server.cc 140 @@ -301,17 +301,17 @@ bool CrossCallParamsEx::GetParameterStr( 141 142 bool CrossCallParamsEx::GetParameterPtr(uint32_t index, 143 uint32_t expected_size, 144 void** pointer) { 145 uint32_t size = 0; 146 ArgType type; 147 void* start = GetRawParameter(index, &size, &type); 148 149 - if ((size != expected_size) || (INOUTPTR_TYPE != type)) 150 + if ((size != expected_size) || (INOUTPTR_TYPE != type && INPTR_TYPE != type)) 151 return false; 152 153 if (!start) 154 return false; 155 156 *pointer = start; 157 return true; 158 } 159 diff --git a/sandbox/win/src/ipc_args.cc b/sandbox/win/src/ipc_args.cc 160 --- a/sandbox/win/src/ipc_args.cc 161 +++ b/sandbox/win/src/ipc_args.cc 162 @@ -15,16 +15,17 @@ namespace sandbox { 163 void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]) { 164 for (size_t i = 0; i < kMaxIpcParams; i++) { 165 switch (ipc_params->args[i]) { 166 case WCHAR_TYPE: { 167 delete reinterpret_cast<std::wstring*>(args[i]); 168 args[i] = nullptr; 169 break; 170 } 171 + case INPTR_TYPE: 172 case INOUTPTR_TYPE: { 173 delete reinterpret_cast<CountedBuffer*>(args[i]); 174 args[i] = nullptr; 175 break; 176 } 177 default: 178 break; 179 } 180 @@ -69,16 +70,17 @@ bool GetArgs(CrossCallParamsEx* params, 181 void* data; 182 if (!params->GetParameterVoidPtr(i, &data)) { 183 ReleaseArgs(ipc_params, args); 184 return false; 185 } 186 args[i] = data; 187 break; 188 } 189 + case INPTR_TYPE: 190 case INOUTPTR_TYPE: { 191 if (!args[i]) { 192 ReleaseArgs(ipc_params, args); 193 return false; 194 } 195 CountedBuffer* buffer = new CountedBuffer(args[i], size); 196 args[i] = buffer; 197 break; 198 diff --git a/sandbox/win/src/ipc_tags.h b/sandbox/win/src/ipc_tags.h 199 --- a/sandbox/win/src/ipc_tags.h 200 +++ b/sandbox/win/src/ipc_tags.h 201 @@ -41,16 +41,17 @@ enum class IpcTag { 202 NTQUERYFULLATTRIBUTESFILE, 203 NTSETINFO_RENAME, 204 NTOPENTHREAD, 205 NTOPENPROCESSTOKENEX, 206 GDI_GDIDLLINITIALIZE, 207 GDI_GETSTOCKOBJECT, 208 USER_REGISTERCLASSW, 209 CREATETHREAD, 210 + GETCOMPLEXLINEBREAKS, 211 NTCREATESECTION, 212 LAST 213 }; 214 215 constexpr size_t kMaxServiceCount = 64; 216 constexpr size_t kMaxIpcTag = static_cast<size_t>(IpcTag::LAST); 217 static_assert(kMaxIpcTag <= kMaxServiceCount, "kMaxServiceCount is too low"); 218 219 diff --git a/sandbox/win/src/policy_engine_opcodes.cc b/sandbox/win/src/policy_engine_opcodes.cc 220 --- a/sandbox/win/src/policy_engine_opcodes.cc 221 +++ b/sandbox/win/src/policy_engine_opcodes.cc 222 @@ -78,17 +78,17 @@ EvalResult OpcodeEval<OP_ALWAYS_TRUE>(Po 223 } 224 225 ////////////////////////////////////////////////////////////////////////////// 226 // Opcode OpAction: 227 // Does not require input parameter. 228 // Argument 0 contains the actual action to return. 229 230 PolicyOpcode* OpcodeFactory::MakeOpAction(EvalResult action, uint32_t options) { 231 - PolicyOpcode* opcode = MakeBase(OP_ACTION, options, 0); 232 + PolicyOpcode* opcode = MakeBase(OP_ACTION, options); 233 if (!opcode) 234 return nullptr; 235 opcode->SetArgument(0, action); 236 return opcode; 237 } 238 239 template <> 240 EvalResult OpcodeEval<OP_ACTION>(PolicyOpcode* opcode, 241 diff --git a/sandbox/win/src/policy_params.h b/sandbox/win/src/policy_params.h 242 --- a/sandbox/win/src/policy_params.h 243 +++ b/sandbox/win/src/policy_params.h 244 @@ -43,11 +43,15 @@ POLPARAMS_BEGIN(OpenKey) 245 POLPARAMS_END(OpenKey) 246 247 // Policy parameter for name-based policies. 248 POLPARAMS_BEGIN(HandleTarget) 249 POLPARAM(NAME) 250 POLPARAM(TARGET) 251 POLPARAMS_END(HandleTarget) 252 253 +// Policy parameters where no parameter based checks are done. 254 +POLPARAMS_BEGIN(EmptyParams) 255 +POLPARAMS_END(EmptyParams) 256 + 257 } // namespace sandbox 258 259 #endif // SANDBOX_WIN_SRC_POLICY_PARAMS_H_ 260 diff --git a/sandbox/win/src/sandbox.h b/sandbox/win/src/sandbox.h 261 --- a/sandbox/win/src/sandbox.h 262 +++ b/sandbox/win/src/sandbox.h 263 @@ -154,16 +154,19 @@ class TargetServices { 264 // fails the current process could be terminated immediately. 265 virtual void LowerToken() = 0; 266 267 // Returns the ProcessState object. Through that object it's possible to have 268 // information about the current state of the process, such as whether 269 // LowerToken has been called or not. 270 virtual ProcessState* GetState() = 0; 271 272 + virtual ResultCode GetComplexLineBreaks(const WCHAR* text, uint32_t length, 273 + uint8_t* break_before) = 0; 274 + 275 protected: 276 ~TargetServices() {} 277 }; 278 279 class [[clang::lto_visibility_public]] PolicyInfo { 280 public: 281 // Returns a JSON representation of the policy snapshot. 282 // This pointer has the same lifetime as this PolicyInfo object. 283 diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h 284 --- a/sandbox/win/src/sandbox_policy.h 285 +++ b/sandbox/win/src/sandbox_policy.h 286 @@ -169,16 +169,19 @@ class TargetPolicy { 287 // Modules patching `pattern` (see AllowFileAccess) can still be loaded under 288 // Code-Integrity Guard (MITIGATION_FORCE_MS_SIGNED_BINS). 289 [[nodiscard]] virtual ResultCode AllowExtraDlls(const wchar_t* pattern) = 0; 290 291 // Adds a policy rule effective for processes spawned using this policy. 292 // Fake gdi init to allow user32 and gdi32 to initialize under Win32 Lockdown. 293 [[nodiscard]] virtual ResultCode SetFakeGdiInit() = 0; 294 295 + // Adds a policy rule to allow complex line break brokering. 296 + [[nodiscard]] virtual ResultCode AllowLineBreaking() = 0; 297 + 298 // Adds a dll that will be unloaded in the target process before it gets 299 // a chance to initialize itself. Typically, dlls that cause the target 300 // to crash go here. 301 virtual void AddDllToUnload(const wchar_t* dll_name) = 0; 302 303 // Sets the integrity level of the process in the sandbox. Both the initial 304 // token and the main token will be affected by this. If the integrity level 305 // is set to a level higher than the current level, the sandbox will fail 306 diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc 307 --- a/sandbox/win/src/sandbox_policy_base.cc 308 +++ b/sandbox/win/src/sandbox_policy_base.cc 309 @@ -26,16 +26,17 @@ 310 #include "base/win/win_util.h" 311 #include "base/win/windows_version.h" 312 #include "sandbox/features.h" 313 #include "sandbox/win/src/acl.h" 314 #include "sandbox/win/src/crosscall_server.h" 315 #include "sandbox/win/src/filesystem_policy.h" 316 #include "sandbox/win/src/interception.h" 317 #include "sandbox/win/src/job.h" 318 +#include "sandbox/win/src/line_break_policy.h" 319 #include "sandbox/win/src/named_pipe_policy.h" 320 #include "sandbox/win/src/policy_broker.h" 321 #include "sandbox/win/src/policy_engine_processor.h" 322 #include "sandbox/win/src/policy_low_level.h" 323 #include "sandbox/win/src/process_mitigations.h" 324 #include "sandbox/win/src/process_mitigations_win32k_policy.h" 325 #include "sandbox/win/src/process_thread_policy.h" 326 #include "sandbox/win/src/restricted_token_utils.h" 327 @@ -281,16 +281,24 @@ ResultCode PolicyBase::AddRuleInternal(S 328 if (!SignedPolicy::GenerateRules(pattern, PolicyMaker())) { 329 NOTREACHED(); 330 return SBOX_ERROR_BAD_PARAMS; 331 } 332 } 333 return SBOX_ALL_OK; 334 } 335 336 +ResultCode ConfigBase::AllowLineBreaking() { 337 + if (!LineBreakPolicy::GenerateRules(PolicyMaker())) { 338 + NOTREACHED(); 339 + return SBOX_ERROR_BAD_PARAMS; 340 + } 341 + return SBOX_ALL_OK; 342 +} 343 + 344 void ConfigBase::AddDllToUnload(const wchar_t* dll_name) { 345 blocklisted_dlls_.push_back(dll_name); 346 } 347 348 ResultCode ConfigBase::SetIntegrityLevel(IntegrityLevel integrity_level) { 349 if (app_container_) 350 return SBOX_ERROR_BAD_PARAMS; 351 integrity_level_ = integrity_level; 352 diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h 353 --- a/sandbox/win/src/sandbox_policy_base.h 354 +++ b/sandbox/win/src/sandbox_policy_base.h 355 @@ -63,16 +63,17 @@ class ConfigBase final : public TargetCo 356 ResultCode SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) override; 357 JobLevel GetJobLevel() const override; 358 void SetJobMemoryLimit(size_t memory_limit) override; 359 ResultCode AllowFileAccess(FileSemantics semantics, 360 const wchar_t* pattern) override; 361 ResultCode AllowNamedPipes(const wchar_t* pattern) override; 362 ResultCode AllowExtraDlls(const wchar_t* pattern) override; 363 ResultCode SetFakeGdiInit() override; 364 + ResultCode AllowLineBreaking() final; 365 void AddDllToUnload(const wchar_t* dll_name) override; 366 ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) override; 367 IntegrityLevel GetIntegrityLevel() const override; 368 void SetDelayedIntegrityLevel(IntegrityLevel integrity_level) override; 369 ResultCode SetLowBox(const wchar_t* sid) override; 370 ResultCode SetProcessMitigations(MitigationFlags flags) override; 371 MitigationFlags GetProcessMitigations() override; 372 ResultCode SetDelayedProcessMitigations(MitigationFlags flags) override; 373 diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc 374 --- a/sandbox/win/src/target_services.cc 375 +++ b/sandbox/win/src/target_services.cc 376 @@ -14,16 +14,17 @@ 377 378 #include <optional> 379 #include "base/containers/span.h" 380 #include "base/logging.h" 381 #include "base/win/access_token.h" 382 #include "sandbox/win/src/acl.h" 383 #include "sandbox/win/src/crosscall_client.h" 384 #include "sandbox/win/src/handle_closer_agent.h" 385 +#include "sandbox/win/src/line_break_interception.h" 386 #include "sandbox/win/src/heap_helper.h" 387 #include "sandbox/win/src/ipc_tags.h" 388 #include "sandbox/win/src/process_mitigations.h" 389 #include "sandbox/win/src/restricted_token_utils.h" 390 #include "sandbox/win/src/sandbox.h" 391 #include "sandbox/win/src/sandbox_nt_util.h" 392 #include "sandbox/win/src/sandbox_types.h" 393 #include "sandbox/win/src/sharedmem_ipc_client.h" 394 @@ -240,9 +241,15 @@ void ProcessState::SetRevertedToSelf() { 395 if (process_state_ < ProcessStateInternal::REVERTED_TO_SELF) 396 process_state_ = ProcessStateInternal::REVERTED_TO_SELF; 397 } 398 399 void ProcessState::SetCsrssConnected(bool csrss_connected) { 400 csrss_connected_ = csrss_connected; 401 } 402 403 +ResultCode TargetServicesBase::GetComplexLineBreaks(const WCHAR* text, 404 + uint32_t length, 405 + uint8_t* break_before) { 406 + return sandbox::GetComplexLineBreaksProxy(text, length, break_before); 407 +} 408 + 409 } // namespace sandbox 410 diff --git a/sandbox/win/src/target_services.h b/sandbox/win/src/target_services.h 411 --- a/sandbox/win/src/target_services.h 412 +++ b/sandbox/win/src/target_services.h 413 @@ -48,16 +48,18 @@ class TargetServicesBase : public Target 414 TargetServicesBase(const TargetServicesBase&) = delete; 415 TargetServicesBase& operator=(const TargetServicesBase&) = delete; 416 417 // Public interface of TargetServices. See comments in sandbox.h. 418 ResultCode Init() override; 419 absl::optional<base::span<const uint8_t>> GetDelegateData() override; 420 void LowerToken() override; 421 ProcessState* GetState() override; 422 + ResultCode GetComplexLineBreaks(const WCHAR* text, uint32_t length, 423 + uint8_t* break_before) final; 424 425 // Factory method. 426 static TargetServicesBase* GetInstance(); 427 428 // Sends a simple IPC Message that has a well-known answer. Returns true 429 // if the IPC was successful and false otherwise. There are 2 versions of 430 // this test: 1 and 2. The first one send a simple message while the 431 // second one send a message with an in/out param. 432 diff --git a/sandbox/win/src/top_level_dispatcher.cc b/sandbox/win/src/top_level_dispatcher.cc 433 --- a/sandbox/win/src/top_level_dispatcher.cc 434 +++ b/sandbox/win/src/top_level_dispatcher.cc 435 @@ -14,16 +14,17 @@ 436 437 #include "base/check.h" 438 #include "base/notreached.h" 439 #include "sandbox/win/src/crosscall_server.h" 440 #include "sandbox/win/src/filesystem_dispatcher.h" 441 #include "sandbox/win/src/interception.h" 442 #include "sandbox/win/src/internal_types.h" 443 #include "sandbox/win/src/ipc_tags.h" 444 +#include "sandbox/win/src/line_break_dispatcher.h" 445 #include "sandbox/win/src/named_pipe_dispatcher.h" 446 #include "sandbox/win/src/process_mitigations_win32k_dispatcher.h" 447 #include "sandbox/win/src/process_thread_dispatcher.h" 448 #include "sandbox/win/src/sandbox_policy_base.h" 449 #include "sandbox/win/src/signed_dispatcher.h" 450 451 namespace sandbox { 452 453 @@ -46,16 +47,20 @@ TopLevelDispatcher::TopLevelDispatcher(P 454 ipc_targets_[static_cast<size_t>(IpcTag::GDI_GDIDLLINITIALIZE)] = dispatcher; 455 ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETSTOCKOBJECT)] = dispatcher; 456 ipc_targets_[static_cast<size_t>(IpcTag::USER_REGISTERCLASSW)] = dispatcher; 457 process_mitigations_win32k_dispatcher_.reset(dispatcher); 458 459 dispatcher = new SignedDispatcher(policy_); 460 ipc_targets_[static_cast<size_t>(IpcTag::NTCREATESECTION)] = dispatcher; 461 signed_dispatcher_.reset(dispatcher); 462 + 463 + dispatcher = new LineBreakDispatcher(policy_); 464 + ipc_targets_[static_cast<size_t>(IpcTag::GETCOMPLEXLINEBREAKS)] = dispatcher; 465 + line_break_dispatcher_.reset(dispatcher); 466 } 467 468 TopLevelDispatcher::~TopLevelDispatcher() {} 469 470 // When an IPC is ready in any of the targets we get called. We manage an array 471 // of IPC dispatchers which are keyed on the IPC tag so we normally delegate 472 // to the appropriate dispatcher unless we can handle the IPC call ourselves. } 473 Dispatcher* TopLevelDispatcher::OnMessageReady(IPCParams* ipc, 474 diff --git a/sandbox/win/src/top_level_dispatcher.h b/sandbox/win/src/top_level_dispatcher.h 475 --- a/sandbox/win/src/top_level_dispatcher.h 476 +++ b/sandbox/win/src/top_level_dispatcher.h 477 @@ -40,14 +40,15 @@ class TopLevelDispatcher : public Dispat 478 479 raw_ptr<PolicyBase> policy_; 480 std::unique_ptr<Dispatcher> filesystem_dispatcher_; 481 std::unique_ptr<Dispatcher> named_pipe_dispatcher_; 482 std::unique_ptr<Dispatcher> thread_process_dispatcher_; 483 std::unique_ptr<Dispatcher> handle_dispatcher_; 484 std::unique_ptr<Dispatcher> process_mitigations_win32k_dispatcher_; 485 std::unique_ptr<Dispatcher> signed_dispatcher_; 486 + std::unique_ptr<Dispatcher> line_break_dispatcher_; 487 Dispatcher* ipc_targets_[kMaxIpcTag]; 488 }; 489 490 } // namespace sandbox 491 492 #endif // SANDBOX_WIN_SRC_TOP_LEVEL_DISPATCHER_H_