зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1746114 - Part1. Avoid delayloading shlwapi.dll in a sandboxed process. r=mhowell
While processing third-party module loading events, the process may delayload shlwapi.dll. This could be a problem if the process is sandboxed and the access to local files is restricted. Before enabling the third-party modules ping in socket process, this patch avoids such delayloading. The first path is `ParamTraits<mozilla::ModuleRecord>::Read` calls `NS_NewLocalFile` that calls `PathGetDriveNumberW`. This API is simple enough that we define our own version. The second path is the ctor of `ProcessedModuleLoadEvent` that is called from `UntrustedModulesProcessor::CompleteProcessing` calls `PreparePathForTelemetry` that calls `PathFindFileNameW` and `PathCanonicalizeW`. For this path, instead of sanitizing a requested name in `ProcessedModuleLoadEvent`'s ctor, we sanitize it when transferring it to the main process. Differential Revision: https://phabricator.services.mozilla.com/D134492
This commit is contained in:
Родитель
0ddbd1d7f7
Коммит
7d38851282
|
@ -220,13 +220,25 @@ ProcessedModuleLoadEvent::ProcessedModuleLoadEvent(
|
|||
return;
|
||||
}
|
||||
|
||||
// Sanitize the requested DLL name. It is not a critical failure if we
|
||||
// cannot do so; we simply do not provide that field to Telemetry.
|
||||
nsAutoString strRequested(
|
||||
aModLoadInfo.mNtLoadInfo.mRequestedDllName.AsString());
|
||||
if (!strRequested.IsEmpty() &&
|
||||
widget::WinUtils::PreparePathForTelemetry(strRequested)) {
|
||||
mRequestedDllName = strRequested;
|
||||
mRequestedDllName = aModLoadInfo.mNtLoadInfo.mRequestedDllName.AsString();
|
||||
|
||||
// If we're in the main process, sanitize the requested DLL name here.
|
||||
// If not, we cannot use PreparePathForTelemetry because it may try to
|
||||
// delayload shlwapi.dll and could fail if the process is sandboxed.
|
||||
// We leave mRequestedDllName unsanitized here and sanitize it when
|
||||
// transferring it to the main process.
|
||||
// (See ParamTraits<mozilla::UntrustedModulesData>::ReadEvent)
|
||||
if (XRE_IsParentProcess()) {
|
||||
SanitizeRequestedDllName();
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessedModuleLoadEvent::SanitizeRequestedDllName() {
|
||||
if (!mRequestedDllName.IsEmpty() &&
|
||||
!widget::WinUtils::PreparePathForTelemetry(mRequestedDllName)) {
|
||||
// If we cannot sanitize a path, we simply do not provide that field to
|
||||
// Telemetry.
|
||||
mRequestedDllName.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,8 @@ class ProcessedModuleLoadEvent final {
|
|||
ProcessedModuleLoadEvent(ProcessedModuleLoadEvent&&) = default;
|
||||
ProcessedModuleLoadEvent& operator=(ProcessedModuleLoadEvent&&) = default;
|
||||
|
||||
void SanitizeRequestedDllName();
|
||||
|
||||
private:
|
||||
static Maybe<LONGLONG> ComputeQPCTimeStampForProcessCreation();
|
||||
static uint64_t QPCTimeStampToProcessUptimeMilliseconds(
|
||||
|
@ -553,6 +555,10 @@ struct ParamTraits<mozilla::UntrustedModulesData> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// When ProcessedModuleLoadEvent was constructed in a child process, we left
|
||||
// mRequestedDllName unsanitized, so now is a good time to sanitize it.
|
||||
aResult->SanitizeRequestedDllName();
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &aResult->mBaseAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "gtest/gtest.h"
|
||||
#include "mozilla/WinHeaderOnlyUtils.h"
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
TEST(WinHeaderOnlyUtils, MozPathGetDriveNumber)
|
||||
{
|
||||
constexpr auto TestPathGetDriveNumber = [](const wchar_t* aPath) {
|
||||
return mozilla::MozPathGetDriveNumber(aPath) ==
|
||||
::PathGetDriveNumberW(aPath);
|
||||
};
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(nullptr));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L""));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L" :"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"a:"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"C:\\file"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"x:/file"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"@:\\\\"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"B"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"abc:\\file"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\:A"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\\\"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\?"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\?\\"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\?\\\\"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\?\\c:\\"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\?\\A"));
|
||||
EXPECT_TRUE(TestPathGetDriveNumber(L"\\\\?\\ \\"));
|
||||
}
|
|
@ -12,6 +12,7 @@ UNIFIED_SOURCES = [
|
|||
if CONFIG["OS_ARCH"] == "WINNT":
|
||||
UNIFIED_SOURCES += [
|
||||
"MockWinWidget.cpp",
|
||||
"TestWinHeaderOnlyUtils.cpp",
|
||||
"TestWinWindowOcclusionTracker.cpp",
|
||||
"TestWinWindowOcclusionTrackerInteractive.cpp",
|
||||
]
|
||||
|
|
|
@ -789,6 +789,35 @@ inline UniquePtr<wchar_t[]> GetPackageFamilyName() {
|
|||
return packageIdentity;
|
||||
}
|
||||
|
||||
// This implementation is equivalent to PathGetDriveNumber[AW].
|
||||
// We define our own version because using PathGetDriveNumber
|
||||
// delay-loads shlwapi.dll, which may fail when the process is
|
||||
// sandboxed.
|
||||
template <typename T>
|
||||
int MozPathGetDriveNumber(const T* aPath) {
|
||||
const auto ToDriveNumber = [](const T* aPath) -> int {
|
||||
if (*aPath == '\0' || *(aPath + 1) != ':') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
T c = *aPath;
|
||||
return (c >= 'A' && c <= 'Z') ? c - 'A'
|
||||
: (c >= 'a' && c <= 'z') ? c - 'a'
|
||||
: -1;
|
||||
};
|
||||
|
||||
if (!aPath) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*aPath == '\\' && *(aPath + 1) == '\\' && *(aPath + 2) == '?' &&
|
||||
*(aPath + 3) == '\\') {
|
||||
return ToDriveNumber(aPath + 4);
|
||||
}
|
||||
|
||||
return ToDriveNumber(aPath);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_WinHeaderOnlyUtils_h
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/TextUtils.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/Utf8.h"
|
||||
#include "mozilla/WinHeaderOnlyUtils.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsMemory.h"
|
||||
|
@ -1053,7 +1054,7 @@ nsLocalFile::InitWithPath(const nsAString& aFilePath) {
|
|||
if (secondChar == L':') {
|
||||
// Make sure we have a valid drive, later code assumes the drive letter
|
||||
// is a single char a-z or A-Z.
|
||||
if (PathGetDriveNumberW(aFilePath.Data()) == -1) {
|
||||
if (MozPathGetDriveNumber<wchar_t>(aFilePath.Data()) == -1) {
|
||||
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче