tor-browser

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

36_add_back_registry_brokering.patch (20119B)


      1 # HG changeset patch
      2 # User Bob Owen <bobowencode@gmail.com>
      3 Add back registry brokering.
      4 
      5 This was removed from the chromium codebase, but we still require it.
      6 The stand-alone files have been added to chromium-shim. This patch covers the
      7 wiring back into other chromium code.
      8 Much of this is reinstating removed code without change, but there are some
      9 differences to allow for new policy config style.
     10 
     11 diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc
     12 --- a/sandbox/win/src/interceptors_64.cc
     13 +++ b/sandbox/win/src/interceptors_64.cc
     14 @@ -5,16 +5,17 @@
     15 #include "sandbox/win/src/interceptors_64.h"
     16 
     17 #include "sandbox/win/src/filesystem_interception.h"
     18 #include "sandbox/win/src/interceptors.h"
     19 #include "sandbox/win/src/named_pipe_interception.h"
     20 #include "sandbox/win/src/policy_target.h"
     21 #include "sandbox/win/src/process_mitigations_win32k_interception.h"
     22 #include "sandbox/win/src/process_thread_interception.h"
     23 +#include "sandbox/win/src/registry_interception.h"
     24 #include "sandbox/win/src/sandbox_nt_types.h"
     25 #include "sandbox/win/src/sandbox_types.h"
     26 #include "sandbox/win/src/signed_interception.h"
     27 #include "sandbox/win/src/target_interceptions.h"
     28 
     29 namespace sandbox {
     30 
     31 SANDBOX_INTERCEPT OriginalFunctions g_originals;
     32 @@ -234,16 +235,46 @@ TargetCreateThread64(LPSECURITY_ATTRIBUT
     33       reinterpret_cast<CreateThreadFunction>(g_originals[CREATE_THREAD_ID]);
     34   return TargetCreateThread(orig_fn, thread_attributes, stack_size,
     35                             start_address, parameter, creation_flags,
     36                             thread_id);
     37 }
     38 
     39 // -----------------------------------------------------------------------
     40 
     41 +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateKey64(
     42 +    PHANDLE key, ACCESS_MASK desired_access,
     43 +    POBJECT_ATTRIBUTES object_attributes, ULONG title_index,
     44 +    PUNICODE_STRING class_name, ULONG create_options, PULONG disposition) {
     45 +  NtCreateKeyFunction orig_fn =
     46 +      reinterpret_cast<NtCreateKeyFunction>(g_originals[CREATE_KEY_ID]);
     47 +  return TargetNtCreateKey(orig_fn, key, desired_access, object_attributes,
     48 +                           title_index, class_name, create_options,
     49 +                           disposition);
     50 +}
     51 +
     52 +SANDBOX_INTERCEPT NTSTATUS WINAPI
     53 +TargetNtOpenKey64(PHANDLE key, ACCESS_MASK desired_access,
     54 +                  POBJECT_ATTRIBUTES object_attributes) {
     55 +  NtOpenKeyFunction orig_fn =
     56 +      reinterpret_cast<NtOpenKeyFunction>(g_originals[OPEN_KEY_ID]);
     57 +  return TargetNtOpenKey(orig_fn, key, desired_access, object_attributes);
     58 +}
     59 +
     60 +SANDBOX_INTERCEPT NTSTATUS WINAPI
     61 +TargetNtOpenKeyEx64(PHANDLE key, ACCESS_MASK desired_access,
     62 +                    POBJECT_ATTRIBUTES object_attributes, ULONG open_options) {
     63 +  NtOpenKeyExFunction orig_fn =
     64 +      reinterpret_cast<NtOpenKeyExFunction>(g_originals[OPEN_KEY_EX_ID]);
     65 +  return TargetNtOpenKeyEx(orig_fn, key, desired_access, object_attributes,
     66 +                           open_options);
     67 +}
     68 +
     69 +// -----------------------------------------------------------------------
     70 +
     71 SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(HANDLE dll,
     72                                                        DWORD reason) {
     73   GdiDllInitializeFunction orig_fn =
     74       reinterpret_cast<GdiDllInitializeFunction>(g_originals[GDIINITIALIZE_ID]);
     75   return TargetGdiDllInitialize(orig_fn, dll, reason);
     76 }
     77 
     78 SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object) {
     79 diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h
     80 --- a/sandbox/win/src/interceptors_64.h
     81 +++ b/sandbox/win/src/interceptors_64.h
     82 @@ -155,16 +155,35 @@ SANDBOX_INTERCEPT HANDLE WINAPI
     83 TargetCreateThread64(LPSECURITY_ATTRIBUTES thread_attributes,
     84                      SIZE_T stack_size,
     85                      LPTHREAD_START_ROUTINE start_address,
     86                      PVOID parameter,
     87                      DWORD creation_flags,
     88                      LPDWORD thread_id);
     89 
     90 // -----------------------------------------------------------------------
     91 +// Interceptors handled by the registry dispatcher.
     92 +
     93 +// Interception of NtCreateKey on the child process.
     94 +SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateKey64(
     95 +    PHANDLE key, ACCESS_MASK desired_access,
     96 +    POBJECT_ATTRIBUTES object_attributes, ULONG title_index,
     97 +    PUNICODE_STRING class_name, ULONG create_options, PULONG disposition);
     98 +
     99 +// Interception of NtOpenKey on the child process.
    100 +SANDBOX_INTERCEPT NTSTATUS WINAPI
    101 +TargetNtOpenKey64(PHANDLE key, ACCESS_MASK desired_access,
    102 +                  POBJECT_ATTRIBUTES object_attributes);
    103 +
    104 +// Interception of NtOpenKeyEx on the child process.
    105 +SANDBOX_INTERCEPT NTSTATUS WINAPI
    106 +TargetNtOpenKeyEx64(PHANDLE key, ACCESS_MASK desired_access,
    107 +                    POBJECT_ATTRIBUTES object_attributes, ULONG open_options);
    108 +
    109 +// -----------------------------------------------------------------------
    110 // Interceptors handled by the process mitigations win32k lockdown code.
    111 
    112 // Interceptor for the GdiDllInitialize function.
    113 SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(HANDLE dll,
    114                                                        DWORD reason);
    115 
    116 // Interceptor for the GetStockObject function.
    117 SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object);
    118 diff --git a/sandbox/win/src/ipc_tags.h b/sandbox/win/src/ipc_tags.h
    119 --- a/sandbox/win/src/ipc_tags.h
    120 +++ b/sandbox/win/src/ipc_tags.h
    121 @@ -16,16 +16,18 @@ enum class IpcTag {
    122   NTCREATEFILE,
    123   NTOPENFILE,
    124   NTQUERYATTRIBUTESFILE,
    125   NTQUERYFULLATTRIBUTESFILE,
    126   NTSETINFO_RENAME,
    127   CREATENAMEDPIPEW,
    128   NTOPENTHREAD,
    129   NTOPENPROCESSTOKENEX,
    130 +  NTCREATEKEY,
    131 +  NTOPENKEY,
    132   GDI_GDIDLLINITIALIZE,
    133   GDI_GETSTOCKOBJECT,
    134   USER_REGISTERCLASSW,
    135   CREATETHREAD,
    136   GETCOMPLEXLINEBREAKS,
    137   NTCREATESECTION,
    138   LAST
    139 };
    140 diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
    141 --- a/sandbox/win/src/nt_internals.h
    142 +++ b/sandbox/win/src/nt_internals.h
    143 @@ -216,16 +216,33 @@ typedef NTSTATUS(WINAPI* NtOpenProcessTo
    144 
    145 typedef NTSTATUS(WINAPI* NtOpenProcessTokenExFunction)(
    146     IN HANDLE ProcessHandle,
    147     IN ACCESS_MASK DesiredAccess,
    148     IN ULONG HandleAttributes,
    149     OUT PHANDLE TokenHandle);
    150 
    151 // -----------------------------------------------------------------------
    152 +// Registry
    153 +
    154 +typedef NTSTATUS(WINAPI* NtCreateKeyFunction)(
    155 +    OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess,
    156 +    IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex,
    157 +    IN PUNICODE_STRING Class OPTIONAL, IN ULONG CreateOptions,
    158 +    OUT PULONG Disposition OPTIONAL);
    159 +
    160 +typedef NTSTATUS(WINAPI* NtOpenKeyFunction)(
    161 +    OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess,
    162 +    IN POBJECT_ATTRIBUTES ObjectAttributes);
    163 +
    164 +typedef NTSTATUS(WINAPI* NtOpenKeyExFunction)(
    165 +    OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess,
    166 +    IN POBJECT_ATTRIBUTES ObjectAttributes, IN DWORD open_options);
    167 +
    168 +// -----------------------------------------------------------------------
    169 // Memory
    170 
    171 // Don't really need this structure right now.
    172 typedef PVOID PRTL_HEAP_PARAMETERS;
    173 
    174 typedef PVOID(WINAPI* RtlCreateHeapFunction)(IN ULONG Flags,
    175                                              IN PVOID HeapBase OPTIONAL,
    176                                              IN SIZE_T ReserveSize OPTIONAL,
    177 diff --git a/sandbox/win/src/sandbox_nt_util.cc b/sandbox/win/src/sandbox_nt_util.cc
    178 --- a/sandbox/win/src/sandbox_nt_util.cc
    179 +++ b/sandbox/win/src/sandbox_nt_util.cc
    180 @@ -364,16 +364,109 @@ NTSTATUS CopyNameAndAttributes(
    181     ret = (NTSTATUS)GetExceptionCode();
    182   }
    183 
    184   if (!NT_SUCCESS(ret) && *out_name)
    185     out_name->reset(nullptr);
    186 
    187   return ret;
    188 }
    189 +NTSTATUS AllocAndGetFullPath(
    190 +    HANDLE root, const wchar_t* path,
    191 +    std::unique_ptr<wchar_t, NtAllocDeleter>* full_path) {
    192 +  if (!InitHeap()) return STATUS_NO_MEMORY;
    193 +
    194 +  DCHECK_NT(full_path);
    195 +  DCHECK_NT(path);
    196 +  NTSTATUS ret = STATUS_UNSUCCESSFUL;
    197 +  __try {
    198 +    do {
    199 +      static NtQueryObjectFunction NtQueryObject = nullptr;
    200 +      if (!NtQueryObject) ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
    201 +
    202 +      ULONG size = 0;
    203 +      // Query the name information a first time to get the size of the name.
    204 +      ret = NtQueryObject(root, ObjectNameInformation, nullptr, 0, &size);
    205 +
    206 +      std::unique_ptr<OBJECT_NAME_INFORMATION, NtAllocDeleter> handle_name;
    207 +      if (size) {
    208 +        handle_name.reset(reinterpret_cast<OBJECT_NAME_INFORMATION*>(
    209 +            new (NT_ALLOC) BYTE[size]));
    210 +
    211 +        // Query the name information a second time to get the name of the
    212 +        // object referenced by the handle.
    213 +        ret = NtQueryObject(root, ObjectNameInformation, handle_name.get(),
    214 +                            size, &size);
    215 +      }
    216 +
    217 +      if (STATUS_SUCCESS != ret) break;
    218 +
    219 +      // Space for path + '\' + name + '\0'.
    220 +      size_t name_length =
    221 +          handle_name->ObjectName.Length + (wcslen(path) + 2) * sizeof(wchar_t);
    222 +      full_path->reset(new (NT_ALLOC) wchar_t[name_length / sizeof(wchar_t)]);
    223 +      if (!*full_path) break;
    224 +      wchar_t* off = full_path->get();
    225 +      ret = CopyData(off, handle_name->ObjectName.Buffer,
    226 +                     handle_name->ObjectName.Length);
    227 +      if (!NT_SUCCESS(ret)) break;
    228 +      off += handle_name->ObjectName.Length / sizeof(wchar_t);
    229 +      *off = L'\\';
    230 +      off += 1;
    231 +      ret = CopyData(off, path, wcslen(path) * sizeof(wchar_t));
    232 +      if (!NT_SUCCESS(ret)) break;
    233 +      off += wcslen(path);
    234 +      *off = L'\0';
    235 +    } while (false);
    236 +  } __except (EXCEPTION_EXECUTE_HANDLER) {
    237 +    ret = GetExceptionCode();
    238 +  }
    239 +
    240 +  if (!NT_SUCCESS(ret) && *full_path) full_path->reset(nullptr);
    241 +
    242 +  return ret;
    243 +}
    244 +
    245 +// Hacky code... replace with AllocAndCopyObjectAttributes.
    246 +NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
    247 +                          std::unique_ptr<wchar_t, NtAllocDeleter>* out_name,
    248 +                          uint32_t* attributes, HANDLE* root) {
    249 +  if (!InitHeap()) return STATUS_NO_MEMORY;
    250 +
    251 +  DCHECK_NT(out_name);
    252 +  NTSTATUS ret = STATUS_UNSUCCESSFUL;
    253 +  __try {
    254 +    do {
    255 +      if (in_object->RootDirectory != static_cast<HANDLE>(0) && !root) break;
    256 +      if (!in_object->ObjectName) break;
    257 +      if (!in_object->ObjectName->Buffer) break;
    258 +
    259 +      size_t size = in_object->ObjectName->Length + sizeof(wchar_t);
    260 +      out_name->reset(new (NT_ALLOC) wchar_t[size / sizeof(wchar_t)]);
    261 +      if (!*out_name) break;
    262 +
    263 +      ret = CopyData(out_name->get(), in_object->ObjectName->Buffer,
    264 +                     size - sizeof(wchar_t));
    265 +      if (!NT_SUCCESS(ret)) break;
    266 +
    267 +      out_name->get()[size / sizeof(wchar_t) - 1] = L'\0';
    268 +
    269 +      if (attributes) *attributes = in_object->Attributes;
    270 +
    271 +      if (root) *root = in_object->RootDirectory;
    272 +      ret = STATUS_SUCCESS;
    273 +    } while (false);
    274 +  } __except (EXCEPTION_EXECUTE_HANDLER) {
    275 +    ret = GetExceptionCode();
    276 +  }
    277 +
    278 +  if (!NT_SUCCESS(ret) && *out_name) out_name->reset(nullptr);
    279 +
    280 +  return ret;
    281 +}
    282 
    283 NTSTATUS GetProcessId(HANDLE process, DWORD* process_id) {
    284   PROCESS_BASIC_INFORMATION proc_info;
    285   ULONG bytes_returned;
    286 
    287   NTSTATUS ret = GetNtExports()->QueryInformationProcess(
    288       process, ProcessBasicInformation, &proc_info, sizeof(proc_info),
    289       &bytes_returned);
    290 diff --git a/sandbox/win/src/sandbox_nt_util.h b/sandbox/win/src/sandbox_nt_util.h
    291 --- a/sandbox/win/src/sandbox_nt_util.h
    292 +++ b/sandbox/win/src/sandbox_nt_util.h
    293 @@ -127,16 +127,26 @@ NTSTATUS CopyData(void* destination, con
    294 // string and |out_name_len| is the number of characters copied. |attributes|
    295 // is a copy of the attribute flags from |in_object|.
    296 NTSTATUS CopyNameAndAttributes(
    297     const OBJECT_ATTRIBUTES* in_object,
    298     std::unique_ptr<wchar_t, NtAllocDeleter>* out_name,
    299     size_t* out_name_len,
    300     uint32_t* attributes = nullptr);
    301 
    302 +// Copies the name from an object attributes.
    303 +NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
    304 +                          std::unique_ptr<wchar_t, NtAllocDeleter>* out_name,
    305 +                          uint32_t* attributes, HANDLE* root);
    306 +
    307 +// Determine full path name from object root and path.
    308 +NTSTATUS AllocAndGetFullPath(
    309 +    HANDLE root, const wchar_t* path,
    310 +    std::unique_ptr<wchar_t, NtAllocDeleter>* full_path);
    311 +
    312 // Initializes our ntdll level heap
    313 bool InitHeap();
    314 
    315 // Returns true if the provided handle refers to the current process.
    316 bool IsSameProcess(HANDLE process);
    317 
    318 enum MappedModuleFlags {
    319   MODULE_IS_PE_IMAGE = 1,      // Module is an executable.
    320 diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
    321 --- a/sandbox/win/src/sandbox_policy.h
    322 +++ b/sandbox/win/src/sandbox_policy.h
    323 @@ -161,16 +161,25 @@ class [[clang::lto_visibility_public]] T
    324   // Adds a policy rule effective for processes spawned using this policy.
    325   // Named pipes matching `pattern` (see AllowFileAccess) can be created.
    326   //
    327   // Note: Do not add new uses of this function - instead proxy pipe handles
    328   // into your process via normal Chrome IPC.
    329   [[nodiscard]] virtual ResultCode AllowNamedPipes(const wchar_t* pattern) = 0;
    330 
    331   // Adds a policy rule effective for processes spawned using this policy.
    332 +  // Registry entries matching `pattern` (see AllowFileAccess) can be opened
    333 +  // for read access.
    334 +  //
    335 +  // Note: Do not add new uses of this function - instead proxy registry handles
    336 +  // into your process via normal Chrome IPC.
    337 +  [[nodiscard]] virtual ResultCode AllowRegistryRead(
    338 +      const wchar_t* pattern) = 0;
    339 +
    340 +  // Adds a policy rule effective for processes spawned using this policy.
    341   // Modules patching `pattern` (see AllowFileAccess) can still be loaded under
    342   // Code-Integrity Guard (MITIGATION_FORCE_MS_SIGNED_BINS).
    343   [[nodiscard]] virtual ResultCode AllowExtraDlls(const wchar_t* pattern) = 0;
    344 
    345   // Adds a policy rule effective for processes spawned using this policy.
    346   // Fake gdi init to allow user32 and gdi32 to initialize under Win32 Lockdown.
    347   [[nodiscard]] virtual ResultCode SetFakeGdiInit() = 0;
    348 
    349 diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
    350 --- a/sandbox/win/src/sandbox_policy_base.cc
    351 +++ b/sandbox/win/src/sandbox_policy_base.cc
    352 @@ -28,16 +28,17 @@
    353 #include "sandbox/win/src/line_break_policy.h"
    354 #include "sandbox/win/src/named_pipe_policy.h"
    355 #include "sandbox/win/src/policy_broker.h"
    356 #include "sandbox/win/src/policy_engine_processor.h"
    357 #include "sandbox/win/src/policy_low_level.h"
    358 #include "sandbox/win/src/process_mitigations.h"
    359 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
    360 #include "sandbox/win/src/process_thread_policy.h"
    361 +#include "sandbox/win/src/registry_policy.h"
    362 #include "sandbox/win/src/restricted_token_utils.h"
    363 #include "sandbox/win/src/sandbox_policy.h"
    364 #include "sandbox/win/src/sandbox_policy_diagnostic.h"
    365 #include "sandbox/win/src/signed_policy.h"
    366 #include "sandbox/win/src/target_process.h"
    367 #include "sandbox/win/src/top_level_dispatcher.h"
    368 #include "third_party/abseil-cpp/absl/types/optional.h"
    369 
    370 @@ -241,16 +242,24 @@ ResultCode ConfigBase::AllowFileAccess(F
    371 ResultCode ConfigBase::AllowNamedPipes(const wchar_t* pattern) {
    372   if (!NamedPipePolicy::GenerateRules(pattern, PolicyMaker())) {
    373     NOTREACHED();
    374     return SBOX_ERROR_BAD_PARAMS;
    375   }
    376   return SBOX_ALL_OK;
    377 }
    378 
    379 +ResultCode ConfigBase::AllowRegistryRead(const wchar_t* pattern) {
    380 +  if (!RegistryPolicy::GenerateRules(pattern, PolicyMaker())) {
    381 +    NOTREACHED();
    382 +    return SBOX_ERROR_BAD_PARAMS;
    383 +  }
    384 +  return SBOX_ALL_OK;
    385 +}
    386 +
    387 ResultCode ConfigBase::SetFakeGdiInit() {
    388   DCHECK_EQ(MITIGATION_WIN32K_DISABLE, mitigations_ & MITIGATION_WIN32K_DISABLE)
    389       << "Enable MITIGATION_WIN32K_DISABLE before adding win32k policy "
    390          "rules.";
    391   if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(PolicyMaker())) {
    392     NOTREACHED();
    393     return SBOX_ERROR_BAD_PARAMS;
    394   }
    395 diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
    396 --- a/sandbox/win/src/sandbox_policy_base.h
    397 +++ b/sandbox/win/src/sandbox_policy_base.h
    398 @@ -63,16 +63,17 @@ class ConfigBase final : public TargetCo
    399   void SetAllowEveryoneForUserRestricted() final;
    400   bool GetAllowEveryoneForUserRestricted() final;
    401   ResultCode SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) override;
    402   JobLevel GetJobLevel() const override;
    403   void SetJobMemoryLimit(size_t memory_limit) override;
    404   ResultCode AllowFileAccess(FileSemantics semantics,
    405                              const wchar_t* pattern) override;
    406   ResultCode AllowNamedPipes(const wchar_t* pattern) override;
    407 +  ResultCode AllowRegistryRead(const wchar_t* pattern) final;
    408   ResultCode AllowExtraDlls(const wchar_t* pattern) override;
    409   ResultCode SetFakeGdiInit() override;
    410   ResultCode AllowLineBreaking() final;
    411   void AddDllToUnload(const wchar_t* dll_name) override;
    412   ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) override;
    413   IntegrityLevel GetIntegrityLevel() const override;
    414   void SetDelayedIntegrityLevel(IntegrityLevel integrity_level) override;
    415   ResultCode SetLowBox(const wchar_t* sid) override;
    416 diff --git a/sandbox/win/src/top_level_dispatcher.cc b/sandbox/win/src/top_level_dispatcher.cc
    417 --- a/sandbox/win/src/top_level_dispatcher.cc
    418 +++ b/sandbox/win/src/top_level_dispatcher.cc
    419 @@ -13,16 +13,17 @@
    420 #include "sandbox/win/src/filesystem_dispatcher.h"
    421 #include "sandbox/win/src/interception.h"
    422 #include "sandbox/win/src/internal_types.h"
    423 #include "sandbox/win/src/ipc_tags.h"
    424 #include "sandbox/win/src/line_break_dispatcher.h"
    425 #include "sandbox/win/src/named_pipe_dispatcher.h"
    426 #include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
    427 #include "sandbox/win/src/process_thread_dispatcher.h"
    428 +#include "sandbox/win/src/registry_dispatcher.h"
    429 #include "sandbox/win/src/sandbox_policy_base.h"
    430 #include "sandbox/win/src/signed_dispatcher.h"
    431 
    432 namespace sandbox {
    433 
    434 TopLevelDispatcher::TopLevelDispatcher(PolicyBase* policy) : policy_(policy) {
    435   // Initialize the IPC dispatcher array.
    436   memset(ipc_targets_, 0, sizeof(ipc_targets_));
    437 @@ -42,16 +43,21 @@ TopLevelDispatcher::TopLevelDispatcher(P
    438   named_pipe_dispatcher_.reset(dispatcher);
    439 
    440   dispatcher = new ThreadProcessDispatcher();
    441   ipc_targets_[static_cast<size_t>(IpcTag::NTOPENTHREAD)] = dispatcher;
    442   ipc_targets_[static_cast<size_t>(IpcTag::NTOPENPROCESSTOKENEX)] = dispatcher;
    443   ipc_targets_[static_cast<size_t>(IpcTag::CREATETHREAD)] = dispatcher;
    444   thread_process_dispatcher_.reset(dispatcher);
    445 
    446 +  dispatcher = new RegistryDispatcher(policy_);
    447 +  ipc_targets_[static_cast<size_t>(IpcTag::NTCREATEKEY)] = dispatcher;
    448 +  ipc_targets_[static_cast<size_t>(IpcTag::NTOPENKEY)] = dispatcher;
    449 +  registry_dispatcher_.reset(dispatcher);
    450 +
    451   dispatcher = new ProcessMitigationsWin32KDispatcher(policy_);
    452   ipc_targets_[static_cast<size_t>(IpcTag::GDI_GDIDLLINITIALIZE)] = dispatcher;
    453   ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETSTOCKOBJECT)] = dispatcher;
    454   ipc_targets_[static_cast<size_t>(IpcTag::USER_REGISTERCLASSW)] = dispatcher;
    455   process_mitigations_win32k_dispatcher_.reset(dispatcher);
    456 
    457   dispatcher = new SignedDispatcher(policy_);
    458   ipc_targets_[static_cast<size_t>(IpcTag::NTCREATESECTION)] = dispatcher;
    459 diff --git a/sandbox/win/src/top_level_dispatcher.h b/sandbox/win/src/top_level_dispatcher.h
    460 --- a/sandbox/win/src/top_level_dispatcher.h
    461 +++ b/sandbox/win/src/top_level_dispatcher.h
    462 @@ -37,16 +37,17 @@ class TopLevelDispatcher : public Dispat
    463 
    464   // Returns a dispatcher from ipc_targets_.
    465   Dispatcher* GetDispatcher(IpcTag ipc_tag);
    466 
    467   raw_ptr<PolicyBase> policy_;
    468   std::unique_ptr<Dispatcher> filesystem_dispatcher_;
    469   std::unique_ptr<Dispatcher> named_pipe_dispatcher_;
    470   std::unique_ptr<Dispatcher> thread_process_dispatcher_;
    471 +  std::unique_ptr<Dispatcher> registry_dispatcher_;
    472   std::unique_ptr<Dispatcher> handle_dispatcher_;
    473   std::unique_ptr<Dispatcher> process_mitigations_win32k_dispatcher_;
    474   std::unique_ptr<Dispatcher> signed_dispatcher_;
    475   std::unique_ptr<Dispatcher> line_break_dispatcher_;
    476   Dispatcher* ipc_targets_[kMaxIpcTag];
    477 };
    478 
    479 }  // namespace sandbox