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_ModuleLoadFrame_h
8 #define mozilla_freestanding_ModuleLoadFrame_h
9 
10 #include "mozilla/LoaderAPIInterfaces.h"
11 #include "mozilla/NativeNt.h"
12 #include "mozilla/ThreadLocal.h"
13 
14 #include "SafeThreadLocal.h"
15 
16 namespace mozilla {
17 namespace freestanding {
18 
19 /**
20  * This class holds information about a DLL load at a particular frame in the
21  * current thread's stack. Each instance adds itself to a thread-local linked
22  * list of ModuleLoadFrames, enabling us to query information about the
23  * previous module load on the stack.
24  */
25 class MOZ_RAII ModuleLoadFrame final {
26  public:
27   /**
28    * This constructor is for use by the LdrLoadDll hook.
29    */
30   explicit ModuleLoadFrame(PCUNICODE_STRING aRequestedDllName);
31   ~ModuleLoadFrame();
32 
33   static void NotifyLSPSubstitutionRequired(PCUNICODE_STRING aLeafName);
34 
35   /**
36    * This static method is called by the NtMapViewOfSection hook.
37    */
38   static void NotifySectionMap(nt::AllocatedUnicodeString&& aSectionName,
39                                const void* aMapBaseAddr, NTSTATUS aMapNtStatus,
40                                ModuleLoadInfo::Status aLoadStatus,
41                                bool aIsDependent);
42   static bool ExistsTopFrame();
43 
44   /**
45    * Called by the LdrLoadDll hook to indicate the status of the load and for
46    * us to provide a substitute output handle if necessary.
47    */
48   NTSTATUS SetLoadStatus(NTSTATUS aNtStatus, PHANDLE aOutHandle);
49 
50   ModuleLoadFrame(const ModuleLoadFrame&) = delete;
51   ModuleLoadFrame(ModuleLoadFrame&&) = delete;
52   ModuleLoadFrame& operator=(const ModuleLoadFrame&) = delete;
53   ModuleLoadFrame& operator=(ModuleLoadFrame&&) = delete;
54 
55  private:
56   /**
57    * Called by OnBareSectionMap to construct a frame for a bare load.
58    */
59   ModuleLoadFrame(nt::AllocatedUnicodeString&& aSectionName,
60                   const void* aMapBaseAddr, NTSTATUS aNtStatus,
61                   ModuleLoadInfo::Status aLoadStatus, bool aIsDependent);
62 
63   void SetLSPSubstitutionRequired(PCUNICODE_STRING aLeafName);
64   void OnSectionMap(nt::AllocatedUnicodeString&& aSectionName,
65                     const void* aMapBaseAddr, NTSTATUS aMapNtStatus,
66                     ModuleLoadInfo::Status aLoadStatus, bool aIsDependent);
67 
68   /**
69    * A "bare" section mapping is one that was mapped without the code passing
70    * through a call to ntdll!LdrLoadDll. This method is invoked when we detect
71    * that condition.
72    */
73   static void OnBareSectionMap(nt::AllocatedUnicodeString&& aSectionName,
74                                const void* aMapBaseAddr, NTSTATUS aMapNtStatus,
75                                ModuleLoadInfo::Status aLoadStatus,
76                                bool aIsDependent);
77 
78  private:
79   // Link to the previous frame
80   ModuleLoadFrame* mPrev;
81   // Pointer to context managed by the nt::LoaderObserver implementation
82   void* mContext;
83   // Set to |true| when we need to block a WinSock LSP
84   bool mLSPSubstitutionRequired;
85   // NTSTATUS code from the |LdrLoadDll| call
86   NTSTATUS mLoadNtStatus;
87   // Telemetry information that will be forwarded to the nt::LoaderObserver
88   ModuleLoadInfo mLoadInfo;
89 
90   // Head of the linked list
91   static SafeThreadLocal<ModuleLoadFrame*> sTopFrame;
92 };
93 
94 }  // namespace freestanding
95 }  // namespace mozilla
96 
97 #endif  // mozilla_freestanding_ModuleLoadFrame_h
98