tor-browser

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

WindowsStackCookie.h (2755B)


      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 #ifndef mozilla_WindowsStackCookie_h
      8 #define mozilla_WindowsStackCookie_h
      9 
     10 #if defined(DEBUG) && defined(_M_X64) && !defined(__MINGW64__)
     11 
     12 #  include <windows.h>
     13 #  include <winnt.h>
     14 
     15 #  include <cstdint>
     16 
     17 namespace mozilla {
     18 
     19 // This function does pattern matching on the instructions generated for a
     20 // given function, to detect whether it uses stack buffers. More specifically,
     21 // it looks for instructions that characterize the presence of stack cookie
     22 // checks. When this function returns true, it can be a false positive, but we
     23 // use a rather long pattern to make false positives very unlikely.
     24 // Note: Do not use this function inside the function that lives at
     25 //       aFunctionAddress, as that could introduce stack buffers.
     26 // Note: The pattern we use does not work for MinGW builds.
     27 inline bool HasStackCookieCheck(uintptr_t aFunctionAddress) {
     28  DWORD64 imageBase{};
     29  auto entry = ::RtlLookupFunctionEntry(
     30      reinterpret_cast<DWORD64>(aFunctionAddress), &imageBase, nullptr);
     31  if (entry && entry->EndAddress > entry->BeginAddress + 14) {
     32    auto begin = reinterpret_cast<uint8_t*>(imageBase + entry->BeginAddress);
     33    auto end = reinterpret_cast<uint8_t*>(imageBase + entry->EndAddress - 14);
     34    for (auto pc = begin; pc != end; ++pc) {
     35      // 48 8b 05 XX XX XX XX:      mov rax, qword ptr [rip + XXXXXXXX]
     36      if ((pc[0] == 0x48 && pc[1] == 0x8b && pc[2] == 0x05) &&
     37          // 48 31 e0:              xor rax, rsp
     38          (pc[7] == 0x48 && pc[8] == 0x31 && pc[9] == 0xe0) &&
     39          // 48 89 (8|4)4 24 ...:   mov qword ptr [rsp + ...], rax
     40          (pc[10] == 0x48 && pc[11] == 0x89 &&
     41           (pc[12] == 0x44 || pc[12] == 0x84) && pc[13] == 0x24)) {
     42        return true;
     43      }
     44    }
     45  }
     46  // In x64, if there is no entry, then there is no stack allocation, hence
     47  // there is no stack cookie check: "Table-based exception handling requires a
     48  // table entry for all functions that allocate stack space or call another
     49  // function (for example, nonleaf functions)."
     50  // https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64
     51  // Similarly, if the gap between begin and end is less than 14 bytes, then
     52  // the function cannot contain the pattern we are looking for, therefore it
     53  // has no cookie check either.
     54  return false;
     55 }
     56 
     57 }  // namespace mozilla
     58 
     59 #endif  // defined(DEBUG) && defined(_M_X64) && !defined(__MINGW64__)
     60 
     61 #endif  // mozilla_WindowsStackCookie_h