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