зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1676913 - Restrict a caller of GetDependentModulePaths to xul.dll. r=mhowell
Bug 1659438 introduced an exported function `GetDependentModulePaths` in firefox.exe so that our sandboxBroker can easily access the shared section whose handle is owned by firefox.exe. This patch disallows `GetDependentModulePaths` to be called from someone other than xul.dll in order to harden the attack to tamper our shared section. This cannot prevent all possible attacks, but it's better than nothing. Differential Revision: https://phabricator.services.mozilla.com/D97377
This commit is contained in:
Родитель
455ee2ab18
Коммит
d98a83f672
|
@ -6,34 +6,15 @@
|
||||||
|
|
||||||
#include "mozilla/LoaderAPIInterfaces.h"
|
#include "mozilla/LoaderAPIInterfaces.h"
|
||||||
|
|
||||||
|
#include "freestanding/CheckForCaller.h"
|
||||||
#include "freestanding/LoaderPrivateAPI.h"
|
#include "freestanding/LoaderPrivateAPI.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# include <intrin.h>
|
|
||||||
# pragma intrinsic(_ReturnAddress)
|
|
||||||
# define RETURN_ADDRESS() _ReturnAddress()
|
|
||||||
#elif defined(__GNUC__) || defined(__clang__)
|
|
||||||
# define RETURN_ADDRESS() \
|
|
||||||
__builtin_extract_return_addr(__builtin_return_address(0))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool CheckForMozglue(void* aReturnAddress) {
|
|
||||||
HMODULE callingModule;
|
|
||||||
if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
|
||||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
|
||||||
reinterpret_cast<LPCWSTR>(aReturnAddress),
|
|
||||||
&callingModule)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return callingModule && callingModule == ::GetModuleHandleW(L"mozglue.dll");
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
extern "C" MOZ_EXPORT nt::LoaderAPI* GetNtLoaderAPI(
|
extern "C" MOZ_EXPORT nt::LoaderAPI* GetNtLoaderAPI(
|
||||||
nt::LoaderObserver* aNewObserver) {
|
nt::LoaderObserver* aNewObserver) {
|
||||||
const bool isCallerMozglue = CheckForMozglue(RETURN_ADDRESS());
|
const bool isCallerMozglue =
|
||||||
|
CheckForAddress(RETURN_ADDRESS(), L"mozglue.dll");
|
||||||
MOZ_ASSERT(isCallerMozglue);
|
MOZ_ASSERT(isCallerMozglue);
|
||||||
if (!isCallerMozglue) {
|
if (!isCallerMozglue) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_freestanding_CheckForCaller_h
|
||||||
|
#define mozilla_freestanding_CheckForCaller_h
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# include <intrin.h>
|
||||||
|
# pragma intrinsic(_ReturnAddress)
|
||||||
|
# define RETURN_ADDRESS() _ReturnAddress()
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
# define RETURN_ADDRESS() \
|
||||||
|
__builtin_extract_return_addr(__builtin_return_address(0))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
bool CheckForAddress(void* aReturnAddress, const wchar_t (&aName)[N]) {
|
||||||
|
HMODULE callingModule;
|
||||||
|
if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||||
|
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
|
reinterpret_cast<LPCWSTR>(aReturnAddress),
|
||||||
|
&callingModule)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return callingModule && callingModule == ::GetModuleHandleW(aName);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_freestanding_CheckForCaller_h
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include "SharedSection.h"
|
#include "SharedSection.h"
|
||||||
|
|
||||||
|
#include "CheckForCaller.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace freestanding {
|
namespace freestanding {
|
||||||
|
|
||||||
|
@ -214,6 +216,15 @@ LauncherVoidResult SharedSection::TransferHandle(
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" MOZ_EXPORT uint32_t GetDependentModulePaths(uint32_t** aOutArray) {
|
extern "C" MOZ_EXPORT uint32_t GetDependentModulePaths(uint32_t** aOutArray) {
|
||||||
|
const bool isCallerXul = CheckForAddress(RETURN_ADDRESS(), L"xul.dll");
|
||||||
|
MOZ_ASSERT(isCallerXul);
|
||||||
|
if (!isCallerXul) {
|
||||||
|
if (aOutArray) {
|
||||||
|
*aOutArray = nullptr;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
LauncherResult<SharedSection::Layout*> resultView = gSharedSection.GetView();
|
LauncherResult<SharedSection::Layout*> resultView = gSharedSection.GetView();
|
||||||
if (resultView.isErr()) {
|
if (resultView.isErr()) {
|
||||||
if (aOutArray) {
|
if (aOutArray) {
|
||||||
|
|
|
@ -68,30 +68,10 @@ static bool VerifySharedSection(SharedSection& aSharedSection) {
|
||||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, GetSystemInfo);
|
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, GetSystemInfo);
|
||||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, VirtualProtect);
|
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, VirtualProtect);
|
||||||
|
|
||||||
Span<uint32_t> modulePaths = []() -> Span<uint32_t> {
|
const uint8_t* const arrayBase =
|
||||||
auto getDependentModulePaths =
|
reinterpret_cast<const uint8_t*>(view->mModulePathArray);
|
||||||
reinterpret_cast<uint32_t (*)(uint32_t**)>(::GetProcAddress(
|
for (uint32_t i = 0; i < view->mModulePathArrayLength; ++i) {
|
||||||
::GetModuleHandleW(nullptr), "GetDependentModulePaths"));
|
uint32_t offset = view->mModulePathArray[i];
|
||||||
if (!getDependentModulePaths) {
|
|
||||||
printf(
|
|
||||||
"TEST-FAILED | TestCrossProcessWin | "
|
|
||||||
"Failed to get a pointer to GetDependentModulePaths - %08lx.\n",
|
|
||||||
::GetLastError());
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t* modulePathArray;
|
|
||||||
uint32_t modulePathArrayLen = getDependentModulePaths(&modulePathArray);
|
|
||||||
return Span(modulePathArray, modulePathArrayLen);
|
|
||||||
}();
|
|
||||||
|
|
||||||
if (modulePaths.IsEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t* arrayBase =
|
|
||||||
reinterpret_cast<const uint8_t*>(modulePaths.data());
|
|
||||||
for (const uint32_t& offset : modulePaths) {
|
|
||||||
// Use NtQueryAttributesFile to check the validity of an NT path.
|
// Use NtQueryAttributesFile to check the validity of an NT path.
|
||||||
UNICODE_STRING ntpath;
|
UNICODE_STRING ntpath;
|
||||||
::RtlInitUnicodeString(
|
::RtlInitUnicodeString(
|
||||||
|
@ -152,6 +132,30 @@ class ChildProcess final {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto getDependentModulePaths =
|
||||||
|
reinterpret_cast<uint32_t (*)(uint32_t**)>(::GetProcAddress(
|
||||||
|
::GetModuleHandleW(nullptr), "GetDependentModulePaths"));
|
||||||
|
if (!getDependentModulePaths) {
|
||||||
|
printf(
|
||||||
|
"TEST-FAILED | TestCrossProcessWin | "
|
||||||
|
"Failed to get a pointer to GetDependentModulePaths - %08lx.\n",
|
||||||
|
::GetLastError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(DEBUG)
|
||||||
|
// GetDependentModulePaths does not allow a caller other than xul.dll.
|
||||||
|
// Skip on Debug build because it hits MOZ_ASSERT.
|
||||||
|
uint32_t* modulePathArray;
|
||||||
|
if (getDependentModulePaths(&modulePathArray) || modulePathArray) {
|
||||||
|
printf(
|
||||||
|
"TEST-FAILED | TestCrossProcessWin | "
|
||||||
|
"GetDependentModulePaths should return zero if the caller is "
|
||||||
|
"not xul.dll.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif // !defined(DEBUG)
|
||||||
|
|
||||||
if (!VerifySharedSection(gSharedSection)) {
|
if (!VerifySharedSection(gSharedSection)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче