1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include <windows.h>
7
8 #include "shared-libraries.h"
9 #include "nsWindowsHelpers.h"
10 #include "mozilla/NativeNt.h"
11 #include "mozilla/WindowsEnumProcessModules.h"
12 #include "mozilla/WindowsProcessMitigations.h"
13 #include "mozilla/WindowsVersion.h"
14 #include "nsPrintfCString.h"
15
IsModuleUnsafeToLoad(const nsAString & aModuleName)16 static bool IsModuleUnsafeToLoad(const nsAString& aModuleName) {
17 #if defined(_M_AMD64) || defined(_M_IX86)
18 // Hackaround for Bug 1607574. Nvidia's shim driver nvd3d9wrap[x].dll detours
19 // LoadLibraryExW and it causes AV when the following conditions are met.
20 // 1. LoadLibraryExW was called for "detoured.dll"
21 // 2. nvinit[x].dll was unloaded
22 // 3. OS version is older than 6.2
23 # if defined(_M_AMD64)
24 LPCWSTR kNvidiaShimDriver = L"nvd3d9wrapx.dll";
25 LPCWSTR kNvidiaInitDriver = L"nvinitx.dll";
26 # elif defined(_M_IX86)
27 LPCWSTR kNvidiaShimDriver = L"nvd3d9wrap.dll";
28 LPCWSTR kNvidiaInitDriver = L"nvinit.dll";
29 # endif
30 if (aModuleName.LowerCaseEqualsLiteral("detoured.dll") &&
31 !mozilla::IsWin8OrLater() && ::GetModuleHandleW(kNvidiaShimDriver) &&
32 !::GetModuleHandleW(kNvidiaInitDriver)) {
33 return true;
34 }
35 #endif // defined(_M_AMD64) || defined(_M_IX86)
36
37 // Hackaround for Bug 1723868. There is no safe way to prevent the module
38 // Microsoft's VP9 Video Decoder from being unloaded because mfplat.dll may
39 // have posted more than one task to unload the module in the work queue
40 // without calling LoadLibrary.
41 if (aModuleName.LowerCaseEqualsLiteral("msvp9dec_store.dll")) {
42 return true;
43 }
44
45 return false;
46 }
47
GetInfoForSelf()48 SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
49 SharedLibraryInfo sharedLibraryInfo;
50
51 auto addSharedLibraryFromModuleInfo = [&sharedLibraryInfo](
52 const wchar_t* aModulePath,
53 HMODULE aModule) {
54 nsDependentSubstring moduleNameStr(
55 mozilla::nt::GetLeafName(nsDependentString(aModulePath)));
56
57 // If the module is unsafe to call LoadLibraryEx for, we skip.
58 if (IsModuleUnsafeToLoad(moduleNameStr)) {
59 return;
60 }
61
62 // If EAF+ is enabled, parsing ntdll's PE header causes a crash.
63 if (mozilla::IsEafPlusEnabled() &&
64 moduleNameStr.LowerCaseEqualsLiteral("ntdll.dll")) {
65 return;
66 }
67
68 // Load the module again to make sure that its handle will remain
69 // valid as we attempt to read the PDB information from it. We load the
70 // DLL as a datafile so that we don't end up running the newly loaded
71 // module's DllMain function. If the original handle |aModule| is valid,
72 // LoadLibraryEx just increments its refcount.
73 // LOAD_LIBRARY_AS_IMAGE_RESOURCE is needed to read information from the
74 // sections (not PE headers) which should be relocated by the loader,
75 // otherwise GetPdbInfo() will cause a crash.
76 nsModuleHandle handleLock(::LoadLibraryExW(
77 aModulePath, NULL,
78 LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE));
79 if (!handleLock) {
80 return;
81 }
82
83 mozilla::nt::PEHeaders headers(handleLock.get());
84 if (!headers) {
85 return;
86 }
87
88 mozilla::Maybe<mozilla::Range<const uint8_t>> bounds = headers.GetBounds();
89 if (!bounds) {
90 return;
91 }
92
93 // Put the original |aModule| into SharedLibrary, but we get debug info
94 // from |handleLock| as |aModule| might be inaccessible.
95 const uintptr_t modStart = reinterpret_cast<uintptr_t>(aModule);
96 const uintptr_t modEnd = modStart + bounds->length();
97
98 nsAutoCString breakpadId;
99 nsAutoString pdbPathStr;
100 if (const auto* debugInfo = headers.GetPdbInfo()) {
101 MOZ_ASSERT(breakpadId.IsEmpty());
102 const GUID& pdbSig = debugInfo->pdbSignature;
103 breakpadId.AppendPrintf(
104 "%08X" // m0
105 "%04X%04X" // m1,m2
106 "%02X%02X%02X%02X%02X%02X%02X%02X" // m3
107 "%X", // pdbAge
108 pdbSig.Data1, pdbSig.Data2, pdbSig.Data3, pdbSig.Data4[0],
109 pdbSig.Data4[1], pdbSig.Data4[2], pdbSig.Data4[3], pdbSig.Data4[4],
110 pdbSig.Data4[5], pdbSig.Data4[6], pdbSig.Data4[7], debugInfo->pdbAge);
111
112 // The PDB file name could be different from module filename,
113 // so report both
114 // e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb
115 pdbPathStr = NS_ConvertUTF8toUTF16(debugInfo->pdbFileName);
116 }
117
118 nsAutoCString versionStr;
119 uint64_t version;
120 if (headers.GetVersionInfo(version)) {
121 versionStr.AppendPrintf("%u.%u.%u.%u",
122 static_cast<uint32_t>((version >> 48) & 0xFFFFu),
123 static_cast<uint32_t>((version >> 32) & 0xFFFFu),
124 static_cast<uint32_t>((version >> 16) & 0xFFFFu),
125 static_cast<uint32_t>(version & 0xFFFFu));
126 }
127
128 const nsString& pdbNameStr =
129 PromiseFlatString(mozilla::nt::GetLeafName(pdbPathStr));
130 SharedLibrary shlib(modStart, modEnd,
131 0, // DLLs are always mapped at offset 0 on Windows
132 breakpadId, PromiseFlatString(moduleNameStr),
133 nsDependentString(aModulePath), pdbNameStr, pdbPathStr,
134 versionStr, "");
135 sharedLibraryInfo.AddSharedLibrary(shlib);
136 };
137
138 mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo);
139 return sharedLibraryInfo;
140 }
141
Initialize()142 void SharedLibraryInfo::Initialize() { /* do nothing */
143 }
144