tor-browser

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

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_