tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ImportDir.h (3712B)


      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/. */
      6 
      7 #include "mozilla/NativeNt.h"
      8 #include "mozilla/WinHeaderOnlyUtils.h"
      9 
     10 namespace mozilla {
     11 namespace detail {
     12 
     13 inline LauncherResult<nt::DataDirectoryEntry> GetImageDirectoryViaFileIo(
     14    const nsAutoHandle& aImageFile, const uint32_t aOurImportDirectoryRva) {
     15  OVERLAPPED ov = {};
     16  ov.Offset = aOurImportDirectoryRva;
     17 
     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();
     23  }
     24 
     25  return result;
     26 }
     27 
     28 }  // namespace detail
     29 
     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.
     34 *
     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.
     40 *
     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.
     45 */
     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);
     54  }
     55 
     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();
     61  }
     62 
     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();
     73  }
     74 
     75  nt::DataDirectoryEntry toWrite = realImportDirectory.unwrap();
     76 
     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());
     82    }
     83 
     84    LauncherVoidResult writeResult = aTransferMgr.Transfer(
     85        importDirEntry, &toWrite, sizeof(IMAGE_DATA_DIRECTORY));
     86    if (writeResult.isErr()) {
     87      return writeResult.propagateErr();
     88    }
     89  }
     90 
     91  return Ok();
     92 }
     93 
     94 }  // namespace mozilla