tor-browser

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

SharedSection.h (9400B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_freestanding_SharedSection_h
      8 #define mozilla_freestanding_SharedSection_h
      9 
     10 #include "mozilla/DynamicBlocklist.h"
     11 #include "mozilla/glue/SharedSection.h"
     12 #include "mozilla/NativeNt.h"
     13 #include "mozilla/interceptor/MMPolicies.h"
     14 
     15 // clang-format off
     16 #define MOZ_LITERAL_UNICODE_STRING(s)                                        \
     17  {                                                                          \
     18    /* Length of the string in bytes, less the null terminator */            \
     19    sizeof(s) - sizeof(wchar_t),                                             \
     20    /* Length of the string in bytes, including the null terminator */       \
     21    sizeof(s),                                                               \
     22    /* Pointer to the buffer */                                              \
     23    const_cast<wchar_t*>(s)                                                  \
     24  }
     25 // clang-format on
     26 
     27 namespace mozilla {
     28 namespace freestanding {
     29 class SharedSectionTestHelper;
     30 
     31 struct DllBlockInfoComparator {
     32  explicit DllBlockInfoComparator(const UNICODE_STRING& aTarget)
     33      : mTarget(&aTarget) {}
     34 
     35  int operator()(const DllBlockInfo& aVal) const {
     36    return static_cast<int>(
     37        ::RtlCompareUnicodeString(mTarget, &aVal.mName, TRUE));
     38  }
     39 
     40  PCUNICODE_STRING mTarget;
     41 };
     42 
     43 // This class calculates RVAs of kernel32's functions and transfers them
     44 // to a target process, where the transferred RVAs are resolved into
     45 // function addresses so that the target process can use them after
     46 // kernel32.dll is loaded and before IAT is resolved.
     47 struct MOZ_TRIVIAL_CTOR_DTOR Kernel32ExportsSolver final
     48    : interceptor::MMPolicyInProcessEarlyStage::Kernel32Exports {
     49  void Init();
     50  bool Resolve();
     51 };
     52 
     53 // This class manages a section which is created in the launcher process and
     54 // mapped in the browser process and the sandboxed processes.  The section's
     55 // layout is represented as SharedSection::Layout.
     56 //
     57 // (1) Kernel32's functions required for MMPolicyInProcessEarlyStage
     58 //     Formatted as Kernel32ExportsSolver.
     59 //
     60 // (2) Various flags and offsets
     61 //
     62 // (3) Entries in the dynamic blocklist, in DllBlockInfo format. There
     63 //     are mNumBlockEntries of these, followed by one that has mName.Length
     64 //     of 0. Note that the strings that contain
     65 //     the names of the entries in the blocklist are stored concatenated
     66 //     after the last entry. The mName pointers in each DllBlockInfo point
     67 //     to these strings correctly in Resolve(), so clients don't need
     68 //     to do anything special to read these strings.
     69 //
     70 // (4) Array of NT paths of the executable's dependent modules
     71 //     Formatted as a null-delimited wide-character string set ending with
     72 //     an empty string. These entries start at offset
     73 //     mDependentModulePathArrayStart (in bytes) from the beginning
     74 //     of the structure
     75 //
     76 // +--------------------------------------------------------------+
     77 // | (1) | FlushInstructionCache                                  |
     78 // |     | GetModuleHandleW                                       |
     79 // |     | GetSystemInfo                                          |
     80 // |     | VirtualProtect                                         |
     81 // |     | State [kUninitialized|kInitialized|kResolved]          |
     82 // +--------------------------------------------------------------+
     83 // | (2) | (flags and offsets)                                    |
     84 // +--------------------------------------------------------------+
     85 // | (3) | <DllBlockInfo for first entry in dynamic blocklist>    |
     86 // |     | <DllBlockInfo for second entry in dynamic blocklist>   |
     87 // |     | ...                                                    |
     88 // |     | <DllBlockInfo for last entry in dynamic blocklist>     |
     89 // |     | <DllBlockInfo with mName.Length of 0>                  |
     90 // |     | L"string1.dllstring2.dll...stringlast.dll"             |
     91 // +--------------------------------------------------------------+
     92 // | (4) | L"NT path 1"                                           |
     93 // |     | L"NT path 2"                                           |
     94 // |     | ...                                                    |
     95 // |     | L""                                                    |
     96 // +--------------------------------------------------------------+
     97 class MOZ_TRIVIAL_CTOR_DTOR SharedSection final : public nt::SharedSection {
     98  struct Layout final {
     99    enum class State {
    100      kUninitialized,
    101      kInitialized,
    102      kLoadedDynamicBlocklistEntries,
    103      kResolved,
    104    } mState;
    105 
    106    Kernel32ExportsSolver mK32Exports;
    107    // 1 if the blocklist is disabled, 0 otherwise.
    108    // If the blocklist is disabled, the entries are still loaded to make it
    109    // easy for the user to remove any they don't want, but none of the DLLs
    110    // here are actually blocked.
    111    // Stored as a uint32_t for alignment reasons.
    112    uint32_t mBlocklistIsDisabled;
    113    // The offset, in bytes, from the beginning of the Layout structure to the
    114    // first dependent module entry.
    115    // When the Layout object is created, this value is 0, indicating that no
    116    // dependent modules have been added and it is safe to add DllBlockInfo
    117    // entries.
    118    // After this value is set to something non-0, no more DllBlockInfo entries
    119    // can be added.
    120    uint32_t mDependentModulePathArrayStart;
    121    // The number of blocklist entries.
    122    uint32_t mNumBlockEntries;
    123    DllBlockInfo mFirstBlockEntry[1];
    124 
    125    Span<DllBlockInfo> GetModulePathArray() {
    126      return Span<DllBlockInfo>(
    127          mFirstBlockEntry,
    128          (kSharedViewSize - (reinterpret_cast<uintptr_t>(mFirstBlockEntry) -
    129                              reinterpret_cast<uintptr_t>(this))) /
    130              sizeof(DllBlockInfo));
    131    }
    132    // Can be used to make sure we don't step past the end of the shared memory
    133    // section.
    134    static constexpr uint32_t GetMaxNumBlockEntries() {
    135      return (kSharedViewSize - (offsetof(Layout, mFirstBlockEntry))) /
    136             sizeof(DllBlockInfo);
    137    }
    138    Layout() = delete;  // disallow instantiation
    139    bool Resolve();
    140    bool IsDisabled() const;
    141    const DllBlockInfo* SearchBlocklist(const UNICODE_STRING& aLeafName) const;
    142    Span<wchar_t> GetDependentModules();
    143  };
    144 
    145  // As we define a global variable of this class and use it in our blocklist
    146  // which is excuted in a process's early stage.  If we have a complex dtor,
    147  // the static initializer tries to register that dtor with onexit() of
    148  // ucrtbase.dll which is not loaded yet, resulting in crash.  Thus, we have
    149  // a raw handle and a pointer as a static variable and manually release them
    150  // by calling Reset() where possible.
    151  static HANDLE sSectionHandle;
    152  static Layout* sWriteCopyView;
    153  static RTL_RUN_ONCE sEnsureOnce;
    154 
    155  // The sLock lock guarantees that while it is held, sSectionHandle will not
    156  // change nor get closed, sEnsureOnce will not get reinitialized, and
    157  // sWriteCopyView will not change nor get unmapped once initialized. We take
    158  // sLock on paths that could run concurrently with ConvertToReadOnly(). This
    159  // method is only called on the main process, and very early, so the only
    160  // real risk here should be threads started by third-party products reaching
    161  // our patched_NtMapViewOfSection (see bug 1850969).
    162  static nt::SRWLock sLock;
    163 
    164  static ULONG NTAPI EnsureWriteCopyViewOnce(PRTL_RUN_ONCE, PVOID, PVOID*);
    165  static Layout* EnsureWriteCopyView(bool requireKernel32Exports = false);
    166 
    167  static constexpr size_t kSharedViewSize = 0x1000;
    168 
    169  // For test use only
    170  friend class SharedSectionTestHelper;
    171 
    172 public:
    173  // Replace |sSectionHandle| with a given handle.
    174  static void Reset(HANDLE aNewSectionObject = sSectionHandle);
    175 
    176  static inline nt::AutoSharedLock AutoNoReset() {
    177    return nt::AutoSharedLock{sLock};
    178  }
    179 
    180  // Replace |sSectionHandle| with a new readonly handle.
    181  static void ConvertToReadOnly();
    182 
    183  // Create a new writable section and initialize the Kernel32ExportsSolver
    184  // part.
    185  static LauncherVoidResult Init();
    186 
    187  // Append a new string to the |sSectionHandle|
    188  static LauncherVoidResult AddDependentModule(PCUNICODE_STRING aNtPath);
    189  static LauncherVoidResult SetBlocklist(const DynamicBlockList& aBlocklist,
    190                                         bool isDisabled);
    191 
    192  // Map |sSectionHandle| to a copy-on-write page and return a writable pointer
    193  // to each structure, or null if Layout failed to resolve exports.
    194  Kernel32ExportsSolver* GetKernel32Exports();
    195  Maybe<Vector<const wchar_t*>> GetDependentModules() final override;
    196  Span<const DllBlockInfo> GetDynamicBlocklist() final override;
    197 
    198  static bool IsDisabled();
    199  static const DllBlockInfo* SearchBlocklist(const UNICODE_STRING& aLeafName);
    200 
    201  // Transfer |sSectionHandle| to a process associated with |aTransferMgr|.
    202  static LauncherVoidResult TransferHandle(
    203      nt::CrossExecTransferManager& aTransferMgr, DWORD aDesiredAccess,
    204      HANDLE* aDestinationAddress = &sSectionHandle);
    205 };
    206 
    207 extern SharedSection gSharedSection;
    208 
    209 }  // namespace freestanding
    210 }  // namespace mozilla
    211 
    212 #endif  // mozilla_freestanding_SharedSection_h