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