зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1659438 - Part2: Transfer Kernel32ExportsSolver as a shared memory. r=mhowell
We transfer several ntdll's function addresses to a child process directly via `WriteProcessMemory`. This patch changes the way to transfer data to using a section object as Chromium sandbox does, so that we can transfer more data with the same cost as transferring a single handle value. Depends on D96282 Differential Revision: https://phabricator.services.mozilla.com/D96283
This commit is contained in:
Родитель
c256f944cc
Коммит
187d19452d
|
@ -41,30 +41,26 @@ LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPFromLauncher(
|
|||
#else
|
||||
|
||||
static LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPInternal(
|
||||
const wchar_t* aFullImagePath, HANDLE aChildProcess,
|
||||
const wchar_t* aFullImagePath, nt::CrossExecTransferManager& aTransferMgr,
|
||||
const IMAGE_THUNK_DATA* aCachedNtdllThunk) {
|
||||
nt::CrossExecTransferManager transferMgr(aChildProcess);
|
||||
if (!transferMgr) {
|
||||
return LAUNCHER_ERROR_FROM_WIN32(ERROR_BAD_EXE_FORMAT);
|
||||
LauncherVoidResult transferResult =
|
||||
freestanding::gSharedSection.TransferHandle(aTransferMgr);
|
||||
if (transferResult.isErr()) {
|
||||
return transferResult.propagateErr();
|
||||
}
|
||||
|
||||
freestanding::gK32.Init();
|
||||
if (freestanding::gK32.IsInitialized()) {
|
||||
Unused << freestanding::gK32.Transfer(transferMgr, &freestanding::gK32);
|
||||
}
|
||||
|
||||
CrossProcessDllInterceptor intcpt(aChildProcess);
|
||||
CrossProcessDllInterceptor intcpt(aTransferMgr.RemoteProcess());
|
||||
intcpt.Init(L"ntdll.dll");
|
||||
|
||||
bool ok = freestanding::stub_NtMapViewOfSection.SetDetour(
|
||||
transferMgr, intcpt, "NtMapViewOfSection",
|
||||
aTransferMgr, intcpt, "NtMapViewOfSection",
|
||||
&freestanding::patched_NtMapViewOfSection);
|
||||
if (!ok) {
|
||||
return LAUNCHER_ERROR_FROM_DETOUR_ERROR(intcpt.GetLastDetourError());
|
||||
}
|
||||
|
||||
ok = freestanding::stub_LdrLoadDll.SetDetour(
|
||||
transferMgr, intcpt, "LdrLoadDll", &freestanding::patched_LdrLoadDll);
|
||||
aTransferMgr, intcpt, "LdrLoadDll", &freestanding::patched_LdrLoadDll);
|
||||
if (!ok) {
|
||||
return LAUNCHER_ERROR_FROM_DETOUR_ERROR(intcpt.GetLastDetourError());
|
||||
}
|
||||
|
@ -80,12 +76,12 @@ static LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPInternal(
|
|||
// it onto the child process's IAT, thus enabling the child process's hook to
|
||||
// safely make its ntdll calls.
|
||||
|
||||
const nt::PEHeaders& ourExeImage = transferMgr.LocalPEHeaders();
|
||||
const nt::PEHeaders& ourExeImage = aTransferMgr.LocalPEHeaders();
|
||||
|
||||
// As part of our mitigation of binary tampering, copy our import directory
|
||||
// from the original in our executable file.
|
||||
LauncherVoidResult importDirRestored =
|
||||
RestoreImportDirectory(aFullImagePath, transferMgr);
|
||||
RestoreImportDirectory(aFullImagePath, aTransferMgr);
|
||||
if (importDirRestored.isErr()) {
|
||||
return importDirRestored;
|
||||
}
|
||||
|
@ -126,13 +122,13 @@ static LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPInternal(
|
|||
SIZE_T iatLength = ntdllThunks.value().LengthBytes();
|
||||
|
||||
AutoVirtualProtect prot =
|
||||
transferMgr.Protect(firstIatThunkDst, iatLength, PAGE_READWRITE);
|
||||
aTransferMgr.Protect(firstIatThunkDst, iatLength, PAGE_READWRITE);
|
||||
if (!prot) {
|
||||
return LAUNCHER_ERROR_FROM_MOZ_WINDOWS_ERROR(prot.GetError());
|
||||
}
|
||||
|
||||
LauncherVoidResult writeResult =
|
||||
transferMgr.Transfer(firstIatThunkDst, firstIatThunkSrc, iatLength);
|
||||
aTransferMgr.Transfer(firstIatThunkDst, firstIatThunkSrc, iatLength);
|
||||
if (writeResult.isErr()) {
|
||||
return writeResult.propagateErr();
|
||||
}
|
||||
|
@ -148,7 +144,7 @@ static LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPInternal(
|
|||
}
|
||||
|
||||
LauncherVoidResult writeResult =
|
||||
transferMgr.Transfer(&gBlocklistInitFlags, &newFlags, sizeof(newFlags));
|
||||
aTransferMgr.Transfer(&gBlocklistInitFlags, &newFlags, sizeof(newFlags));
|
||||
if (writeResult.isErr()) {
|
||||
return writeResult.propagateErr();
|
||||
}
|
||||
|
@ -159,26 +155,44 @@ static LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPInternal(
|
|||
LauncherVoidResultWithLineInfo InitializeDllBlocklistOOP(
|
||||
const wchar_t* aFullImagePath, HANDLE aChildProcess,
|
||||
const IMAGE_THUNK_DATA* aCachedNtdllThunk) {
|
||||
nt::CrossExecTransferManager transferMgr(aChildProcess);
|
||||
if (!transferMgr) {
|
||||
return LAUNCHER_ERROR_FROM_WIN32(ERROR_BAD_EXE_FORMAT);
|
||||
}
|
||||
|
||||
// We come here when the browser process launches a sandbox process.
|
||||
// If the launcher process already failed to bootstrap the browser process,
|
||||
// we should not attempt to bootstrap a child process because it's likely
|
||||
// to fail again. Instead, we only restore the import directory entry.
|
||||
if (!(gBlocklistInitFlags & eDllBlocklistInitFlagWasBootstrapped)) {
|
||||
nt::CrossExecTransferManager transferMgr(aChildProcess);
|
||||
if (!transferMgr) {
|
||||
return LAUNCHER_ERROR_FROM_WIN32(ERROR_BAD_EXE_FORMAT);
|
||||
}
|
||||
|
||||
return RestoreImportDirectory(aFullImagePath, transferMgr);
|
||||
}
|
||||
|
||||
return InitializeDllBlocklistOOPInternal(aFullImagePath, aChildProcess,
|
||||
return InitializeDllBlocklistOOPInternal(aFullImagePath, transferMgr,
|
||||
aCachedNtdllThunk);
|
||||
}
|
||||
|
||||
LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPFromLauncher(
|
||||
const wchar_t* aFullImagePath, HANDLE aChildProcess) {
|
||||
return InitializeDllBlocklistOOPInternal(aFullImagePath, aChildProcess,
|
||||
nt::CrossExecTransferManager transferMgr(aChildProcess);
|
||||
if (!transferMgr) {
|
||||
return LAUNCHER_ERROR_FROM_WIN32(ERROR_BAD_EXE_FORMAT);
|
||||
}
|
||||
|
||||
// The launcher process initializes a section object, whose handle is
|
||||
// transferred to the browser process, and that transferred handle in
|
||||
// the browser process is transferred to the sandbox processes.
|
||||
LauncherVoidResultWithLineInfo result =
|
||||
freestanding::gSharedSection.Init(transferMgr.LocalPEHeaders());
|
||||
if (result.isErr()) {
|
||||
return result.propagateErr();
|
||||
}
|
||||
|
||||
auto clearInstance = MakeScopeExit([]() {
|
||||
// After transfer, the launcher process does not need the object anymore.
|
||||
freestanding::gSharedSection.Reset(nullptr);
|
||||
});
|
||||
return InitializeDllBlocklistOOPInternal(aFullImagePath, transferMgr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -279,14 +279,19 @@ static BlockAction DetermineBlockAction(const UNICODE_STRING& aLeafName,
|
|||
// If we fail to detour a module's entrypoint, we reluctantly allow the
|
||||
// module for free.
|
||||
|
||||
auto resultView = mozilla::freestanding::gSharedSection.GetView();
|
||||
if (resultView.isErr()) {
|
||||
return BlockAction::Allow;
|
||||
}
|
||||
|
||||
static RTL_RUN_ONCE sRunOnce = RTL_RUN_ONCE_INIT;
|
||||
mozilla::freestanding::gK32.Resolve(sRunOnce);
|
||||
if (!mozilla::freestanding::gK32.IsResolved()) {
|
||||
resultView.inspect()->mK32Exports.Resolve(sRunOnce);
|
||||
if (!resultView.inspect()->mK32Exports.IsResolved()) {
|
||||
return BlockAction::Allow;
|
||||
}
|
||||
|
||||
mozilla::interceptor::WindowsDllEntryPointInterceptor interceptor(
|
||||
mozilla::freestanding::gK32);
|
||||
resultView.inspect()->mK32Exports);
|
||||
if (!interceptor.Set(headers, NoOp_DllMain)) {
|
||||
return BlockAction::Allow;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
namespace mozilla {
|
||||
namespace freestanding {
|
||||
|
||||
Kernel32ExportsSolver gK32;
|
||||
SharedSection gSharedSection;
|
||||
|
||||
bool Kernel32ExportsSolver::IsInitialized() const {
|
||||
return mState == State::Initialized || IsResolved();
|
||||
|
@ -33,11 +33,12 @@ bool Kernel32ExportsSolver::IsResolved() const {
|
|||
if (!rvaToFunction) { \
|
||||
return; \
|
||||
} \
|
||||
mOffsets.m##name = *rvaToFunction; \
|
||||
m##name = reinterpret_cast<decltype(m##name)>(*rvaToFunction); \
|
||||
} while (0)
|
||||
|
||||
#define RESOLVE_FUNCTION(base, name) \
|
||||
m##name = reinterpret_cast<decltype(m##name)>(base + mOffsets.m##name)
|
||||
#define RESOLVE_FUNCTION(base, name) \
|
||||
m##name = reinterpret_cast<decltype(m##name)>( \
|
||||
base + reinterpret_cast<uintptr_t>(m##name))
|
||||
|
||||
void Kernel32ExportsSolver::Init() {
|
||||
if (mState == State::Initialized || mState == State::Resolved) {
|
||||
|
@ -95,18 +96,67 @@ void Kernel32ExportsSolver::Resolve(RTL_RUN_ONCE& aRunOnce) {
|
|||
::RtlRunOnceExecuteOnce(&aRunOnce, &ResolveOnce, this, nullptr);
|
||||
}
|
||||
|
||||
LauncherVoidResult Kernel32ExportsSolver::Transfer(
|
||||
nt::CrossExecTransferManager& aTransferMgr,
|
||||
Kernel32ExportsSolver* aTargetAddress) const {
|
||||
LauncherVoidResult writeResult = aTransferMgr.Transfer(
|
||||
&aTargetAddress->mOffsets, &mOffsets, sizeof(mOffsets));
|
||||
if (writeResult.isErr()) {
|
||||
return writeResult.propagateErr();
|
||||
HANDLE SharedSection::sSectionHandle = nullptr;
|
||||
void* SharedSection::sWriteCopyView = nullptr;
|
||||
|
||||
void SharedSection::Reset(HANDLE aNewSecionObject) {
|
||||
if (sWriteCopyView) {
|
||||
nt::AutoMappedView view(sWriteCopyView);
|
||||
sWriteCopyView = nullptr;
|
||||
}
|
||||
|
||||
State stateInChild = State::Initialized;
|
||||
return aTransferMgr.Transfer(&aTargetAddress->mState, &stateInChild,
|
||||
sizeof(stateInChild));
|
||||
if (sSectionHandle) {
|
||||
::CloseHandle(sSectionHandle);
|
||||
}
|
||||
sSectionHandle = aNewSecionObject;
|
||||
}
|
||||
|
||||
LauncherVoidResult SharedSection::Init(const nt::PEHeaders& aPEHeaders) {
|
||||
HANDLE section =
|
||||
::CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
|
||||
sizeof(Kernel32ExportsSolver), nullptr);
|
||||
if (!section) {
|
||||
return LAUNCHER_ERROR_FROM_LAST();
|
||||
}
|
||||
Reset(section);
|
||||
|
||||
// The initial contents of the pages in a file mapping object backed by
|
||||
// the operating system paging file are 0 (zero). No need to zero it out
|
||||
// ourselves.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw
|
||||
nt::AutoMappedView writableView(sSectionHandle, PAGE_READWRITE);
|
||||
if (!writableView) {
|
||||
return LAUNCHER_ERROR_FROM_LAST();
|
||||
}
|
||||
|
||||
SharedSection::Layout* view = writableView.as<SharedSection::Layout>();
|
||||
view->mK32Exports.Init();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
LauncherResult<SharedSection::Layout*> SharedSection::GetView() {
|
||||
if (!sWriteCopyView) {
|
||||
nt::AutoMappedView view(sSectionHandle, PAGE_WRITECOPY);
|
||||
if (!view) {
|
||||
return LAUNCHER_ERROR_FROM_LAST();
|
||||
}
|
||||
sWriteCopyView = view.release();
|
||||
}
|
||||
return reinterpret_cast<SharedSection::Layout*>(sWriteCopyView);
|
||||
}
|
||||
|
||||
LauncherVoidResult SharedSection::TransferHandle(
|
||||
nt::CrossExecTransferManager& aTransferMgr, HANDLE* aDestinationAddress) {
|
||||
HANDLE remoteHandle;
|
||||
if (!::DuplicateHandle(nt::kCurrentProcess, sSectionHandle,
|
||||
aTransferMgr.RemoteProcess(), &remoteHandle,
|
||||
GENERIC_READ, FALSE, 0)) {
|
||||
return LAUNCHER_ERROR_FROM_LAST();
|
||||
}
|
||||
|
||||
return aTransferMgr.Transfer(aDestinationAddress, &remoteHandle,
|
||||
sizeof(remoteHandle));
|
||||
}
|
||||
|
||||
} // namespace freestanding
|
||||
|
|
|
@ -25,12 +25,6 @@ class MOZ_TRIVIAL_CTOR_DTOR Kernel32ExportsSolver final
|
|||
Resolved,
|
||||
} mState;
|
||||
|
||||
struct FunctionOffsets {
|
||||
uint32_t mFlushInstructionCache;
|
||||
uint32_t mGetSystemInfo;
|
||||
uint32_t mVirtualProtect;
|
||||
} mOffsets;
|
||||
|
||||
static ULONG NTAPI ResolveOnce(PRTL_RUN_ONCE aRunOnce, PVOID aParameter,
|
||||
PVOID*);
|
||||
void ResolveInternal();
|
||||
|
@ -48,11 +42,38 @@ class MOZ_TRIVIAL_CTOR_DTOR Kernel32ExportsSolver final
|
|||
|
||||
void Init();
|
||||
void Resolve(RTL_RUN_ONCE& aRunOnce);
|
||||
LauncherVoidResult Transfer(nt::CrossExecTransferManager& aTransferMgr,
|
||||
Kernel32ExportsSolver* aTargetAddress) const;
|
||||
};
|
||||
|
||||
extern Kernel32ExportsSolver gK32;
|
||||
// This class manages a section which is created in the launcher process and
|
||||
// mapped in the browser process and the sandboxed processes as a copy-on-write
|
||||
// region. The section's layout is represented as SharedSection::Layout.
|
||||
class MOZ_TRIVIAL_CTOR_DTOR SharedSection final {
|
||||
// As we define a global variable of this class and use it in our blocklist
|
||||
// which is excuted in a process's early stage. If we have a complex dtor,
|
||||
// the static initializer tries to register that dtor with onexit() of
|
||||
// ucrtbase.dll which is not loaded yet, resulting in crash. Thus, we have
|
||||
// a raw handle and a pointer as a static variable and manually release them
|
||||
// by calling Reset() where possible.
|
||||
static HANDLE sSectionHandle;
|
||||
static void* sWriteCopyView;
|
||||
|
||||
public:
|
||||
struct Layout final {
|
||||
Kernel32ExportsSolver mK32Exports;
|
||||
|
||||
Layout() = delete; // disallow instantiation
|
||||
};
|
||||
|
||||
static void Reset(HANDLE aNewSecionObject);
|
||||
static LauncherVoidResult Init(const nt::PEHeaders& aPEHeaders);
|
||||
|
||||
static LauncherResult<Layout*> GetView();
|
||||
static LauncherVoidResult TransferHandle(
|
||||
nt::CrossExecTransferManager& aTransferMgr,
|
||||
HANDLE* aDestinationAddress = &sSectionHandle);
|
||||
};
|
||||
|
||||
extern SharedSection gSharedSection;
|
||||
|
||||
} // namespace freestanding
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
const wchar_t kChildArg[] = L"--child";
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::freestanding;
|
||||
|
||||
template <typename T, int N>
|
||||
void PrintLauncherError(const LauncherResult<T>& aResult,
|
||||
|
@ -22,17 +23,38 @@ void PrintLauncherError(const LauncherResult<T>& aResult,
|
|||
err.mError.AsHResult(), err.mFile, err.mLine);
|
||||
}
|
||||
|
||||
#define VERIFY_FUNCTION_RESOLVED(mod, name) \
|
||||
do { \
|
||||
if (reinterpret_cast<FARPROC>(freestanding::gK32.m##name) != \
|
||||
::GetProcAddress(mod, #name)) { \
|
||||
printf( \
|
||||
"TEST-FAILED | TestCrossProcessWin | " \
|
||||
"Kernel32ExportsSolver::" #name " did not match.\n"); \
|
||||
return 1; \
|
||||
} \
|
||||
#define VERIFY_FUNCTION_RESOLVED(mod, exports, name) \
|
||||
do { \
|
||||
if (reinterpret_cast<FARPROC>(exports.m##name) != \
|
||||
::GetProcAddress(mod, #name)) { \
|
||||
printf( \
|
||||
"TEST-FAILED | TestCrossProcessWin | " \
|
||||
"Kernel32ExportsSolver::" #name " did not match.\n"); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool VerifySharedSection(SharedSection& aSharedSection) {
|
||||
LauncherResult<SharedSection::Layout*> resultView = aSharedSection.GetView();
|
||||
if (resultView.isErr()) {
|
||||
PrintLauncherError(resultView, "Failed to map a shared section");
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedSection::Layout* view = resultView.unwrap();
|
||||
|
||||
// Use a local variable of RTL_RUN_ONCE to resolve Kernel32Exports every time
|
||||
RTL_RUN_ONCE sRunEveryTime = RTL_RUN_ONCE_INIT;
|
||||
view->mK32Exports.Resolve(sRunEveryTime);
|
||||
|
||||
HMODULE k32mod = ::GetModuleHandleW(L"kernel32.dll");
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, FlushInstructionCache);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, GetSystemInfo);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, VirtualProtect);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class ChildProcess final {
|
||||
nsAutoHandle mChildProcess;
|
||||
nsAutoHandle mChildMainThread;
|
||||
|
@ -69,18 +91,24 @@ class ChildProcess final {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static RTL_RUN_ONCE sRunOnce = RTL_RUN_ONCE_INIT;
|
||||
freestanding::gK32.Resolve(sRunOnce);
|
||||
if (!freestanding::gK32.IsResolved()) {
|
||||
printf(
|
||||
"TEST-FAILED | TestCrossProcessWin | "
|
||||
"Kernel32ExportsSolver::Resolve failed.\n");
|
||||
if (!VerifySharedSection(gSharedSection)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
HMODULE k32mod = ::GetModuleHandleW(L"kernel32.dll");
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, FlushInstructionCache);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, GetSystemInfo);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, VirtualProtect);
|
||||
// Test a scenario to transfer a transferred section
|
||||
static HANDLE copiedHandle = nullptr;
|
||||
nt::CrossExecTransferManager tansferToSelf(::GetCurrentProcess());
|
||||
LauncherVoidResult result =
|
||||
gSharedSection.TransferHandle(tansferToSelf, &copiedHandle);
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "SharedSection::TransferHandle(self) failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
gSharedSection.Reset(copiedHandle);
|
||||
if (!VerifySharedSection(gSharedSection)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -175,35 +203,19 @@ int wmain(int argc, wchar_t* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
freestanding::gK32.Init();
|
||||
if (!freestanding::gK32.IsInitialized()) {
|
||||
printf(
|
||||
"TEST-FAILED | TestCrossProcessWin | "
|
||||
"Kernel32ExportsSolver initialization failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
LauncherVoidResult writeResult =
|
||||
freestanding::gK32.Transfer(transferMgr, &freestanding::gK32);
|
||||
if (writeResult.isErr()) {
|
||||
PrintLauncherError(writeResult, "Kernel32ExportsSolver::Transfer failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
writeResult =
|
||||
LauncherVoidResult result =
|
||||
transferMgr.Transfer(&ChildProcess::sExecutableImageBase,
|
||||
&remoteImageBase.inspect(), sizeof(HMODULE));
|
||||
if (writeResult.isErr()) {
|
||||
PrintLauncherError(writeResult,
|
||||
"ChildProcess::WriteData(Imagebase) failed");
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "ChildProcess::WriteData(Imagebase) failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DWORD childPid = childProcess.GetProcessId();
|
||||
|
||||
DWORD* readOnlyData = const_cast<DWORD*>(&ChildProcess::sReadOnlyProcessId);
|
||||
writeResult = transferMgr.Transfer(readOnlyData, &childPid, sizeof(DWORD));
|
||||
if (writeResult.isOk()) {
|
||||
result = transferMgr.Transfer(readOnlyData, &childPid, sizeof(DWORD));
|
||||
if (result.isOk()) {
|
||||
printf(
|
||||
"TEST-UNEXPECTED | TestCrossProcessWin | "
|
||||
"A constant was located in a writable section.");
|
||||
|
@ -220,12 +232,28 @@ int wmain(int argc, wchar_t* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
writeResult = transferMgr.Transfer(readOnlyData, &childPid, sizeof(DWORD));
|
||||
if (writeResult.isErr()) {
|
||||
PrintLauncherError(writeResult, "ChildProcess::WriteData(PID) failed");
|
||||
result = transferMgr.Transfer(readOnlyData, &childPid, sizeof(DWORD));
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "ChildProcess::WriteData(PID) failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
// Define a scope for |sharedSection| to resume the child process after
|
||||
// the section is deleted in the parent process.
|
||||
result = gSharedSection.Init(transferMgr.LocalPEHeaders());
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "SharedSection::Init failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = gSharedSection.TransferHandle(transferMgr);
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "SharedSection::TransferHandle failed");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!childProcess.ResumeAndWaitUntilExit()) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -655,10 +655,8 @@ class MOZ_RAII PEHeaders final {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
nsTHashtable<nsStringCaseInsensitiveHashKey> GenerateDependentModuleSet() {
|
||||
nsTHashtable<nsStringCaseInsensitiveHashKey> dependentModuleSet;
|
||||
|
||||
template <typename CallbackT>
|
||||
void EnumImportChunks(const CallbackT& aCallback) const {
|
||||
for (PIMAGE_IMPORT_DESCRIPTOR curImpDesc = GetImportDirectory();
|
||||
IsValid(curImpDesc); ++curImpDesc) {
|
||||
auto curName = mIsImportDirectoryTampered
|
||||
|
@ -668,9 +666,17 @@ class MOZ_RAII PEHeaders final {
|
|||
continue;
|
||||
}
|
||||
|
||||
dependentModuleSet.PutEntry(GetLeafName(NS_ConvertASCIItoUTF16(curName)));
|
||||
aCallback(curName);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
nsTHashtable<nsStringCaseInsensitiveHashKey> GenerateDependentModuleSet()
|
||||
const {
|
||||
nsTHashtable<nsStringCaseInsensitiveHashKey> dependentModuleSet;
|
||||
EnumImportChunks([&dependentModuleSet](const char* aModule) {
|
||||
dependentModuleSet.PutEntry(GetLeafName(NS_ConvertASCIItoUTF16(aModule)));
|
||||
});
|
||||
return dependentModuleSet;
|
||||
}
|
||||
#endif // defined(MOZILLA_INTERNAL_API)
|
||||
|
@ -1530,6 +1536,71 @@ class RtlAllocPolicy {
|
|||
[[nodiscard]] bool checkSimulatedOOM() const { return true; }
|
||||
};
|
||||
|
||||
class AutoMappedView final {
|
||||
void* mView;
|
||||
|
||||
void Unmap() {
|
||||
if (!mView) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
::UnmapViewOfFile(mView);
|
||||
#else
|
||||
NTSTATUS status = ::NtUnmapViewOfSection(nt::kCurrentProcess, mView);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
::RtlSetLastWin32Error(::RtlNtStatusToDosError(status));
|
||||
}
|
||||
#endif
|
||||
mView = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit AutoMappedView(void* aView) : mView(aView) {}
|
||||
|
||||
AutoMappedView(HANDLE aSection, ULONG aProtectionFlags) : mView(nullptr) {
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
mView = ::MapViewOfFile(aSection, aProtectionFlags, 0, 0, 0);
|
||||
#else
|
||||
SIZE_T viewSize = 0;
|
||||
NTSTATUS status = ::NtMapViewOfSection(aSection, nt::kCurrentProcess,
|
||||
&mView, 0, 0, nullptr, &viewSize,
|
||||
ViewUnmap, 0, aProtectionFlags);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
::RtlSetLastWin32Error(::RtlNtStatusToDosError(status));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
~AutoMappedView() { Unmap(); }
|
||||
|
||||
// Allow move & Disallow copy
|
||||
AutoMappedView(AutoMappedView&& aOther) : mView(aOther.mView) {
|
||||
aOther.mView = nullptr;
|
||||
}
|
||||
AutoMappedView& operator=(AutoMappedView&& aOther) {
|
||||
if (this != &aOther) {
|
||||
Unmap();
|
||||
mView = aOther.mView;
|
||||
aOther.mView = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
AutoMappedView(const AutoMappedView&) = delete;
|
||||
AutoMappedView& operator=(const AutoMappedView&) = delete;
|
||||
|
||||
explicit operator bool() const { return !!mView; }
|
||||
template <typename T>
|
||||
T* as() {
|
||||
return reinterpret_cast<T*>(mView);
|
||||
}
|
||||
|
||||
void* release() {
|
||||
void* p = mView;
|
||||
mView = nullptr;
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nt
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче