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 uint32_t mLoadStatus
; // corresponding to enum ModuleLoadInfo::Status
149 ProcessedModuleLoadEvent(const ProcessedModuleLoadEvent
&) = delete;
150 ProcessedModuleLoadEvent
& operator=(const ProcessedModuleLoadEvent
&) = delete;
152 ProcessedModuleLoadEvent(ProcessedModuleLoadEvent
&&) = default;
153 ProcessedModuleLoadEvent
& operator=(ProcessedModuleLoadEvent
&&) = default;
156 static Maybe
<LONGLONG
> ComputeQPCTimeStampForProcessCreation();
157 static uint64_t QPCTimeStampToProcessUptimeMilliseconds(
158 const LARGE_INTEGER
& aTimeStamp
);
161 // Declaring ModulesMap this way makes it much easier to forward declare than
162 // if we had used |using| or |typedef|.
163 class ModulesMap final
164 : public nsRefPtrHashtable
<nsStringCaseInsensitiveHashKey
, ModuleRecord
> {
167 : nsRefPtrHashtable
<nsStringCaseInsensitiveHashKey
, ModuleRecord
>() {}
170 class UntrustedModulesData final
{
172 UntrustedModulesData()
173 : mProcessType(XRE_GetProcessType()),
174 mPid(::GetCurrentProcessId()),
175 mSanitizationFailures(0),
176 mTrustTestFailures(0) {}
178 UntrustedModulesData(UntrustedModulesData
&&) = default;
179 UntrustedModulesData
& operator=(UntrustedModulesData
&&) = default;
181 UntrustedModulesData(const UntrustedModulesData
&) = delete;
182 UntrustedModulesData
& operator=(const UntrustedModulesData
&) = delete;
184 explicit operator bool() const {
185 return !mEvents
.empty() || mSanitizationFailures
|| mTrustTestFailures
||
186 mXULLoadDurationMS
.isSome();
189 void AddNewLoads(const ModulesMap
& aModulesMap
,
190 Vector
<ProcessedModuleLoadEvent
>&& aEvents
,
191 Vector
<Telemetry::ProcessedStack
>&& aStacks
);
192 void Merge(UntrustedModulesData
&& aNewData
);
194 void Swap(UntrustedModulesData
& aOther
);
196 GeckoProcessType mProcessType
;
198 TimeDuration mElapsed
;
200 Vector
<ProcessedModuleLoadEvent
> mEvents
;
201 Telemetry::CombinedStacks mStacks
;
202 Maybe
<double> mXULLoadDurationMS
;
203 uint32_t mSanitizationFailures
;
204 uint32_t mTrustTestFailures
;
207 class ModulesMapResult final
{
209 ModulesMapResult() : mTrustTestFailures(0) {}
211 ModulesMapResult(const ModulesMapResult
& aOther
) = delete;
212 ModulesMapResult(ModulesMapResult
&& aOther
) = default;
213 ModulesMapResult
& operator=(const ModulesMapResult
& aOther
) = delete;
214 ModulesMapResult
& operator=(ModulesMapResult
&& aOther
) = default;
217 uint32_t mTrustTestFailures
;
220 } // namespace mozilla
225 struct ParamTraits
<mozilla::ModuleVersion
> {
226 typedef mozilla::ModuleVersion paramType
;
228 static void Write(Message
* aMsg
, const paramType
& aParam
) {
229 aMsg
->WriteUInt64(aParam
.AsInteger());
232 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
233 paramType
* aResult
) {
235 if (!aMsg
->ReadUInt64(aIter
, &ver
)) {
245 struct ParamTraits
<mozilla::VendorInfo
> {
246 typedef mozilla::VendorInfo paramType
;
248 static void Write(Message
* aMsg
, const paramType
& aParam
) {
249 aMsg
->WriteUInt32(static_cast<uint32_t>(aParam
.mSource
));
250 WriteParam(aMsg
, aParam
.mVendor
);
253 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
254 paramType
* aResult
) {
256 if (!aMsg
->ReadUInt32(aIter
, &source
)) {
260 aResult
->mSource
= static_cast<mozilla::VendorInfo::Source
>(source
);
262 if (!ReadParam(aMsg
, aIter
, &aResult
->mVendor
)) {
271 struct ParamTraits
<mozilla::ModuleRecord
> {
272 typedef mozilla::ModuleRecord paramType
;
274 static void Write(Message
* aMsg
, const paramType
& aParam
) {
275 WriteParam(aMsg
, aParam
.mResolvedNtName
);
277 nsAutoString resolvedDosName
;
278 if (aParam
.mResolvedDosName
) {
279 mozilla::DebugOnly
<nsresult
> rv
=
280 aParam
.mResolvedDosName
->GetPath(resolvedDosName
);
281 MOZ_ASSERT(NS_SUCCEEDED(rv
));
284 WriteParam(aMsg
, resolvedDosName
);
285 WriteParam(aMsg
, aParam
.mSanitizedDllName
);
286 WriteParam(aMsg
, aParam
.mVersion
);
287 WriteParam(aMsg
, aParam
.mVendorInfo
);
288 aMsg
->WriteUInt32(static_cast<uint32_t>(aParam
.mTrustFlags
));
291 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
292 paramType
* aResult
) {
293 if (!ReadParam(aMsg
, aIter
, &aResult
->mResolvedNtName
)) {
297 nsAutoString resolvedDosName
;
298 if (!ReadParam(aMsg
, aIter
, &resolvedDosName
)) {
302 if (resolvedDosName
.IsEmpty()) {
303 aResult
->mResolvedDosName
= nullptr;
304 } else if (NS_FAILED(NS_NewLocalFile(
305 resolvedDosName
, false,
306 getter_AddRefs(aResult
->mResolvedDosName
)))) {
310 if (!ReadParam(aMsg
, aIter
, &aResult
->mSanitizedDllName
)) {
314 if (!ReadParam(aMsg
, aIter
, &aResult
->mVersion
)) {
318 if (!ReadParam(aMsg
, aIter
, &aResult
->mVendorInfo
)) {
323 if (!aMsg
->ReadUInt32(aIter
, &trustFlags
)) {
327 aResult
->mTrustFlags
= static_cast<mozilla::ModuleTrustFlags
>(trustFlags
);
333 struct ParamTraits
<mozilla::ModulesMap
> {
334 typedef mozilla::ModulesMap paramType
;
336 static void Write(Message
* aMsg
, const paramType
& aParam
) {
337 aMsg
->WriteUInt32(aParam
.Count());
339 for (const auto& entry
: aParam
) {
340 MOZ_RELEASE_ASSERT(entry
.GetData());
341 WriteParam(aMsg
, entry
.GetKey());
342 WriteParam(aMsg
, *(entry
.GetData()));
346 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
347 paramType
* aResult
) {
349 if (!ReadParam(aMsg
, aIter
, &count
)) {
353 for (uint32_t current
= 0; current
< count
; ++current
) {
355 if (!ReadParam(aMsg
, aIter
, &key
) || key
.IsEmpty()) {
359 RefPtr
<mozilla::ModuleRecord
> rec(new mozilla::ModuleRecord());
360 if (!ReadParam(aMsg
, aIter
, rec
.get())) {
364 aResult
->InsertOrUpdate(key
, std::move(rec
));
372 struct ParamTraits
<mozilla::ModulePaths
> {
373 typedef mozilla::ModulePaths paramType
;
375 static void Write(Message
* aMsg
, const paramType
& aParam
) {
376 aParam
.mModuleNtPaths
.match(
377 [aMsg
](const paramType::SetType
& aSet
) { WriteSet(aMsg
, aSet
); },
378 [aMsg
](const paramType::VecType
& aVec
) { WriteVector(aMsg
, aVec
); });
381 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
382 paramType
* aResult
) {
384 if (!aMsg
->ReadUInt32(aIter
, &len
)) {
388 // As noted in the comments for ModulePaths, we only deserialize using the
389 // Vector representation.
390 auto& vec
= aResult
->mModuleNtPaths
.as
<paramType::VecType
>();
391 if (!vec
.reserve(len
)) {
395 for (uint32_t idx
= 0; idx
< len
; ++idx
) {
397 if (!ReadParam(aMsg
, aIter
, &str
)) {
401 if (!vec
.emplaceBack(std::move(str
))) {
410 // NB: This function must write out the set in the same format as WriteVector
411 static void WriteSet(Message
* aMsg
, const paramType::SetType
& aSet
) {
412 aMsg
->WriteUInt32(aSet
.Count());
413 for (const auto& key
: aSet
.Keys()) {
414 WriteParam(aMsg
, key
);
418 // NB: This function must write out the vector in the same format as WriteSet
419 static void WriteVector(Message
* aMsg
, const paramType::VecType
& aVec
) {
420 aMsg
->WriteUInt32(aVec
.length());
421 for (auto const& item
: aVec
) {
422 WriteParam(aMsg
, item
);
428 struct ParamTraits
<mozilla::UntrustedModulesData
> {
429 typedef mozilla::UntrustedModulesData paramType
;
431 static void Write(Message
* aMsg
, const paramType
& aParam
) {
432 aMsg
->WriteUInt32(aParam
.mProcessType
);
433 aMsg
->WriteULong(aParam
.mPid
);
434 WriteParam(aMsg
, aParam
.mElapsed
);
435 WriteParam(aMsg
, aParam
.mModules
);
437 aMsg
->WriteUInt32(aParam
.mEvents
.length());
438 for (auto& evt
: aParam
.mEvents
) {
439 WriteEvent(aMsg
, evt
);
442 WriteParam(aMsg
, aParam
.mStacks
);
443 WriteParam(aMsg
, aParam
.mXULLoadDurationMS
);
444 aMsg
->WriteUInt32(aParam
.mSanitizationFailures
);
445 aMsg
->WriteUInt32(aParam
.mTrustTestFailures
);
448 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
449 paramType
* aResult
) {
450 uint32_t processType
;
451 if (!aMsg
->ReadUInt32(aIter
, &processType
)) {
455 aResult
->mProcessType
= static_cast<GeckoProcessType
>(processType
);
457 if (!aMsg
->ReadULong(aIter
, &aResult
->mPid
)) {
461 if (!ReadParam(aMsg
, aIter
, &aResult
->mElapsed
)) {
465 if (!ReadParam(aMsg
, aIter
, &aResult
->mModules
)) {
469 // We read mEvents manually so that we can use ReadEvent defined below.
471 if (!ReadParam(aMsg
, aIter
, &eventsLen
)) {
475 if (!aResult
->mEvents
.resize(eventsLen
)) {
479 for (uint32_t curEventIdx
= 0; curEventIdx
< eventsLen
; ++curEventIdx
) {
480 if (!ReadEvent(aMsg
, aIter
, &(aResult
->mEvents
[curEventIdx
]),
481 aResult
->mModules
)) {
486 if (!ReadParam(aMsg
, aIter
, &aResult
->mStacks
)) {
490 if (!ReadParam(aMsg
, aIter
, &aResult
->mXULLoadDurationMS
)) {
494 if (!aMsg
->ReadUInt32(aIter
, &aResult
->mSanitizationFailures
)) {
498 if (!aMsg
->ReadUInt32(aIter
, &aResult
->mTrustTestFailures
)) {
506 // Because ProcessedModuleLoadEvent depends on a hash table from
507 // UntrustedModulesData, we do its serialization as part of this
509 static void WriteEvent(Message
* aMsg
,
510 const mozilla::ProcessedModuleLoadEvent
& aParam
) {
511 aMsg
->WriteUInt64(aParam
.mProcessUptimeMS
);
512 WriteParam(aMsg
, aParam
.mLoadDurationMS
);
513 aMsg
->WriteULong(aParam
.mThreadId
);
514 WriteParam(aMsg
, aParam
.mThreadName
);
515 WriteParam(aMsg
, aParam
.mRequestedDllName
);
516 WriteParam(aMsg
, aParam
.mBaseAddress
);
517 WriteParam(aMsg
, aParam
.mIsDependent
);
518 WriteParam(aMsg
, aParam
.mLoadStatus
);
520 // We don't write the ModuleRecord directly; we write its key into the
521 // UntrustedModulesData::mModules hash table.
522 MOZ_ASSERT(aParam
.mModule
&& !aParam
.mModule
->mResolvedNtName
.IsEmpty());
523 WriteParam(aMsg
, aParam
.mModule
->mResolvedNtName
);
526 // Because ProcessedModuleLoadEvent depends on a hash table from
527 // UntrustedModulesData, we do its deserialization as part of this
529 static bool ReadEvent(const Message
* aMsg
, PickleIterator
* aIter
,
530 mozilla::ProcessedModuleLoadEvent
* aResult
,
531 const mozilla::ModulesMap
& aModulesMap
) {
532 if (!aMsg
->ReadUInt64(aIter
, &aResult
->mProcessUptimeMS
)) {
536 if (!ReadParam(aMsg
, aIter
, &aResult
->mLoadDurationMS
)) {
540 if (!aMsg
->ReadULong(aIter
, &aResult
->mThreadId
)) {
544 if (!ReadParam(aMsg
, aIter
, &aResult
->mThreadName
)) {
548 if (!ReadParam(aMsg
, aIter
, &aResult
->mRequestedDllName
)) {
552 if (!ReadParam(aMsg
, aIter
, &aResult
->mBaseAddress
)) {
556 if (!ReadParam(aMsg
, aIter
, &aResult
->mIsDependent
)) {
560 if (!ReadParam(aMsg
, aIter
, &aResult
->mLoadStatus
)) {
564 nsAutoString resolvedNtName
;
565 if (!ReadParam(aMsg
, aIter
, &resolvedNtName
)) {
569 // NB: While bad data integrity might for some reason result in a null
570 // mModule, we do not fail the deserialization; this is a data error,
571 // rather than an IPC error. The error is detected and dealt with in
573 aResult
->mModule
= aModulesMap
.Get(resolvedNtName
);
580 struct ParamTraits
<mozilla::ModulesMapResult
> {
581 typedef mozilla::ModulesMapResult paramType
;
583 static void Write(Message
* aMsg
, const paramType
& aParam
) {
584 WriteParam(aMsg
, aParam
.mModules
);
585 aMsg
->WriteUInt32(aParam
.mTrustTestFailures
);
588 static bool Read(const Message
* aMsg
, PickleIterator
* aIter
,
589 paramType
* aResult
) {
590 if (!ReadParam(aMsg
, aIter
, &aResult
->mModules
)) {
594 if (!aMsg
->ReadUInt32(aIter
, &aResult
->mTrustTestFailures
)) {
604 #else // defined(XP_WIN)
608 // For compiling IPDL on non-Windows platforms
609 using UntrustedModulesData
= uint32_t;
610 using ModulePaths
= uint32_t;
611 using ModulesMapResult
= uint32_t;
613 } // namespace mozilla
615 #endif // defined(XP_WIN)
617 #endif // mozilla_UntrustedModulesData_h