Bug 1708422: part 13) Factor code out to `mozInlineSpellChecker::SpellCheckerTimeSlic...
[gecko.git] / toolkit / xre / UntrustedModulesData.h
blob6cd095b91335ff18d9ef631e5123c95adad5b907
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
10 #if defined(XP_WIN)
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"
24 # include "nsIFile.h"
25 # include "nsISupportsImpl.h"
26 # include "nsRefPtrHashtable.h"
27 # include "nsString.h"
28 # include "nsXULAppAPI.h"
30 namespace mozilla {
31 namespace glue {
32 struct EnhancedModuleLoadInfo;
33 } // namespace glue
35 enum class ModuleTrustFlags : uint32_t {
36 None = 0,
37 MozillaSignature = 1,
38 MicrosoftWindowsSignature = 2,
39 MicrosoftVersion = 4,
40 FirefoxDirectory = 8,
41 FirefoxDirectoryAndVersion = 0x10,
42 SystemDirectory = 0x20,
43 KeyboardLayout = 0x40,
44 JitPI = 0x80,
45 WinSxSDirectory = 0x100,
48 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ModuleTrustFlags);
50 class VendorInfo final {
51 public:
52 enum class Source : uint32_t {
53 None,
54 Signature,
55 VersionInfo,
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());
64 Source mSource;
65 nsString mVendor;
68 class ModulesMap;
70 class ModuleRecord final {
71 public:
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(); }
84 bool IsXUL() const;
85 bool IsTrusted() const;
87 ModuleRecord(const ModuleRecord&) = delete;
88 ModuleRecord(ModuleRecord&&) = delete;
90 ModuleRecord& operator=(const ModuleRecord&) = delete;
91 ModuleRecord& operator=(ModuleRecord&&) = delete;
93 private:
94 ModuleRecord();
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 {
127 public:
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;
138 DWORD mThreadId;
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
143 // to know about it.
144 uintptr_t mBaseAddress;
145 RefPtr<ModuleRecord> mModule;
146 bool mIsDependent;
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;
155 private:
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> {
165 public:
166 ModulesMap()
167 : nsRefPtrHashtable<nsStringCaseInsensitiveHashKey, ModuleRecord>() {}
170 class UntrustedModulesData final {
171 public:
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;
197 DWORD mPid;
198 TimeDuration mElapsed;
199 ModulesMap mModules;
200 Vector<ProcessedModuleLoadEvent> mEvents;
201 Telemetry::CombinedStacks mStacks;
202 Maybe<double> mXULLoadDurationMS;
203 uint32_t mSanitizationFailures;
204 uint32_t mTrustTestFailures;
207 class ModulesMapResult final {
208 public:
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;
216 ModulesMap mModules;
217 uint32_t mTrustTestFailures;
220 } // namespace mozilla
222 namespace IPC {
224 template <>
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) {
234 uint64_t ver;
235 if (!aMsg->ReadUInt64(aIter, &ver)) {
236 return false;
239 *aResult = ver;
240 return true;
244 template <>
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) {
255 uint32_t source;
256 if (!aMsg->ReadUInt32(aIter, &source)) {
257 return false;
260 aResult->mSource = static_cast<mozilla::VendorInfo::Source>(source);
262 if (!ReadParam(aMsg, aIter, &aResult->mVendor)) {
263 return false;
266 return true;
270 template <>
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)) {
294 return false;
297 nsAutoString resolvedDosName;
298 if (!ReadParam(aMsg, aIter, &resolvedDosName)) {
299 return false;
302 if (resolvedDosName.IsEmpty()) {
303 aResult->mResolvedDosName = nullptr;
304 } else if (NS_FAILED(NS_NewLocalFile(
305 resolvedDosName, false,
306 getter_AddRefs(aResult->mResolvedDosName)))) {
307 return false;
310 if (!ReadParam(aMsg, aIter, &aResult->mSanitizedDllName)) {
311 return false;
314 if (!ReadParam(aMsg, aIter, &aResult->mVersion)) {
315 return false;
318 if (!ReadParam(aMsg, aIter, &aResult->mVendorInfo)) {
319 return false;
322 uint32_t trustFlags;
323 if (!aMsg->ReadUInt32(aIter, &trustFlags)) {
324 return false;
327 aResult->mTrustFlags = static_cast<mozilla::ModuleTrustFlags>(trustFlags);
328 return true;
332 template <>
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) {
348 uint32_t count;
349 if (!ReadParam(aMsg, aIter, &count)) {
350 return false;
353 for (uint32_t current = 0; current < count; ++current) {
354 nsAutoString key;
355 if (!ReadParam(aMsg, aIter, &key) || key.IsEmpty()) {
356 return false;
359 RefPtr<mozilla::ModuleRecord> rec(new mozilla::ModuleRecord());
360 if (!ReadParam(aMsg, aIter, rec.get())) {
361 return false;
364 aResult->InsertOrUpdate(key, std::move(rec));
367 return true;
371 template <>
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) {
383 uint32_t len;
384 if (!aMsg->ReadUInt32(aIter, &len)) {
385 return false;
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)) {
392 return false;
395 for (uint32_t idx = 0; idx < len; ++idx) {
396 nsString str;
397 if (!ReadParam(aMsg, aIter, &str)) {
398 return false;
401 if (!vec.emplaceBack(std::move(str))) {
402 return false;
406 return true;
409 private:
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);
427 template <>
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)) {
452 return false;
455 aResult->mProcessType = static_cast<GeckoProcessType>(processType);
457 if (!aMsg->ReadULong(aIter, &aResult->mPid)) {
458 return false;
461 if (!ReadParam(aMsg, aIter, &aResult->mElapsed)) {
462 return false;
465 if (!ReadParam(aMsg, aIter, &aResult->mModules)) {
466 return false;
469 // We read mEvents manually so that we can use ReadEvent defined below.
470 uint32_t eventsLen;
471 if (!ReadParam(aMsg, aIter, &eventsLen)) {
472 return false;
475 if (!aResult->mEvents.resize(eventsLen)) {
476 return false;
479 for (uint32_t curEventIdx = 0; curEventIdx < eventsLen; ++curEventIdx) {
480 if (!ReadEvent(aMsg, aIter, &(aResult->mEvents[curEventIdx]),
481 aResult->mModules)) {
482 return false;
486 if (!ReadParam(aMsg, aIter, &aResult->mStacks)) {
487 return false;
490 if (!ReadParam(aMsg, aIter, &aResult->mXULLoadDurationMS)) {
491 return false;
494 if (!aMsg->ReadUInt32(aIter, &aResult->mSanitizationFailures)) {
495 return false;
498 if (!aMsg->ReadUInt32(aIter, &aResult->mTrustTestFailures)) {
499 return false;
502 return true;
505 private:
506 // Because ProcessedModuleLoadEvent depends on a hash table from
507 // UntrustedModulesData, we do its serialization as part of this
508 // specialization.
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
528 // specialization.
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)) {
533 return false;
536 if (!ReadParam(aMsg, aIter, &aResult->mLoadDurationMS)) {
537 return false;
540 if (!aMsg->ReadULong(aIter, &aResult->mThreadId)) {
541 return false;
544 if (!ReadParam(aMsg, aIter, &aResult->mThreadName)) {
545 return false;
548 if (!ReadParam(aMsg, aIter, &aResult->mRequestedDllName)) {
549 return false;
552 if (!ReadParam(aMsg, aIter, &aResult->mBaseAddress)) {
553 return false;
556 if (!ReadParam(aMsg, aIter, &aResult->mIsDependent)) {
557 return false;
560 if (!ReadParam(aMsg, aIter, &aResult->mLoadStatus)) {
561 return false;
564 nsAutoString resolvedNtName;
565 if (!ReadParam(aMsg, aIter, &resolvedNtName)) {
566 return false;
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
572 // telemetry.
573 aResult->mModule = aModulesMap.Get(resolvedNtName);
575 return true;
579 template <>
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)) {
591 return false;
594 if (!aMsg->ReadUInt32(aIter, &aResult->mTrustTestFailures)) {
595 return false;
598 return true;
602 } // namespace IPC
604 #else // defined(XP_WIN)
606 namespace mozilla {
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