Bug 1842999 - Part 25: Support testing elements are present in resizable typed arrays...
[gecko.git] / mozglue / misc / ImportDir.h
blob6f7721d9660055e31d33970353dc13e5937f9dd8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "mozilla/NativeNt.h"
8 #include "mozilla/WinHeaderOnlyUtils.h"
10 namespace mozilla {
11 namespace detail {
13 inline LauncherResult<nt::DataDirectoryEntry> GetImageDirectoryViaFileIo(
14 const nsAutoHandle& aImageFile, const uint32_t aOurImportDirectoryRva) {
15 OVERLAPPED ov = {};
16 ov.Offset = aOurImportDirectoryRva;
18 DWORD bytesRead;
19 nt::DataDirectoryEntry result;
20 if (!::ReadFile(aImageFile, &result, sizeof(result), &bytesRead, &ov) ||
21 bytesRead != sizeof(result)) {
22 return LAUNCHER_ERROR_FROM_LAST();
25 return result;
28 } // namespace detail
30 /**
31 * This function ensures that the import directory of a loaded binary image
32 * matches the version that is found in the original file on disk. We do this
33 * to prevent tampering by third-party code.
35 * Yes, this function may perform file I/O on the critical path during
36 * startup. A mitigating factor here is that this function must be called
37 * immediately after creating a process using the image specified by
38 * |aFullImagePath|; by this point, the system has already paid the price of
39 * pulling the image file's contents into the page cache.
41 * @param aFullImagePath Wide-character string containing the absolute path
42 * to the binary whose import directory we are touching.
43 * @param aTransferMgr Encapsulating the transfer from the current process to
44 * the child process whose import table we are touching.
46 inline LauncherVoidResult RestoreImportDirectory(
47 const wchar_t* aFullImagePath, nt::CrossExecTransferManager& aTransferMgr) {
48 uint32_t importDirEntryRva;
49 PIMAGE_DATA_DIRECTORY importDirEntry =
50 aTransferMgr.LocalPEHeaders().GetImageDirectoryEntryPtr(
51 IMAGE_DIRECTORY_ENTRY_IMPORT, &importDirEntryRva);
52 if (!importDirEntry) {
53 return LAUNCHER_ERROR_FROM_WIN32(ERROR_BAD_EXE_FORMAT);
56 nsAutoHandle file(::CreateFileW(aFullImagePath, GENERIC_READ, FILE_SHARE_READ,
57 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
58 nullptr));
59 if (file.get() == INVALID_HANDLE_VALUE) {
60 return LAUNCHER_ERROR_FROM_LAST();
63 // Why do we use file I/O here instead of a memory mapping? The simple reason
64 // is that we do not want any kernel-mode drivers to start tampering with file
65 // contents under the belief that the file is being mapped for execution.
66 // Windows 8 supports creation of file mappings using the SEC_IMAGE_NO_EXECUTE
67 // flag, which may help to mitigate this, but we might as well just support
68 // a single implementation that works everywhere.
69 LauncherResult<nt::DataDirectoryEntry> realImportDirectory =
70 detail::GetImageDirectoryViaFileIo(file, importDirEntryRva);
71 if (realImportDirectory.isErr()) {
72 return realImportDirectory.propagateErr();
75 nt::DataDirectoryEntry toWrite = realImportDirectory.unwrap();
77 { // Scope for prot
78 AutoVirtualProtect prot = aTransferMgr.Protect(
79 importDirEntry, sizeof(IMAGE_DATA_DIRECTORY), PAGE_READWRITE);
80 if (!prot) {
81 return LAUNCHER_ERROR_FROM_MOZ_WINDOWS_ERROR(prot.GetError());
84 LauncherVoidResult writeResult = aTransferMgr.Transfer(
85 importDirEntry, &toWrite, sizeof(IMAGE_DATA_DIRECTORY));
86 if (writeResult.isErr()) {
87 return writeResult.propagateErr();
91 return Ok();
94 } // namespace mozilla