summaryrefslogtreecommitdiffstats
path: root/browser/app/winlauncher/freestanding/SharedSection.h
diff options
context:
space:
mode:
Diffstat (limited to 'browser/app/winlauncher/freestanding/SharedSection.h')
-rw-r--r--browser/app/winlauncher/freestanding/SharedSection.h212
1 files changed, 212 insertions, 0 deletions
diff --git a/browser/app/winlauncher/freestanding/SharedSection.h b/browser/app/winlauncher/freestanding/SharedSection.h
new file mode 100644
index 0000000000..54e89a2325
--- /dev/null
+++ b/browser/app/winlauncher/freestanding/SharedSection.h
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_freestanding_SharedSection_h
+#define mozilla_freestanding_SharedSection_h
+
+#include "mozilla/DynamicBlocklist.h"
+#include "mozilla/glue/SharedSection.h"
+#include "mozilla/NativeNt.h"
+#include "mozilla/interceptor/MMPolicies.h"
+
+// clang-format off
+#define MOZ_LITERAL_UNICODE_STRING(s) \
+ { \
+ /* Length of the string in bytes, less the null terminator */ \
+ sizeof(s) - sizeof(wchar_t), \
+ /* Length of the string in bytes, including the null terminator */ \
+ sizeof(s), \
+ /* Pointer to the buffer */ \
+ const_cast<wchar_t*>(s) \
+ }
+// clang-format on
+
+namespace mozilla {
+namespace freestanding {
+class SharedSectionTestHelper;
+
+struct DllBlockInfoComparator {
+ explicit DllBlockInfoComparator(const UNICODE_STRING& aTarget)
+ : mTarget(&aTarget) {}
+
+ int operator()(const DllBlockInfo& aVal) const {
+ return static_cast<int>(
+ ::RtlCompareUnicodeString(mTarget, &aVal.mName, TRUE));
+ }
+
+ PCUNICODE_STRING mTarget;
+};
+
+// This class calculates RVAs of kernel32's functions and transfers them
+// to a target process, where the transferred RVAs are resolved into
+// function addresses so that the target process can use them after
+// kernel32.dll is loaded and before IAT is resolved.
+struct MOZ_TRIVIAL_CTOR_DTOR Kernel32ExportsSolver final
+ : interceptor::MMPolicyInProcessEarlyStage::Kernel32Exports {
+ void Init();
+ bool Resolve();
+};
+
+// This class manages a section which is created in the launcher process and
+// mapped in the browser process and the sandboxed processes. The section's
+// layout is represented as SharedSection::Layout.
+//
+// (1) Kernel32's functions required for MMPolicyInProcessEarlyStage
+// Formatted as Kernel32ExportsSolver.
+//
+// (2) Various flags and offsets
+//
+// (3) Entries in the dynamic blocklist, in DllBlockInfo format. There
+// are mNumBlockEntries of these, followed by one that has mName.Length
+// of 0. Note that the strings that contain
+// the names of the entries in the blocklist are stored concatenated
+// after the last entry. The mName pointers in each DllBlockInfo point
+// to these strings correctly in Resolve(), so clients don't need
+// to do anything special to read these strings.
+//
+// (4) Array of NT paths of the executable's dependent modules
+// Formatted as a null-delimited wide-character string set ending with
+// an empty string. These entries start at offset
+// mDependentModulePathArrayStart (in bytes) from the beginning
+// of the structure
+//
+// +--------------------------------------------------------------+
+// | (1) | FlushInstructionCache |
+// | | GetModuleHandleW |
+// | | GetSystemInfo |
+// | | VirtualProtect |
+// | | State [kUninitialized|kInitialized|kResolved] |
+// +--------------------------------------------------------------+
+// | (2) | (flags and offsets) |
+// +--------------------------------------------------------------+
+// | (3) | <DllBlockInfo for first entry in dynamic blocklist> |
+// | | <DllBlockInfo for second entry in dynamic blocklist> |
+// | | ... |
+// | | <DllBlockInfo for last entry in dynamic blocklist> |
+// | | <DllBlockInfo with mName.Length of 0> |
+// | | L"string1.dllstring2.dll...stringlast.dll" |
+// +--------------------------------------------------------------+
+// | (4) | L"NT path 1" |
+// | | L"NT path 2" |
+// | | ... |
+// | | L"" |
+// +--------------------------------------------------------------+
+class MOZ_TRIVIAL_CTOR_DTOR SharedSection final : public nt::SharedSection {
+ struct Layout final {
+ enum class State {
+ kUninitialized,
+ kInitialized,
+ kLoadedDynamicBlocklistEntries,
+ kResolved,
+ } mState;
+
+ Kernel32ExportsSolver mK32Exports;
+ // 1 if the blocklist is disabled, 0 otherwise.
+ // If the blocklist is disabled, the entries are still loaded to make it
+ // easy for the user to remove any they don't want, but none of the DLLs
+ // here are actually blocked.
+ // Stored as a uint32_t for alignment reasons.
+ uint32_t mBlocklistIsDisabled;
+ // The offset, in bytes, from the beginning of the Layout structure to the
+ // first dependent module entry.
+ // When the Layout object is created, this value is 0, indicating that no
+ // dependent modules have been added and it is safe to add DllBlockInfo
+ // entries.
+ // After this value is set to something non-0, no more DllBlockInfo entries
+ // can be added.
+ uint32_t mDependentModulePathArrayStart;
+ // The number of blocklist entries.
+ uint32_t mNumBlockEntries;
+ DllBlockInfo mFirstBlockEntry[1];
+
+ Span<DllBlockInfo> GetModulePathArray() {
+ return Span<DllBlockInfo>(
+ mFirstBlockEntry,
+ (kSharedViewSize - (reinterpret_cast<uintptr_t>(mFirstBlockEntry) -
+ reinterpret_cast<uintptr_t>(this))) /
+ sizeof(DllBlockInfo));
+ }
+ // Can be used to make sure we don't step past the end of the shared memory
+ // section.
+ static constexpr uint32_t GetMaxNumBlockEntries() {
+ return (kSharedViewSize - (offsetof(Layout, mFirstBlockEntry))) /
+ sizeof(DllBlockInfo);
+ }
+ Layout() = delete; // disallow instantiation
+ bool Resolve();
+ bool IsDisabled() const;
+ const DllBlockInfo* SearchBlocklist(const UNICODE_STRING& aLeafName) const;
+ Span<wchar_t> GetDependentModules();
+ };
+
+ // As we define a global variable of this class and use it in our blocklist
+ // which is excuted in a process's early stage. If we have a complex dtor,
+ // the static initializer tries to register that dtor with onexit() of
+ // ucrtbase.dll which is not loaded yet, resulting in crash. Thus, we have
+ // a raw handle and a pointer as a static variable and manually release them
+ // by calling Reset() where possible.
+ static HANDLE sSectionHandle;
+ static Layout* sWriteCopyView;
+ static RTL_RUN_ONCE sEnsureOnce;
+
+ // The sLock lock guarantees that while it is held, sSectionHandle will not
+ // change nor get closed, sEnsureOnce will not get reinitialized, and
+ // sWriteCopyView will not change nor get unmapped once initialized. We take
+ // sLock on paths that could run concurrently with ConvertToReadOnly(). This
+ // method is only called on the main process, and very early, so the only
+ // real risk here should be threads started by third-party products reaching
+ // our patched_NtMapViewOfSection (see bug 1850969).
+ static nt::SRWLock sLock;
+
+ static ULONG NTAPI EnsureWriteCopyViewOnce(PRTL_RUN_ONCE, PVOID, PVOID*);
+ static Layout* EnsureWriteCopyView(bool requireKernel32Exports = false);
+
+ static constexpr size_t kSharedViewSize = 0x1000;
+
+ // For test use only
+ friend class SharedSectionTestHelper;
+
+ public:
+ // Replace |sSectionHandle| with a given handle.
+ static void Reset(HANDLE aNewSectionObject = sSectionHandle);
+
+ static inline nt::AutoSharedLock AutoNoReset() {
+ return nt::AutoSharedLock{sLock};
+ }
+
+ // Replace |sSectionHandle| with a new readonly handle.
+ static void ConvertToReadOnly();
+
+ // Create a new writable section and initialize the Kernel32ExportsSolver
+ // part.
+ static LauncherVoidResult Init();
+
+ // Append a new string to the |sSectionHandle|
+ static LauncherVoidResult AddDependentModule(PCUNICODE_STRING aNtPath);
+ static LauncherVoidResult SetBlocklist(const DynamicBlockList& aBlocklist,
+ bool isDisabled);
+
+ // Map |sSectionHandle| to a copy-on-write page and return a writable pointer
+ // to each structure, or null if Layout failed to resolve exports.
+ Kernel32ExportsSolver* GetKernel32Exports();
+ Maybe<Vector<const wchar_t*>> GetDependentModules() final override;
+ Span<const DllBlockInfo> GetDynamicBlocklist() final override;
+
+ static bool IsDisabled();
+ static const DllBlockInfo* SearchBlocklist(const UNICODE_STRING& aLeafName);
+
+ // Transfer |sSectionHandle| to a process associated with |aTransferMgr|.
+ static LauncherVoidResult TransferHandle(
+ nt::CrossExecTransferManager& aTransferMgr, DWORD aDesiredAccess,
+ HANDLE* aDestinationAddress = &sSectionHandle);
+};
+
+extern SharedSection gSharedSection;
+
+} // namespace freestanding
+} // namespace mozilla
+
+#endif // mozilla_freestanding_SharedSection_h