зеркало из 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 "freestanding/CheckForCaller.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 {
|
||||
|
||||
extern "C" MOZ_EXPORT nt::LoaderAPI* GetNtLoaderAPI(
|
||||
nt::LoaderObserver* aNewObserver) {
|
||||
const bool isCallerMozglue = CheckForMozglue(RETURN_ADDRESS());
|
||||
const bool isCallerMozglue =
|
||||
CheckForAddress(RETURN_ADDRESS(), L"mozglue.dll");
|
||||
MOZ_ASSERT(isCallerMozglue);
|
||||
if (!isCallerMozglue) {
|
||||
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 "CheckForCaller.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace freestanding {
|
||||
|
||||
|
@ -214,6 +216,15 @@ LauncherVoidResult SharedSection::TransferHandle(
|
|||
}
|
||||
|
||||
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();
|
||||
if (resultView.isErr()) {
|
||||
if (aOutArray) {
|
||||
|
|
|
@ -68,30 +68,10 @@ static bool VerifySharedSection(SharedSection& aSharedSection) {
|
|||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, GetSystemInfo);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, VirtualProtect);
|
||||
|
||||
Span<uint32_t> modulePaths = []() -> Span<uint32_t> {
|
||||
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 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) {
|
||||
const uint8_t* const arrayBase =
|
||||
reinterpret_cast<const uint8_t*>(view->mModulePathArray);
|
||||
for (uint32_t i = 0; i < view->mModulePathArrayLength; ++i) {
|
||||
uint32_t offset = view->mModulePathArray[i];
|
||||
// Use NtQueryAttributesFile to check the validity of an NT path.
|
||||
UNICODE_STRING ntpath;
|
||||
::RtlInitUnicodeString(
|
||||
|
@ -152,6 +132,30 @@ class ChildProcess final {
|
|||
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)) {
|
||||
return 1;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче