/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 http://mozilla.org/MPL/2.0/. */ #include #include "shared-libraries.h" #include "nsWindowsHelpers.h" #include "mozilla/NativeNt.h" #include "mozilla/WindowsEnumProcessModules.h" #include "mozilla/WindowsProcessMitigations.h" #include "nsPrintfCString.h" static bool IsModuleUnsafeToLoad(const nsAString& aModuleName) { // Hackaround for Bug 1723868. There is no safe way to prevent the module // Microsoft's VP9 Video Decoder from being unloaded because mfplat.dll may // have posted more than one task to unload the module in the work queue // without calling LoadLibrary. if (aModuleName.LowerCaseEqualsLiteral("msvp9dec_store.dll")) { return true; } return false; } void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo, const wchar_t* aModulePath, mozilla::Maybe aModule) { nsDependentSubstring moduleNameStr( mozilla::nt::GetLeafName(nsDependentString(aModulePath))); // If the module is unsafe to call LoadLibraryEx for, we skip. if (IsModuleUnsafeToLoad(moduleNameStr)) { return; } // If EAF+ is enabled, parsing ntdll's PE header causes a crash. if (mozilla::IsEafPlusEnabled() && moduleNameStr.LowerCaseEqualsLiteral("ntdll.dll")) { return; } // Load the module again - to make sure that its handle will remain valid as // we attempt to read the PDB information from it - or for the first time if // we only have a path. We want to load the DLL without running the newly // loaded module's DllMain function, but not as a data file because we want // to be able to do RVA computations easily. Hence, we use the flag // LOAD_LIBRARY_AS_IMAGE_RESOURCE which ensures that the sections (not PE // headers) will be relocated by the loader. Otherwise GetPdbInfo() and/or // GetVersionInfo() can cause a crash. If the original handle |aModule| is // valid, LoadLibraryEx just increments its refcount. nsModuleHandle handleLock( ::LoadLibraryExW(aModulePath, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE)); if (!handleLock) { return; } mozilla::nt::PEHeaders headers(handleLock.get()); if (!headers) { return; } mozilla::Maybe> bounds = headers.GetBounds(); if (!bounds) { return; } // Put the original |aModule| into SharedLibrary, but we get debug info // from |handleLock| as |aModule| might be inaccessible. const uintptr_t modStart = aModule.isSome() ? reinterpret_cast(*aModule) : reinterpret_cast(handleLock.get()); const uintptr_t modEnd = modStart + bounds->length(); nsAutoCString breakpadId; nsAutoString pdbPathStr; if (const auto* debugInfo = headers.GetPdbInfo()) { MOZ_ASSERT(breakpadId.IsEmpty()); const GUID& pdbSig = debugInfo->pdbSignature; breakpadId.AppendPrintf( "%08lX" // m0 "%04X%04X" // m1,m2 "%02X%02X%02X%02X%02X%02X%02X%02X" // m3 "%X", // pdbAge pdbSig.Data1, pdbSig.Data2, pdbSig.Data3, pdbSig.Data4[0], pdbSig.Data4[1], pdbSig.Data4[2], pdbSig.Data4[3], pdbSig.Data4[4], pdbSig.Data4[5], pdbSig.Data4[6], pdbSig.Data4[7], debugInfo->pdbAge); // The PDB file name could be different from module filename, // so report both // e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb pdbPathStr = NS_ConvertUTF8toUTF16(debugInfo->pdbFileName); } nsAutoCString codeId; DWORD timestamp; DWORD imageSize; if (headers.GetTimeStamp(timestamp) && headers.GetImageSize(imageSize)) { codeId.AppendPrintf( "%08lX" // Uppercase 8 digits of hex timestamp with leading zeroes. "%lx", // Lowercase hex image size timestamp, imageSize); } nsAutoCString versionStr; uint64_t version; if (headers.GetVersionInfo(version)) { versionStr.AppendPrintf("%u.%u.%u.%u", static_cast((version >> 48) & 0xFFFFu), static_cast((version >> 32) & 0xFFFFu), static_cast((version >> 16) & 0xFFFFu), static_cast(version & 0xFFFFu)); } const nsString& pdbNameStr = PromiseFlatString(mozilla::nt::GetLeafName(pdbPathStr)); SharedLibrary shlib(modStart, modEnd, 0, // DLLs are always mapped at offset 0 on Windows breakpadId, codeId, PromiseFlatString(moduleNameStr), nsDependentString(aModulePath), pdbNameStr, pdbPathStr, versionStr, ""); sharedLibraryInfo.AddSharedLibrary(shlib); } SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() { SharedLibraryInfo sharedLibraryInfo; auto addSharedLibraryFromModuleInfo = [&sharedLibraryInfo](const wchar_t* aModulePath, HMODULE aModule) { AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aModulePath, mozilla::Some(aModule)); }; mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo); return sharedLibraryInfo; } SharedLibraryInfo SharedLibraryInfo::GetInfoFromPath(const wchar_t* aPath) { SharedLibraryInfo sharedLibraryInfo; AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aPath, mozilla::Nothing()); return sharedLibraryInfo; } void SharedLibraryInfo::Initialize() { /* do nothing */ }