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 http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_glue_WindowsDllServices_h
8 #define mozilla_glue_WindowsDllServices_h
9 
10 #include <utility>
11 
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Authenticode.h"
14 #include "mozilla/LoaderAPIInterfaces.h"
15 #include "mozilla/UniquePtr.h"
16 #include "mozilla/Vector.h"
17 #include "mozilla/WinHeaderOnlyUtils.h"
18 #include "mozilla/WindowsDllBlocklist.h"
19 #include "mozilla/mozalloc.h"
20 
21 #if defined(MOZILLA_INTERNAL_API)
22 #  include "MainThreadUtils.h"
23 #  include "nsISupportsImpl.h"
24 #  include "nsString.h"
25 #  include "nsThreadUtils.h"
26 #  include "prthread.h"
27 #  include "mozilla/SchedulerGroup.h"
28 #endif  // defined(MOZILLA_INTERNAL_API)
29 
30 // For PCUNICODE_STRING
31 #include <winternl.h>
32 
33 namespace mozilla {
34 namespace glue {
35 namespace detail {
36 
37 class DllServicesBase : public Authenticode {
38  public:
39   /**
40    * WARNING: This method is called from within an unsafe context that holds
41    *          multiple locks inside the Windows loader. The only thing that
42    *          this function should be used for is dispatching the event to our
43    *          event loop so that it may be handled in a safe context.
44    */
45   virtual void DispatchDllLoadNotification(ModuleLoadInfo&& aModLoadInfo) = 0;
46 
47   /**
48    * This function accepts module load events to be processed later for
49    * the untrusted modules telemetry ping.
50    *
51    * WARNING: This method is run from within the Windows loader and should
52    *          only perform trivial, loader-friendly operations.
53    */
54   virtual void DispatchModuleLoadBacklogNotification(
55       ModuleLoadInfoVec&& aEvents) = 0;
56 
SetAuthenticodeImpl(Authenticode * aAuthenticode)57   void SetAuthenticodeImpl(Authenticode* aAuthenticode) {
58     mAuthenticode = aAuthenticode;
59   }
60 
SetWinLauncherFunctions(const nt::WinLauncherFunctions & aFunctions)61   void SetWinLauncherFunctions(const nt::WinLauncherFunctions& aFunctions) {
62     mWinLauncherFunctions = aFunctions;
63   }
64 
65   template <typename... Args>
InitDllBlocklistOOP(Args &&...aArgs)66   LauncherVoidResultWithLineInfo InitDllBlocklistOOP(Args&&... aArgs) {
67     MOZ_RELEASE_ASSERT(mWinLauncherFunctions.mInitDllBlocklistOOP);
68     return mWinLauncherFunctions.mInitDllBlocklistOOP(
69         std::forward<Args>(aArgs)...);
70   }
71 
72   template <typename... Args>
HandleLauncherError(Args &&...aArgs)73   void HandleLauncherError(Args&&... aArgs) {
74     MOZ_RELEASE_ASSERT(mWinLauncherFunctions.mHandleLauncherError);
75     mWinLauncherFunctions.mHandleLauncherError(std::forward<Args>(aArgs)...);
76   }
77 
78   // In debug builds we override GetBinaryOrgName to add a Gecko-specific
79   // assertion. OTOH, we normally do not want people overriding this function,
80   // so we'll make it final in the release case, thus covering all bases.
81 #if defined(DEBUG)
82   UniquePtr<wchar_t[]> GetBinaryOrgName(
83       const wchar_t* aFilePath,
84       AuthenticodeFlags aFlags = AuthenticodeFlags::Default) override
85 #else
86   UniquePtr<wchar_t[]> GetBinaryOrgName(
87       const wchar_t* aFilePath,
88       AuthenticodeFlags aFlags = AuthenticodeFlags::Default) final
89 #endif  // defined(DEBUG)
90   {
91     if (!mAuthenticode) {
92       return nullptr;
93     }
94 
95     return mAuthenticode->GetBinaryOrgName(aFilePath, aFlags);
96   }
97 
DisableFull()98   virtual void DisableFull() { DllBlocklist_SetFullDllServices(nullptr); }
99 
100   DllServicesBase(const DllServicesBase&) = delete;
101   DllServicesBase(DllServicesBase&&) = delete;
102   DllServicesBase& operator=(const DllServicesBase&) = delete;
103   DllServicesBase& operator=(DllServicesBase&&) = delete;
104 
105  protected:
DllServicesBase()106   DllServicesBase() : mAuthenticode(nullptr) {}
107 
108   virtual ~DllServicesBase() = default;
109 
EnableFull()110   void EnableFull() { DllBlocklist_SetFullDllServices(this); }
EnableBasic()111   void EnableBasic() { DllBlocklist_SetBasicDllServices(this); }
112 
113  private:
114   Authenticode* mAuthenticode;
115   nt::WinLauncherFunctions mWinLauncherFunctions;
116 };
117 
118 }  // namespace detail
119 
120 #if defined(MOZILLA_INTERNAL_API)
121 
122 struct EnhancedModuleLoadInfo final {
EnhancedModuleLoadInfofinal123   explicit EnhancedModuleLoadInfo(ModuleLoadInfo&& aModLoadInfo)
124       : mNtLoadInfo(std::move(aModLoadInfo)) {
125     // Only populate mThreadName when we're on the same thread as the event
126     if (mNtLoadInfo.mThreadId == ::GetCurrentThreadId()) {
127       mThreadName = PR_GetThreadName(PR_GetCurrentThread());
128     }
129     MOZ_ASSERT(!mNtLoadInfo.mSectionName.IsEmpty());
130   }
131 
132   EnhancedModuleLoadInfo(EnhancedModuleLoadInfo&&) = default;
133   EnhancedModuleLoadInfo& operator=(EnhancedModuleLoadInfo&&) = default;
134 
135   EnhancedModuleLoadInfo(const EnhancedModuleLoadInfo&) = delete;
136   EnhancedModuleLoadInfo& operator=(const EnhancedModuleLoadInfo&) = delete;
137 
GetSectionNamefinal138   nsDependentString GetSectionName() const {
139     return mNtLoadInfo.mSectionName.AsString();
140   }
141 
142   using BacktraceType = decltype(ModuleLoadInfo::mBacktrace);
143 
144   ModuleLoadInfo mNtLoadInfo;
145   nsCString mThreadName;
146 };
147 
148 class DllServices : public detail::DllServicesBase {
149  public:
DispatchDllLoadNotification(ModuleLoadInfo && aModLoadInfo)150   void DispatchDllLoadNotification(ModuleLoadInfo&& aModLoadInfo) final {
151     nsCOMPtr<nsIRunnable> runnable(
152         NewRunnableMethod<StoreCopyPassByRRef<EnhancedModuleLoadInfo>>(
153             "DllServices::NotifyDllLoad", this, &DllServices::NotifyDllLoad,
154             std::move(aModLoadInfo)));
155 
156     SchedulerGroup::Dispatch(TaskCategory::Other, runnable.forget());
157   }
158 
DispatchModuleLoadBacklogNotification(ModuleLoadInfoVec && aEvents)159   void DispatchModuleLoadBacklogNotification(
160       ModuleLoadInfoVec&& aEvents) final {
161     nsCOMPtr<nsIRunnable> runnable(
162         NewRunnableMethod<StoreCopyPassByRRef<ModuleLoadInfoVec>>(
163             "DllServices::NotifyModuleLoadBacklog", this,
164             &DllServices::NotifyModuleLoadBacklog, std::move(aEvents)));
165 
166     SchedulerGroup::Dispatch(TaskCategory::Other, runnable.forget());
167   }
168 
169 #  if defined(DEBUG)
170   UniquePtr<wchar_t[]> GetBinaryOrgName(
171       const wchar_t* aFilePath,
172       AuthenticodeFlags aFlags = AuthenticodeFlags::Default) final {
173     // This function may perform disk I/O, so we should never call it on the
174     // main thread.
175     MOZ_ASSERT(!NS_IsMainThread());
176     return detail::DllServicesBase::GetBinaryOrgName(aFilePath, aFlags);
177   }
178 #  endif  // defined(DEBUG)
179 
180   NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(DllServices)
181 
182  protected:
183   DllServices() = default;
184   ~DllServices() = default;
185 
186   virtual void NotifyDllLoad(EnhancedModuleLoadInfo&& aModLoadInfo) = 0;
187   virtual void NotifyModuleLoadBacklog(ModuleLoadInfoVec&& aEvents) = 0;
188 };
189 
190 #else
191 
192 class BasicDllServices final : public detail::DllServicesBase {
193  public:
BasicDllServices()194   BasicDllServices() { EnableBasic(); }
195 
196   ~BasicDllServices() = default;
197 
198   // Not useful in this class, so provide a default implementation
DispatchDllLoadNotification(ModuleLoadInfo && aModLoadInfo)199   virtual void DispatchDllLoadNotification(
200       ModuleLoadInfo&& aModLoadInfo) override {}
201 
DispatchModuleLoadBacklogNotification(ModuleLoadInfoVec && aEvents)202   virtual void DispatchModuleLoadBacklogNotification(
203       ModuleLoadInfoVec&& aEvents) override {}
204 };
205 
206 #endif  // defined(MOZILLA_INTERNAL_API)
207 
208 }  // namespace glue
209 }  // namespace mozilla
210 
211 #endif  // mozilla_glue_WindowsDllServices_h
212