Bug 1744362 - Part 7: support code for about:third-party r=handyman

Differential Revision: https://phabricator.services.mozilla.com/D164489
This commit is contained in:
Greg Stoll 2022-12-27 20:06:41 +00:00
Родитель acc64a126e
Коммит 78bf088bb7
7 изменённых файлов: 204 добавлений и 7 удалений

Просмотреть файл

@ -495,11 +495,11 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
job = CreateJobAndAssignProcess(process.get()); job = CreateJobAndAssignProcess(process.get());
} }
bool disableDynamicBlocklist = bool disableDynamicBlocklist = IsDynamicBlocklistDisabled(
isSafeMode.value() || isSafeMode.value(),
mozilla::CheckArg( mozilla::CheckArg(
argc, argv, mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch, argc, argv, mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch,
nullptr, mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND; nullptr, mozilla::CheckArgFlag::None) == mozilla::ARG_FOUND);
LauncherVoidResult setupResult = PostCreationSetup( LauncherVoidResult setupResult = PostCreationSetup(
argv[0], process.get(), mainThread.get(), deelevationStatus, argv[0], process.get(), mainThread.get(), deelevationStatus,
isSafeMode.value(), disableDynamicBlocklist, blocklistFileName); isSafeMode.value(), disableDynamicBlocklist, blocklistFileName);

Просмотреть файл

@ -1373,8 +1373,10 @@ bool WindowsProcessLauncher::DoSetup() {
} }
# ifdef HAS_DLL_BLOCKLIST # ifdef HAS_DLL_BLOCKLIST
if (CommandLine::ForCurrentProcess()->HasSwitch( if (IsDynamicBlocklistDisabled(
UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch))) { gSafeMode,
CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(
mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)))) {
mCmdLine->AppendLooseValue( mCmdLine->AppendLooseValue(
UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)); UTF8ToWide(mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch));
} }

Просмотреть файл

@ -7,11 +7,18 @@
#include "AboutThirdParty.h" #include "AboutThirdParty.h"
#include "AboutThirdPartyUtils.h" #include "AboutThirdPartyUtils.h"
#include "base/command_line.h"
#include "base/string_util.h"
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/DynamicBlocklist.h"
#include "mozilla/GeckoArgs.h"
#include "mozilla/NativeNt.h" #include "mozilla/NativeNt.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
#include "mozilla/WinDllServices.h"
#include "MsiDatabase.h" #include "MsiDatabase.h"
#include "nsAppRunner.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "nsIWindowsRegKey.h" #include "nsIWindowsRegKey.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
@ -56,6 +63,20 @@ void EnumSubkeys(nsIWindowsRegKey* aRegBase, const CallbackT& aCallback) {
} }
} }
Span<const DllBlockInfo> GetDynamicBlocklistSpan(
RefPtr<DllServices>&& aDllSvc) {
if (!aDllSvc) {
return nullptr;
}
nt::SharedSection* sharedSection = aDllSvc->GetSharedSection();
if (!sharedSection) {
return nullptr;
}
return sharedSection->GetDynamicBlocklist();
}
} // anonymous namespace } // anonymous namespace
InstallLocationComparator::InstallLocationComparator(const nsAString& aFilePath) InstallLocationComparator::InstallLocationComparator(const nsAString& aFilePath)
@ -655,6 +676,15 @@ void AboutThirdParty::BackgroundThread() {
MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mWorkerState == WorkerState::Running); MOZ_ASSERT(mWorkerState == WorkerState::Running);
auto cleanup = MakeScopeExit(
[self = RefPtr{this}] { self->mWorkerState = WorkerState::Done; });
RefPtr<DllServices> dllSvc(DllServices::Get());
if (!dllSvc) {
// Probably we're shutting down. Bail out before expensive tasks.
return;
}
KnownModule::EnumAll( KnownModule::EnumAll(
[self = RefPtr{this}](const nsString& aDllPath, KnownModuleType aType) { [self = RefPtr{this}](const nsString& aDllPath, KnownModuleType aType) {
self->AddKnownModule(aDllPath, aType); self->AddKnownModule(aDllPath, aType);
@ -663,11 +693,56 @@ void AboutThirdParty::BackgroundThread() {
InstalledApplications apps; InstalledApplications apps;
apps.Collect(mComponentPaths, mLocations); apps.Collect(mComponentPaths, mLocations);
mWorkerState = WorkerState::Done; #if defined(MOZ_LAUNCHER_PROCESS)
Span<const DllBlockInfo> blocklist =
GetDynamicBlocklistSpan(std::move(dllSvc));
if (blocklist.IsEmpty()) {
return;
}
for (auto info = blocklist.begin(); info != blocklist.end(); ++info) {
if (!info->mName.Buffer || !info->mName.Length ||
info->mName.Length > info->mName.MaximumLength ||
info->mMaxVersion != DllBlockInfo::ALL_VERSIONS ||
info->mFlags != DllBlockInfo::Flags::FLAGS_DEFAULT) {
break;
}
nsString name(info->mName.Buffer, info->mName.Length / sizeof(wchar_t));
mDynamicBlocklist.Insert(std::move(name));
}
#endif // defined(MOZ_LAUNCHER_PROCESS)
}
NS_IMETHODIMP AboutThirdParty::GetBlockedModuleNames(
const nsTArray<nsString>& aLoadedModuleNames,
nsTArray<nsString>& aBlockedModuleNames) {
MOZ_ASSERT(NS_IsMainThread());
aBlockedModuleNames.SetLength(0);
#if defined(MOZ_LAUNCHER_PROCESS)
if (mWorkerState != WorkerState::Done) {
return NS_OK;
}
// Blocklist entries are case-insensitive
nsTHashSet<nsStringCaseInsensitiveHashKey> loadedModuleNameSet;
for (const nsString& loadedModuleName : aLoadedModuleNames) {
loadedModuleNameSet.Insert(loadedModuleName);
}
for (const auto& blocklistEntry : mDynamicBlocklist) {
// Only return entries that we haven't already tried to load,
// because those will already show up in the page
if (!loadedModuleNameSet.Contains(blocklistEntry)) {
aBlockedModuleNames.AppendElement(blocklistEntry);
}
}
#endif // defined(MOZ_LAUNCHER_PROCESS)
return NS_OK;
} }
NS_IMETHODIMP AboutThirdParty::LookupModuleType(const nsAString& aLeafName, NS_IMETHODIMP AboutThirdParty::LookupModuleType(const nsAString& aLeafName,
uint32_t* aResult) { uint32_t* aResult) {
static_assert(static_cast<uint32_t>(KnownModuleType::Last) <= 32,
"Too many flags in KnownModuleType");
constexpr uint32_t kShellExtensions = constexpr uint32_t kShellExtensions =
1u << static_cast<uint32_t>(KnownModuleType::IconOverlay) | 1u << static_cast<uint32_t>(KnownModuleType::IconOverlay) |
1u << static_cast<uint32_t>(KnownModuleType::ContextMenuHandler) | 1u << static_cast<uint32_t>(KnownModuleType::ContextMenuHandler) |
@ -687,9 +762,15 @@ NS_IMETHODIMP AboutThirdParty::LookupModuleType(const nsAString& aLeafName,
return NS_OK; return NS_OK;
} }
#if defined(MOZ_LAUNCHER_PROCESS)
if (mDynamicBlocklist.Contains(aLeafName)) {
*aResult |= nsIAboutThirdParty::ModuleType_BlockedByUser;
}
#endif
uint32_t flags; uint32_t flags;
if (!mKnownModules.Get(aLeafName, &flags)) { if (!mKnownModules.Get(aLeafName, &flags)) {
*aResult = nsIAboutThirdParty::ModuleType_Unknown; *aResult |= nsIAboutThirdParty::ModuleType_Unknown;
return NS_OK; return NS_OK;
} }
@ -703,6 +784,7 @@ NS_IMETHODIMP AboutThirdParty::LookupModuleType(const nsAString& aLeafName,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP AboutThirdParty::LookupApplication( NS_IMETHODIMP AboutThirdParty::LookupApplication(
const nsAString& aModulePath, nsIInstalledApplication** aResult) { const nsAString& aModulePath, nsIInstalledApplication** aResult) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
@ -739,6 +821,76 @@ NS_IMETHODIMP AboutThirdParty::LookupApplication(
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP AboutThirdParty::GetIsDynamicBlocklistAvailable(
bool* aIsDynamicBlocklistAvailable) {
*aIsDynamicBlocklistAvailable =
!GetDynamicBlocklistSpan(DllServices::Get()).IsEmpty();
return NS_OK;
}
NS_IMETHODIMP AboutThirdParty::GetIsDynamicBlocklistDisabled(
bool* aIsDynamicBlocklistDisabled) {
*aIsDynamicBlocklistDisabled = IsDynamicBlocklistDisabled(
gSafeMode, CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(
mozilla::geckoargs::sDisableDynamicDllBlocklist.sMatch)));
return NS_OK;
}
NS_IMETHODIMP AboutThirdParty::UpdateBlocklist(const nsAString& aLeafName,
bool aNewBlockStatus,
JSContext* aCx,
dom::Promise** aResult) {
#if defined(MOZ_LAUNCHER_PROCESS)
MOZ_ASSERT(NS_IsMainThread());
nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
MOZ_ASSERT(global);
ErrorResult result;
RefPtr<dom::Promise> promise(dom::Promise::Create(global, result));
if (NS_WARN_IF(result.Failed())) {
return result.StealNSResult();
}
auto returnPromise = MakeScopeExit([&] { promise.forget(aResult); });
if (aNewBlockStatus) {
mDynamicBlocklist.Insert(aLeafName);
} else {
mDynamicBlocklist.Remove(aLeafName);
}
auto newTask = MakeUnique<DynamicBlocklistWriter>(promise, mDynamicBlocklist);
if (!newTask->IsReady()) {
promise->MaybeReject(NS_ERROR_CANNOT_CONVERT_DATA);
return NS_OK;
}
UniquePtr<DynamicBlocklistWriter> oldTask(
mPendingWriter.exchange(newTask.release()));
if (oldTask) {
oldTask->Cancel();
}
nsresult rv = NS_DispatchBackgroundTask(
NS_NewRunnableFunction(__func__,
[self = RefPtr{this}]() {
UniquePtr<DynamicBlocklistWriter> task(
self->mPendingWriter.exchange(nullptr));
if (task) {
task->Run();
}
}),
NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
promise->MaybeReject(rv);
}
return NS_OK;
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif // defined(MOZ_LAUNCHER_PROCESS)
}
RefPtr<BackgroundThreadPromise> AboutThirdParty::CollectSystemInfoAsync() { RefPtr<BackgroundThreadPromise> AboutThirdParty::CollectSystemInfoAsync() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());

Просмотреть файл

@ -12,9 +12,12 @@
#include "nsInterfaceHashtable.h" #include "nsInterfaceHashtable.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "nsTHashMap.h" #include "nsTHashMap.h"
#include "nsTHashSet.h"
namespace mozilla { namespace mozilla {
class DynamicBlocklistWriter;
using InstallLocationT = using InstallLocationT =
CompactPair<nsString, nsCOMPtr<nsIInstalledApplication>>; CompactPair<nsString, nsCOMPtr<nsIInstalledApplication>>;
using ComponentPathMapT = nsInterfaceHashtable<nsStringCaseInsensitiveHashKey, using ComponentPathMapT = nsInterfaceHashtable<nsStringCaseInsensitiveHashKey,
@ -78,6 +81,11 @@ class AboutThirdParty final : public nsIAboutThirdParty {
ComponentPathMapT mComponentPaths; ComponentPathMapT mComponentPaths;
nsTArray<InstallLocationT> mLocations; nsTArray<InstallLocationT> mLocations;
#if defined(MOZ_LAUNCHER_PROCESS)
Atomic<DynamicBlocklistWriter*> mPendingWriter;
nsTHashSet<nsStringCaseInsensitiveHashKey> mDynamicBlocklist;
#endif
~AboutThirdParty() = default; ~AboutThirdParty() = default;
void BackgroundThread(); void BackgroundThread();
void AddKnownModule(const nsString& aPath, KnownModuleType aType); void AddKnownModule(const nsString& aPath, KnownModuleType aType);

Просмотреть файл

@ -33,3 +33,5 @@ if CONFIG["ENABLE_TESTS"]:
DIRS += ["tests/gtest"] DIRS += ["tests/gtest"]
TEST_DIRS += ["tests/TestShellEx"] TEST_DIRS += ["tests/TestShellEx"]
include("/ipc/chromium/chromium-config.mozbuild")

Просмотреть файл

@ -21,6 +21,7 @@ interface nsIAboutThirdParty : nsISupports
const unsigned long ModuleType_Unknown = 1 << 0; const unsigned long ModuleType_Unknown = 1 << 0;
const unsigned long ModuleType_IME = 1 << 1; const unsigned long ModuleType_IME = 1 << 1;
const unsigned long ModuleType_ShellExtension = 1 << 2; const unsigned long ModuleType_ShellExtension = 1 << 2;
const unsigned long ModuleType_BlockedByUser = 1 << 3;
/** /**
* Returns a bitwise combination of the ModuleType_* flags * Returns a bitwise combination of the ModuleType_* flags
@ -34,6 +35,29 @@ interface nsIAboutThirdParty : nsISupports
*/ */
nsIInstalledApplication lookupApplication(in AString aModulePath); nsIInstalledApplication lookupApplication(in AString aModulePath);
/**
* Gets the list of modules that have been blocklisted but have not
* attempted to load.
*/
void getBlockedModuleNames(in Array<AString> aLoadedModuleNames, out Array<AString> aBlockedModuleNames);
/**
* Returns true if DynamicBlocklist is available.
*/
readonly attribute bool isDynamicBlocklistAvailable;
/**
* Returns true if DynamicBlocklist is available but disabled.
*/
readonly attribute bool isDynamicBlocklistDisabled;
/**
* Add or remove an entry from the dynamic blocklist and save
* the resulting file.
*/
[implicit_jscontext] Promise updateBlocklist(in AString aLeafName,
in boolean aNewBlockStatus);
/** /**
* Posts a background task to collect system information and resolves * Posts a background task to collect system information and resolves
* the returned promise when the task is finished. * the returned promise when the task is finished.

Просмотреть файл

@ -327,4 +327,13 @@ struct FreeSidDeleter {
// This typedef will work for storing a PSID in a UniquePtr and should make // This typedef will work for storing a PSID in a UniquePtr and should make
// things a bit more readable. // things a bit more readable.
typedef mozilla::UniquePtr<void, FreeSidDeleter> UniqueSidPtr; typedef mozilla::UniquePtr<void, FreeSidDeleter> UniqueSidPtr;
// One caller of this function is early in startup and several others are not,
// so they have different ways of determining the two parameters. This function
// exists just so any future code that needs to determine whether the dynamic
// blocklist is disabled remembers to check whether safe mode is active.
inline bool IsDynamicBlocklistDisabled(bool isSafeMode,
bool hasCommandLineDisableArgument) {
return isSafeMode || hasCommandLineDisableArgument;
}
#endif #endif