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/. */
7 #ifndef mozilla_UntrustedModulesData_h
8 #define mozilla_UntrustedModulesData_h
12 # include "ipc/IPCMessageUtils.h"
13 # include "mozilla/CombinedStacks.h"
14 # include "mozilla/DebugOnly.h"
15 # include "mozilla/Maybe.h"
16 # include "mozilla/RefPtr.h"
17 # include "mozilla/TypedEnumBits.h"
18 # include "mozilla/Unused.h"
19 # include "mozilla/Variant.h"
20 # include "mozilla/Vector.h"
21 # include "mozilla/WinHeaderOnlyUtils.h"
22 # include "nsCOMPtr.h"
23 # include "nsHashKeys.h"
25 # include "nsISupportsImpl.h"
26 # include "nsRefPtrHashtable.h"
27 # include "nsString.h"
28 # include "nsXULAppAPI.h"
32 struct EnhancedModuleLoadInfo
;
35 enum class ModuleTrustFlags
: uint32_t {
38 MicrosoftWindowsSignature
= 2,
41 FirefoxDirectoryAndVersion
= 0x10,
42 SystemDirectory
= 0x20,
43 KeyboardLayout
= 0x40,
45 WinSxSDirectory
= 0x100,
48 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ModuleTrustFlags
);
50 class VendorInfo final
{
52 enum class Source
: uint32_t {
58 VendorInfo() : mSource(Source::None
) {}
59 VendorInfo(const Source aSource
, const nsAString
& aVendor
)
60 : mSource(aSource
), mVendor(aVendor
) {
61 MOZ_ASSERT(aSource
!= Source::None
&& !aVendor
.IsEmpty());
70 class ModuleRecord final
{
72 explicit ModuleRecord(const nsAString
& aResolvedNtPath
);
74 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ModuleRecord
)
76 nsString mResolvedNtName
;
77 nsCOMPtr
<nsIFile
> mResolvedDosName
;
78 nsString mSanitizedDllName
;
79 Maybe
<ModuleVersion
> mVersion
;
80 Maybe
<VendorInfo
> mVendorInfo
;
81 ModuleTrustFlags mTrustFlags
;
83 explicit operator bool() const { return !mSanitizedDllName
.IsEmpty(); }
85 bool IsTrusted() const;
87 ModuleRecord(const ModuleRecord
&) = delete;
88 ModuleRecord(ModuleRecord
&&) = delete;
90 ModuleRecord
& operator=(const ModuleRecord
&) = delete;
91 ModuleRecord
& operator=(ModuleRecord
&&) = delete;
95 ~ModuleRecord() = default;
96 void GetVersionAndVendorInfo(const nsAString
& aPath
);
97 int32_t GetScoreThreshold() const;
99 friend struct ::IPC::ParamTraits
<ModulesMap
>;
103 * This type holds module path data using one of two internal representations.
104 * It may be created from either a nsTHashtable or a Vector, and may be
105 * serialized from either representation into a common format over the wire.
106 * Deserialization always uses the Vector representation.
108 struct ModulePaths final
{
109 using SetType
= nsTHashtable
<nsStringCaseInsensitiveHashKey
>;
110 using VecType
= Vector
<nsString
>;
112 Variant
<SetType
, VecType
> mModuleNtPaths
;
114 template <typename T
>
115 explicit ModulePaths(T
&& aPaths
)
116 : mModuleNtPaths(AsVariant(std::forward
<T
>(aPaths
))) {}
118 ModulePaths() : mModuleNtPaths(VecType()) {}
120 ModulePaths(const ModulePaths
& aOther
) = delete;
121 ModulePaths(ModulePaths
&& aOther
) = default;
122 ModulePaths
& operator=(const ModulePaths
&) = delete;
123 ModulePaths
& operator=(ModulePaths
&&) = default;
126 class ProcessedModuleLoadEvent final
{
128 ProcessedModuleLoadEvent();
129 ProcessedModuleLoadEvent(glue::EnhancedModuleLoadInfo
&& aModLoadInfo
,
130 RefPtr
<ModuleRecord
>&& aModuleRecord
);
132 explicit operator bool() const { return mModule
&& *mModule
; }
133 bool IsXULLoad() const;
134 bool IsTrusted() const;
136 uint64_t mProcessUptimeMS
;
137 Maybe
<double> mLoadDurationMS
;
139 nsCString mThreadName
;
140 nsString mRequestedDllName
;
141 // We intentionally store mBaseAddress as part of the event and not the
142 // module, as relocation may cause it to change between loads. If so, we want
144 uintptr_t mBaseAddress
;
145 RefPtr
<ModuleRecord
> mModule
;
147 ProcessedModuleLoadEvent(const ProcessedModuleLoadEvent
&) = delete;
148 ProcessedModuleLoadEvent
& operator=(const ProcessedModuleLoadEvent
&) = delete;
150 ProcessedModuleLoadEvent(ProcessedModuleLoadEvent
&&) = default;
151 ProcessedModuleLoadEvent
& operator=(ProcessedModuleLoadEvent
&&) = default;
154 static Maybe
<LONGLONG
> ComputeQPCTimeStampForProcessCreation();
155 static uint64_t QPCTimeStampToProcessUptimeMilliseconds(
156 const LARGE_INTEGER
& aTimeStamp
);
159 // Declaring ModulesMap this way makes it much easier to forward declare than
160 // if we had used |using| or |typedef|.
161 class ModulesMap final
162 : public nsRefPtrHashtable
<nsStringCaseInsensitiveHashKey
, ModuleRecord
> {
165 : nsRefPtrHashtable
<nsStringCaseInsensitiveHashKey
, ModuleRecord
>() {}
168 class UntrustedModulesData final
{
170 UntrustedModulesData()
171 : mProcessType(XRE_GetProcessType()),
172 mPid(::GetCurrentProcessId()),
173 mSanitizationFailures(0),
174 mTrustTestFailures(0) {}
176 UntrustedModulesData(UntrustedModulesData
&&) = default;
177 UntrustedModulesData
& operator=(UntrustedModulesData
&&) = default;
179 UntrustedModulesData(const UntrustedModulesData
&) = delete;
180 UntrustedModulesData
& operator=(const UntrustedModulesData
&) = delete;
182 explicit operator bool() const {
183 return !mEvents
.empty() || mSanitizationFailures
|| mTrustTestFailures
||
184 mXULLoadDurationMS
.isSome();
187 void AddNewLoads(const ModulesMap
& aModulesMap
,
188 Vector
<ProcessedModuleLoadEvent
>&& aEvents
,
189 Vector
<Telemetry::ProcessedStack
>&& aStacks
);
191 void Swap(UntrustedModulesData
& aOther
);
193 GeckoProcessType mProcessType
;
195 TimeDuration mElapsed
;
197 Vector
<ProcessedModuleLoadEvent
> mEvents
;
198 Telemetry::CombinedStacks mStacks
;
199 Maybe
<double> mXULLoadDurationMS
;
200 uint32_t mSanitizationFailures
;
201 uint32_t mTrustTestFailures
;
204 class ModulesMapResult final
{
206 ModulesMapResult() : mTrustTestFailures(0) {}
208 ModulesMapResult(const ModulesMapResult
& aOther
) = delete;
209 ModulesMapResult(ModulesMapResult
&& aOther
) = default;
210 ModulesMapResult
& operator=(const ModulesMapResult
& aOther
) = delete;
211 ModulesMapResult
& operator=(ModulesMapResult
&& aOther
) = default;
214 uint32_t mTrustTestFailures
;
217 } // namespace mozilla
222 struct ParamTraits
<mozilla::ModuleVersion
> {
223 typedef mozilla::ModuleVersion paramType
;
225 static void Write(Message
* aMsg
, const paramType
& aParam
) {
226 aMsg
->WriteUInt64(aParam
.AsInteger());
229 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
230 paramType
* aResult
) {
232 if (!aMsg
->ReadUInt64(aIter
, &ver
)) {
242 struct ParamTraits
<mozilla::VendorInfo
> {
243 typedef mozilla::VendorInfo paramType
;
245 static void Write(Message
* aMsg
, const paramType
& aParam
) {
246 aMsg
->WriteUInt32(static_cast<uint32_t>(aParam
.mSource
));
247 WriteParam(aMsg
, aParam
.mVendor
);
250 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
251 paramType
* aResult
) {
253 if (!aMsg
->ReadUInt32(aIter
, &source
)) {
257 aResult
->mSource
= static_cast<mozilla::VendorInfo::Source
>(source
);
259 if (!ReadParam(aMsg
, aIter
, &aResult
->mVendor
)) {
268 struct ParamTraits
<mozilla::ModuleRecord
> {
269 typedef mozilla::ModuleRecord paramType
;
271 static void Write(Message
* aMsg
, const paramType
& aParam
) {
272 WriteParam(aMsg
, aParam
.mResolvedNtName
);
274 nsAutoString resolvedDosName
;
275 if (aParam
.mResolvedDosName
) {
276 mozilla::DebugOnly
<nsresult
> rv
=
277 aParam
.mResolvedDosName
->GetPath(resolvedDosName
);
278 MOZ_ASSERT(NS_SUCCEEDED(rv
));
281 WriteParam(aMsg
, resolvedDosName
);
282 WriteParam(aMsg
, aParam
.mSanitizedDllName
);
283 WriteParam(aMsg
, aParam
.mVersion
);
284 WriteParam(aMsg
, aParam
.mVendorInfo
);
285 aMsg
->WriteUInt32(static_cast<uint32_t>(aParam
.mTrustFlags
));
288 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
289 paramType
* aResult
) {
290 if (!ReadParam(aMsg
, aIter
, &aResult
->mResolvedNtName
)) {
294 nsAutoString resolvedDosName
;
295 if (!ReadParam(aMsg
, aIter
, &resolvedDosName
)) {
299 if (resolvedDosName
.IsEmpty()) {
300 aResult
->mResolvedDosName
= nullptr;
301 } else if (NS_FAILED(NS_NewLocalFile(
302 resolvedDosName
, false,
303 getter_AddRefs(aResult
->mResolvedDosName
)))) {
307 if (!ReadParam(aMsg
, aIter
, &aResult
->mSanitizedDllName
)) {
311 if (!ReadParam(aMsg
, aIter
, &aResult
->mVersion
)) {
315 if (!ReadParam(aMsg
, aIter
, &aResult
->mVendorInfo
)) {
320 if (!aMsg
->ReadUInt32(aIter
, &trustFlags
)) {
324 aResult
->mTrustFlags
= static_cast<mozilla::ModuleTrustFlags
>(trustFlags
);
330 struct ParamTraits
<mozilla::ModulesMap
> {
331 typedef mozilla::ModulesMap paramType
;
333 static void Write(Message
* aMsg
, const paramType
& aParam
) {
334 aMsg
->WriteUInt32(aParam
.Count());
336 for (auto iter
= aParam
.ConstIter(); !iter
.Done(); iter
.Next()) {
337 MOZ_RELEASE_ASSERT(iter
.Data());
338 WriteParam(aMsg
, iter
.Key());
339 WriteParam(aMsg
, *(iter
.Data()));
343 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
344 paramType
* aResult
) {
346 if (!ReadParam(aMsg
, aIter
, &count
)) {
350 for (uint32_t current
= 0; current
< count
; ++current
) {
352 if (!ReadParam(aMsg
, aIter
, &key
) || key
.IsEmpty()) {
356 RefPtr
<mozilla::ModuleRecord
> rec(new mozilla::ModuleRecord());
357 if (!ReadParam(aMsg
, aIter
, rec
.get())) {
361 aResult
->Put(key
, rec
.forget());
369 struct ParamTraits
<mozilla::ModulePaths
> {
370 typedef mozilla::ModulePaths paramType
;
372 static void Write(Message
* aMsg
, const paramType
& aParam
) {
373 aParam
.mModuleNtPaths
.match(
374 [aMsg
](const paramType::SetType
& aSet
) { WriteSet(aMsg
, aSet
); },
375 [aMsg
](const paramType::VecType
& aVec
) { WriteVector(aMsg
, aVec
); });
378 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
379 paramType
* aResult
) {
381 if (!aMsg
->ReadUInt32(aIter
, &len
)) {
385 // As noted in the comments for ModulePaths, we only deserialize using the
386 // Vector representation.
387 auto& vec
= aResult
->mModuleNtPaths
.as
<paramType::VecType
>();
388 if (!vec
.reserve(len
)) {
392 for (uint32_t idx
= 0; idx
< len
; ++idx
) {
394 if (!ReadParam(aMsg
, aIter
, &str
)) {
398 if (!vec
.emplaceBack(std::move(str
))) {
407 // NB: This function must write out the set in the same format as WriteVector
408 static void WriteSet(Message
* aMsg
, const paramType::SetType
& aSet
) {
409 aMsg
->WriteUInt32(aSet
.Count());
410 for (auto iter
= aSet
.ConstIter(); !iter
.Done(); iter
.Next()) {
411 WriteParam(aMsg
, iter
.Get()->GetKey());
415 // NB: This function must write out the vector in the same format as WriteSet
416 static void WriteVector(Message
* aMsg
, const paramType::VecType
& aVec
) {
417 aMsg
->WriteUInt32(aVec
.length());
418 for (auto const& item
: aVec
) {
419 WriteParam(aMsg
, item
);
425 struct ParamTraits
<mozilla::UntrustedModulesData
> {
426 typedef mozilla::UntrustedModulesData paramType
;
428 static void Write(Message
* aMsg
, const paramType
& aParam
) {
429 aMsg
->WriteUInt32(aParam
.mProcessType
);
430 aMsg
->WriteULong(aParam
.mPid
);
431 WriteParam(aMsg
, aParam
.mElapsed
);
432 WriteParam(aMsg
, aParam
.mModules
);
434 aMsg
->WriteUInt32(aParam
.mEvents
.length());
435 for (auto& evt
: aParam
.mEvents
) {
436 WriteEvent(aMsg
, evt
);
439 WriteParam(aMsg
, aParam
.mStacks
);
440 WriteParam(aMsg
, aParam
.mXULLoadDurationMS
);
441 aMsg
->WriteUInt32(aParam
.mSanitizationFailures
);
442 aMsg
->WriteUInt32(aParam
.mTrustTestFailures
);
445 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
446 paramType
* aResult
) {
447 uint32_t processType
;
448 if (!aMsg
->ReadUInt32(aIter
, &processType
)) {
452 aResult
->mProcessType
= static_cast<GeckoProcessType
>(processType
);
454 if (!aMsg
->ReadULong(aIter
, &aResult
->mPid
)) {
458 if (!ReadParam(aMsg
, aIter
, &aResult
->mElapsed
)) {
462 if (!ReadParam(aMsg
, aIter
, &aResult
->mModules
)) {
466 // We read mEvents manually so that we can use ReadEvent defined below.
468 if (!ReadParam(aMsg
, aIter
, &eventsLen
)) {
472 if (!aResult
->mEvents
.resize(eventsLen
)) {
476 for (uint32_t curEventIdx
= 0; curEventIdx
< eventsLen
; ++curEventIdx
) {
477 if (!ReadEvent(aMsg
, aIter
, &(aResult
->mEvents
[curEventIdx
]),
478 aResult
->mModules
)) {
483 if (!ReadParam(aMsg
, aIter
, &aResult
->mStacks
)) {
487 if (!ReadParam(aMsg
, aIter
, &aResult
->mXULLoadDurationMS
)) {
491 if (!aMsg
->ReadUInt32(aIter
, &aResult
->mSanitizationFailures
)) {
495 if (!aMsg
->ReadUInt32(aIter
, &aResult
->mTrustTestFailures
)) {
503 // Because ProcessedModuleLoadEvent depends on a hash table from
504 // UntrustedModulesData, we do its serialization as part of this
506 static void WriteEvent(Message
* aMsg
,
507 const mozilla::ProcessedModuleLoadEvent
& aParam
) {
508 aMsg
->WriteUInt64(aParam
.mProcessUptimeMS
);
509 WriteParam(aMsg
, aParam
.mLoadDurationMS
);
510 aMsg
->WriteULong(aParam
.mThreadId
);
511 WriteParam(aMsg
, aParam
.mThreadName
);
512 WriteParam(aMsg
, aParam
.mRequestedDllName
);
513 WriteParam(aMsg
, aParam
.mBaseAddress
);
515 // We don't write the ModuleRecord directly; we write its key into the
516 // UntrustedModulesData::mModules hash table.
517 MOZ_ASSERT(aParam
.mModule
&& !aParam
.mModule
->mResolvedNtName
.IsEmpty());
518 WriteParam(aMsg
, aParam
.mModule
->mResolvedNtName
);
521 // Because ProcessedModuleLoadEvent depends on a hash table from
522 // UntrustedModulesData, we do its deserialization as part of this
524 static bool ReadEvent(const Message
* aMsg
, PickleIterator
* aIter
,
525 mozilla::ProcessedModuleLoadEvent
* aResult
,
526 const mozilla::ModulesMap
& aModulesMap
) {
527 if (!aMsg
->ReadUInt64(aIter
, &aResult
->mProcessUptimeMS
)) {
531 if (!ReadParam(aMsg
, aIter
, &aResult
->mLoadDurationMS
)) {
535 if (!aMsg
->ReadULong(aIter
, &aResult
->mThreadId
)) {
539 if (!ReadParam(aMsg
, aIter
, &aResult
->mThreadName
)) {
543 if (!ReadParam(aMsg
, aIter
, &aResult
->mRequestedDllName
)) {
547 if (!ReadParam(aMsg
, aIter
, &aResult
->mBaseAddress
)) {
551 nsAutoString resolvedNtName
;
552 if (!ReadParam(aMsg
, aIter
, &resolvedNtName
)) {
556 aResult
->mModule
= aModulesMap
.Get(resolvedNtName
);
557 if (!aResult
->mModule
) {
566 struct ParamTraits
<mozilla::ModulesMapResult
> {
567 typedef mozilla::ModulesMapResult paramType
;
569 static void Write(Message
* aMsg
, const paramType
& aParam
) {
570 WriteParam(aMsg
, aParam
.mModules
);
571 aMsg
->WriteUInt32(aParam
.mTrustTestFailures
);
574 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
575 paramType
* aResult
) {
576 if (!ReadParam(aMsg
, aIter
, &aResult
->mModules
)) {
580 if (!aMsg
->ReadUInt32(aIter
, &aResult
->mTrustTestFailures
)) {
590 #else // defined(XP_WIN)
594 // For compiling IPDL on non-Windows platforms
595 using UntrustedModulesData
= uint32_t;
596 using ModulePaths
= uint32_t;
597 using ModulesMapResult
= uint32_t;
599 } // namespace mozilla
601 #endif // defined(XP_WIN)
603 #endif // mozilla_UntrustedModulesData_h