├── README.md ├── img ├── SL2logo.png └── confirm_flow.png ├── src ├── api_hook.cpp ├── callback_linux.cpp ├── callback_windows.cpp ├── code_coop_linux.cpp ├── code_coop_windows.cpp ├── convention.cpp ├── cppeh.cpp ├── data_symbl.cpp ├── delay_load.cpp ├── fptr.cpp ├── inc.cpp ├── inc.h ├── jit.cpp ├── load_time_dynlnk_linux.cpp ├── load_time_dynlnk_windows.cpp ├── mem.cpp ├── multithreading_linux32.cpp ├── multithreading_linux64.cpp ├── multithreading_windows.cpp ├── ret.cpp ├── run_time_dynlnk.cpp ├── seh.cpp ├── setup.cpp ├── setup.h ├── signal.cpp ├── switch.cpp ├── tail_call.cpp ├── tls_callback.cpp ├── unmatched_pair.cpp ├── veh.cpp └── vtbl_call.cpp └── xu19-confirm.pdf /README.md: -------------------------------------------------------------------------------- 1 | alt text 2 | 3 | # ConFIRM 4 | ConFIRM (Control-Flow Integrity Relevance Metrics) is a new evaluation methodology and microbenchmarking suite for assessing compatibility, applicability, and relevance of *control-flow integrity* (CFI) protections for preserving the intended semantics of software while protecting it from abuse. 5 | 6 | ## Compatibility Metrics 7 | To measure compatibility of CFI mechanisms, we propose a set of metrics that each includes one or more code features from either C/C++ source code or compiled assembly code. We derived this feature set by attempting to apply many CFI solutions to large software products, then manually testing the functionalities of the resulting hardened software for correctness, and finally debugging each broken functionality step-wise at the assembly level to determine what caused the hardened code to fail. Since many failures manifest as subtle 8 | forms of register or memory corruption that only cause the program to crash or malfunction long after the failed operation completes, this debugging constitutes many hundreds of person-hours amassed over several years of development experience involving CFI-protected software. 9 | 10 | 11 | **Table 1: ConFIRM compatibility metrics** 12 | 13 | | Compatibility metric | Real-world software examples | 14 | |----------------------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 15 | | Function Pointers | 7-Zip, Adobe Reader, Apache, Calculator, Chrome, Dropbox, Firefox, JVM, Notepad, MS Paint, MS PowerPoint, PotPlayer, PowerShell, PuTTY, Skype, TeXstudio, UPX, Visual Studio, Windows Defender, WinSCP | 16 | | Callbacks | 7-Zip, Adobe Reader, Apache, Calculator, Chrome, Dropbox, Firefox, JVM, Notepad, MS Paint, MS PowerPoint, PotPlayer, PowerShell, PuTTY, TeXstudio, Visual Studio, Windows Defender, WinSCP | 17 | | Dynamic Linking | 7-Zip, Adobe Reader, Apache, Calculator, Chrome, Dropbox, Firefox, JVM, Notepad, MS Paint, MS PowerPoint, PotPlayer, PowerShell, PuTTY, Skype, TeXstudio, UPX, Visual Studio, Windows Defender, WinSCP | 18 | | Delay-Loading | Adobe Reader, Calculator, Chrome, Firefox, JVM, MS Paint, MS PowerPoint, PotPlayer, Visual Studio, WinSCP | 19 | | Exporting/Importing Data | 7-Zip, Apache, Calculator, Chrome, Dropbox, Firefox, MS Paint, MS PowerPoint, PowerShell, TeXstudio, UPX, Visual Studio | 20 | | Virtual Functions | 7-Zip, Adobe Reader, Calculator, Chrome, Dropbox, Firefox, JVM, Notepad, MS Paint, MS PowerPoint, PotPlayer, PowerShell, PuTTY, TeXstudio, Visual Studio, Windows Defender, WinSCP | 21 | | CODE-COOP Attack | Programs built on GTK+ or Microsoft COM can pass objects to trusted modules as arguments. | 22 | | Tail Calls | Mainstream compilers provide options for tail call optimization. e.g. /O2 in MSVC, -O2 in GCC, and -O2 in LLVM. | 23 | | Switch-Case Statements | 7-Zip, Adobe Reader, Apache, Calculator, Chrome, Dropbox, Firefox, JVM, MS Paint, MS PowerPoint, PotPlayer, PuTTY, TeXstudio, Visual Studio, WinSCP | 24 | | Returns | Every benign program has returns. | 25 | | Unmatched Call/Return Pairs | Adobe Reader, Apache, Chrome, Firefox, JVM, MS PowerPoint, Visual Studio | 26 | | Exceptions | 7-Zip, Adobe Reader, Apache, Calculator, Chrome, Dropbox, Firefox, JVM, MS Paint, MS PowerPoint, PotPlayer, PowerShell, PuTTY, Skype, TeXstudio, Visual Studio, Windows Defender, WinSCP | 27 | | Calling Conventions | Every program adopts one or more calling convention. | 28 | | Multithreading | 7-Zip, Adobe Reader, Apache, Calculator, Chrome, Dropbox, Firefox, JVM, Notepad, MS Paint, MS PowerPoint, PotPlayer, PowerShell, PuTTY, Skype, TeXstudio, UPX, Visual Studio, Windows Defender, WinSCP | 29 | | TLS Callbacks | Adobe Reader, Chrome, Firefox, MS Paint, TeXstudio, UPX | 30 | | Position-Independent Code | 7-Zip, Adobe Reader, Apache, Calculator, Chrome, Dropbox, Firefox, JVM, Notepad, MS Paint, MS PowerPoint, PotPlayer, PowerShell, PuTTY, Skype, TeXstudio, UPX, Visual Studio, Windows Defender, WinSCP | 31 | | Memory Protection | 7-Zip, Adobe Reader, Apache, Chrome, Dropbox, Firefox, MS PowerPoint, PotPlayer, TeXstudio, Visual Studio, Windows Defender, WinSCP | 32 | | JIT Compiler | Adobe Flash, Chrome, Dropbox, Firefox, JVM, MS PowerPoint, PotPlayer, PowerShell, Skype, Visual Studio, WinSCP | 33 | | self-Unpacking | Programs decompressed by self-extractors (e.g., UPX, NSIS). | 34 | | Windows API Hooking | Microsoft Office family software, including MS Excel, MS PowerPoint, etc. | 35 | 36 | Table 1 presents the resulting list of code features organized into one row for each root cause of failure. Column two additionally lists some widely available, commodity software products where each of these features can be observed in nonmalicious software in the wild. This demonstrates that each feature is representative of real-world software functionalities that must be preserved by CFI implementations in order for their protections to be usable and relevant in contexts that deploy these and similar products. 37 | 38 | ### 1. Indirect Branches 39 | We first discuss compatibility metrics related to the code feature of greatest relevance to most CFI works: indirect branches. Indirect branches are control-flow transfers whose destination addresses are computed at runtime—via pointer arithmetic and/or memory-reads. Such transfers tend to be of high interest to attackers, since computed destinations are more prone to manipulation. CFI defenses therefore guard indirect branches to ensure that they target permissible destinations at runtime. Indirect branches are commonly categorized into three classes: indirect calls, indirect jumps, and returns. 40 | 41 | **Table 2: Source code compiled to indirect call** 42 | 43 | | | Source code | | Assembly code | 44 | |--------------- |------------------------ |--- |--------------- | 45 | | 1 | void foo() { return; } | | | 46 | | 2 | void bar() { return; } | | | 47 | | 3 | void main() { | | | 48 | | 4 |     void (*fptr)(); | 1 | ... | 49 | | 5 |     int n = input(); | 2 | call _input | 50 | | 6 |     if (n) | 3 | test eax, eax | 51 | | 7 |         fptr = foo; | 4 | mov edx, offset_foo | 52 | | 8 |     else | 5 | mov ecx, offset_bar | 53 | | 9 |         fptr = bar; | 6 | cmovnz ecx, edx | 54 | | 10 |     fptr(); | 7 | call ecx | 55 | | 11 | } | 8 | ... | 56 | 57 | Table 2 shows a simple example of source code being compiled to an indirect call. The function called at source line 5 depends on user input. This prevents the compiler from generating a direct branch that targets a fixed memory address at compile time. Instead, the compiler generates a registerindirect call (assembly line 7) whose target is computed at runtime. While this is one common example of how indirect branches arise, in practice they are a result of many different programming idioms, discussed below. 58 | 59 | **Function Pointers.** Calls through function pointers typically compile to indirect calls. For example, using gcc with the `-O2` option generates register-indirect calls for function pointers, and MSVC does so by default. 60 | 61 | **Callbacks.** Event-driven programs frequently pass function pointers to external modules or the OS, which the receiving code later dereferences and calls in response to an event. These callback pointers are generally implemented by using function pointers in C, or as method references in C++. Callbacks can pose special problems for CFI, since the call site is not within the module that generated the pointer. If the call site is within a module that cannot easily be modified (e.g., the OS kernel), it must be protected in some other way, such as by sanitizing and securing the pointer before it is passed. 62 | 63 | **Dynamic Linking.** Dynamically linked shared libraries reduce program size and improve locality. But dynamic linking has been a challenge for CFI compatibility because CFG edges that span modules may be unavailable statically. 64 | 65 | In Windows, *dynamically linked libraries* (DLLs) can be loaded into memory at load time or runtime. In load-time dynamic linking, a function call from a module to an exported DLL function is usually compiled to a memory-indirect call targeting an address stored in the module’s *import address table* (IAT). But if this function is called more than once, the compiler first moves the target address to a register, and then generates register-indirect calls to improve execution performance. In run-time dynamic linking, a module calls APIs, such as `LoadLibrary()`, to load the DLL at runtime. When loaded into memory, the module calls the `GetProcAddress()` API to retrieve the address of the exported function, and then calls the exported function using the function pointer returned by `GetProcAddress()`. 66 | 67 | Additionally, MSVC (since version 6.0) provides linker support for delay-loaded DLLs using the `/DELAYLOAD` linker option. These DLLs are not loaded into memory until one of their exported functions is invoked. 68 | 69 | In Linux, a module calls functions exported by a shared library by calling a stub in its *procedure linkage table* (PLT). Each stub contains a memory-indirect jump whose target depends on the writable, lazy-bound *global offset table* (GOT). As in Windows, an application can also load a module at runtime using function `dlopen()`, and retrieve an exported symbol using function `dlsym()`. 70 | 71 | Supporting dynamic and delay-load linkage is further complicated by the fact that shared libraries can also export data pointers within their export tables in both Linux and Windows. CFI solutions that modify export tables must usually treat code and data pointers differently, and must therefore somehow distinguish the two types to avoid data corruptions. 72 | 73 | **Virtual Functions.** Polymorphism is a key feature of OOP languages, such as C++. Virtual functions are used to support runtime polymorphism, and are implemented by C++ compilers using a form of late binding embodied as *virtual tables* (vtables). The tables are populated by code pointers to virtual function bodies. When an object calls a virtual function, it indexes its vtable by a function-specific constant, and flows control to the memory address read from the table. At the assembly level, this manifests as a memory-indirect call. The ubiquity and complexity of this process has made vtable hijacking a favorite exploit strategy of attackers. 74 | 75 | Some CFI and vtable protections address vtable hijacking threats by guarding call sites that read vtables, thereby detecting potential vtable corruption at time-of-use. Others seek to protect vtable integrity directly by guarding writes to them. However, both strategies are potentially susceptible to COOP and CODE-COOP attacks, which replace one vtable with another that is legal but is not the one the original code intended to call. The defense problem is further complicated by the fact that many large classes of software 76 | (e.g., GTK+ and Microsoft COM) rely upon dynamically generated vtables. CFI solutions that write-protect vtables or whose guards check against a static list of permitted vtables are incompatible with such software. 77 | 78 | **Tail Calls.** Modern C/C++ compilers can optimize tail-calls by replacing them with jumps. Row 8 of Table 1 lists relevant compiler options. With these options, callees can return directly to ancestors of their callers in the call graph, rather than to their callers. These mismatched call/return pairs affect precision of some CFG recovery algorithms. 79 | 80 | **Switch-case Statements.** Many C/C++ compilers optimize switch-case statements via a static dispatch table populated with pointers to case-blocks. When the switch is executed, it calculates a dispatch table index, fetches the indexed code pointer, and jumps to the correct case-block. This introduces memory-indirect jumps that refer to code pointers not contained in any vtable, and that do not point to function boundaries. CFI solutions that compare code pointers to a whitelist of function boundaries can therefore cause the switch-case code to malfunction. Solutions that permit unrestricted indirect jumps within each local function risk unsafety, since large functions can contain abusable gadgets. 81 | 82 | **Returns.** Nearly every benign program has returns. Unlike indirect branches whose target addresses are stored in registers or non-writable data sections, return instructions read their destination addresses from the stack. Since stacks are typically writable, this makes return addresses prime targets for malicious corruption. 83 | 84 | On Intel-based CISC architectures, return instructions have one of the shortest encodings (1 byte), complicating the efforts of source-free solutions to replace them in-line with secured equivalent instruction sequences. Additionally, many hardware architectures heavily optimize the behavior of returns (e.g., via speculative execution powered by shadow stacks for call/return matching). Source-aware CFI solutions that replace returns with some other instruction sequence can therefore face stiff performance penalties by losing these optimization advantages. 85 | 86 | **Unmatched call/return Pairs.** Control-flow transfer mechanisms, including exceptions and setjmp/longjmp, can yield flows in which the relation between executed call instructions and executed return instructions is not one-to-one. For example, exception-handling implementations often pop stack frames from multiple calls, followed by a single return to the parent of the popped call chain. Shadow stack defenses that are implemented based on traditional call/return matching may be incompatible with such mechanisms. 87 | 88 | ### 2. Other Metrics 89 | While indirect branches tend to be the primary code feature of interest to CFI attacks and defenses, there are many other code features that can also pose control-flow security problems, or that can become inadvertently corrupted by CFI code transformation algorithms, and that therefore pose compatibility limitations. Some important examples are discussed below. 90 | 91 | **Multithreading.** With the rise of multicore hardware, multithreading has become a centerpiece of software efficiency. Unfortunately, concurrent code execution poses some serious safety problems for many CFI algorithms. 92 | 93 | For example, in order to take advantage of hardware callreturn optimization, most CFI algorithms produce code containing guarded return instructions. The guards check the return address before executing the return. However, on parallelized architectures with flat memory spaces, this is unsafe because any thread can potentially write to any other (concurrently executing) thread’s return address at any 94 | time. This introduces a TOCTOU vulnerability in which an attacker-manipulated thread corrupts a victim thread’s return address after the victim thread’s guard code has checked it but before the guarded return executes. We term this a cross-thread stack-smashing attack. Since nearly all modern architectures combine concurrency, flat memory spaces, and returns, this leaves almost all CFI solutions either inapplicable, unsafe, or unacceptably inefficient for a large percentage of modern production software. 95 | 96 | **Position-Independent Code.** *Position-independent code* (PIC) is designed to be relocatable after it is statically generated, and is a standard practice in the creation of shared libraries. Unfortunately, the mechanisms that implement PIC often prove brittle to code transformations commonly employed for source-free CFI enforcement. For example, PIC often achieves its position independence by dynamically computing its own virtual memory address (e.g., by performing a call to itself and reading the pushed return address from the stack), and then performing pointer arithmetic to locate other code or data at fixed offsets relative to itself. This procedure 97 | assumes that the relative positions of PIC code and data are invariant even if the base address of the PIC block changes. 98 | 99 | However, CFI transforms typically violate this assumption by introducing guard code that changes the sizes of code blocks, and therefore their relative positions. To solve this, PIC-compatible CFI solutions must detect the introspection and pointer arithmetic operations that implement PIC and adjust them to compute corrected pointer values. Since there are typically an unlimited number of ways to perform these computations at both the source and native code levels, CFI detection of these computations is inevitably heuristic, allowing some PIC instantiations to malfunction. 100 | 101 | **Exceptions.** Exception raising and handling is a mainstay of modern software design, but introduces control-flow patterns that can be problematic for CFI policy inference and enforcement. Object-oriented languages, such as C++, boast first-class exception machinery, whereas standard C programs typically realize exceptional control-flows with gotos, longjumps, and signals. In Linux, compilers (e.g., gcc) implement C++ exception handling in a table-driven approach. The compiler statically generates read-only tables that hold 102 | exception-handling information. For instance, gcc produces a `gcc_except_table` comprised of *language-specific data areas* (LSDAs). Each LSDA contains various exception-related information, including pointers to exception handlers. 103 | 104 | In Windows, *structured exception handling* (SEH) extends the standard C language with first-class support for both hardware and software exceptions. SEH uses stack-based exception nodes, wherein exception handlers form a linked list on the stack, and the list head is stored in the *thread information block* (TIB). Whenever an exception occurs, the OS fetches the list head and walks through the SEH list to find a suitable handler for the thrown exception. Without proper protection, these exception handlers on the stack can potentially be overwritten by an attacker. By triggering an exception, the attacker can then redirect the control-flow to arbitrary code. CFI protection against these SEH attacks is complicated by the fact that code outside the vulnerable module (e.g., in the OS and/or system libraries) uses pointer arithmetic to fetch, decode, and call these pointers during exception handling. Thus, suitable protections must typically span multiple modules, and perhaps the OS kernel. 105 | 106 | From Windows XP onward, applications have additionally leveraged *vectored exception handling* (VEH). Unlike SEH, VEH is not stack-based; applications register a global handler chain for VEH exceptions with the OS, and these handlers are invoked by the OS by interrupting the application’s current execution, no matter where the exception occurs within a frame. 107 | 108 | There are at least two features of VEH that are potentially exploitable by attackers. First, to register a vectored exception handler, the application calls an API `AddVecoredExceptionHandler()` that accepts a callback function pointer parameter that points to the handler code. Securing this pointer requires some form of inter-module callback protection. 109 | 110 | Second, the VEH handler-chain data structure is stored in the application’s writable heap memory, making the handler chain data directly susceptible to data corruption attacks. Windows protects the handlers somewhat by obfuscating them using the `EncodePointer()` API. However, `EncodePointer()` does not implement a cryptographically secure function (since doing so would impose high overhead); it typically returns the XOR of the input pointer with a processspecific secret. This secret is not protected against memory disclosure attacks; it is potentially derivable from disclosure of any encoded pointer with value known to the attacker (since XOR is invertible), and it is stored in the *process environment block* (PEB), which is readable by the process and therefore by an attacker armed with an information disclosure exploit. With this secret, the attacker can overwrite the heap with a properly obfuscated malicious pointer, and thereby take control of the application. 111 | 112 | From a compatibility perspective, CFI protections that do not include first-class support for these various exceptionhandling mechanisms often conservatively block unusual control-flows associated with exceptions. This can break important application functionalities, making the protections unusable for large classes of software that use exceptions. 113 | 114 | **Calling Conventions.** CFI guard code typically instruments call and return sites in the target program. In order to preserve the original program’s functionality, this guard code must therefore respect the various calling conventions that might be implemented by calls and returns. Unfortunately, many solutions to this problem make simplifying assumptions about the potential diversity of calling conventions in order to achieve acceptable performance. For example, a CFI solution whose guard code uses `EDX` as a scratch register might suddenly fail when applied to code whose calling convention passes arguments in `EDX`. Adapting the solution to save and restore `EDX` to support the new calling convention can lead to tens of additional instructions per call, including additional memory accesses, and therefore much higher overhead. 115 | 116 | The C standard calling convention (`cdecl`) is caller-pop, pushes arguments right-to-left onto the stack, and returns primitive values in an architecture-specific register (`EAX` on Intel). Each architecture also specifies a set of caller-save and callee-save registers. Caller-popped calling conventions are important for implementing variadic functions, since callees can remain unaware of argument list lengths. 117 | 118 | Callee-popped conventions include `stdcall`, which is the standard convention of the Win32 API, and `fastcall`, which passes the first two arguments via registers rather than the stack to improve execution speed. In OOP languages, every nonstatic member function has a hidden *this pointer* argument that points to the current object. The `thiscall` convention passes the this pointer in a register (`ECX` on Intel). 119 | 120 | Calling conventions on 64-bit architectures implement several refinements of the 32-bit conventions. Linux and Windows pass up to 14 and 4 parameters, respectively, in registers rather than on the stack. To allow callees to optionally spill these parameters, the caller additionally reserves a *red zone* (Linux) or 32-byte *shadow space* (Windows) for callee temporary storage. 121 | 122 | Highly optimized programs also occasionally adopt nonstandard, undocumented calling conventions, or even blur function boundaries entirely (e.g., by performing various forms of function in-lining). For example, some C compilers support language extensions (e.g., MSVC’s `naked` declaration) that yield binary functions with no prologue or epilogue code, and therefore no standard calling convention. Such code can have subtle dependencies on non-register processor elements, such as requiring that certain Intel status flags be preserved across calls. Many CFI solutions break such code by in-lining call site guards that violate these undocumented conventions. 123 | 124 | **TLS Callbacks.** Multithreaded programs require efficient means to manipulate thread-local data without expensive locking. Using *thread local storage* (TLS), applications export one or more TLS callback functions that are invoked by the OS for thread initialization or termination. These functions form a null-terminated table whose base is stored in the PE header. For compiler-based CFI solutions, the TLS callback functions do not usually need extra protection, since both the PE header and the TLS callback table are in unwritable memory. But source-free solutions must ensure that TLS callbacks constitute policy-permitted control-flows at runtime. 125 | 126 | **Memory Protection.** Modern OSes provide APIs for memory page allocation (e.g., `VirtualAlloc` and `mmap`) and permission changes (e.g., `VirtualProtect` and `mprotect`). However, memory pages changed from writable to executable, or to simultaneously writable and executable, can potentially be abused by attackers to bypass DEP defenses and execute attacker-injected code. Many software applications nevertheless rely upon these APIs for legitimate purposes (see Table 1), so conservatively disallowing access to them introduces many compatibility problems. Relevant CFI mechanisms must therefore carefully enforce memory access policies that permit virtual memory management but block code-injection attacks. 127 | 128 | **Runtime Code Generation.** Most CFI algorithms achieve acceptable overheads by performing code generation strictly statically. The statically generated code includes fixed runtime guards that perform small, optimized computations to validate dynamic control-flows. However, this strategy breaks down when target programs generate new code dynamically and attempt to execute it, since the generated code might not include CFI guards. *Runtime code generation* (RCG) is therefore conservatively disallowed by most CFI solutions, with the expectation that RCG is only common in a few, specialized application domains, which can receive specialized protections. 129 | 130 | Unfortunately, our analysis of commodity software products indicates that RCG is becoming more prevalent than is commonly recognized. In general, we encountered RCG compatibility limitations in at least three main forms across a variety of COTS products: 131 | 132 | 1. Although typically associated with web browsers, *just-in-time* (JIT) compilation has become increasingly relevant as an optimization strategy for many languages, including Python, Java, the Microsoft .NET family of languages (e.g., C#), and Ruby. Software containing any component or module written in any JIT-compiled language frequently cannot be protected with CFI. 133 | 134 | 2. Mobile code is increasingly space-optimized for quick ransport across networks. *Self-unpacking executables* are therefore a widespread source of RCG. At runtime, self-unpacking executables first decompress archived data sections to code, and then map the code into writable and executable memory. This entails a dynamic creation of fresh code bytes. Large, component-driven programs sometimes store rarely used components as self-unpacking code that decompresses into memory whenever needed, and is deallocated after use. For example, NSIS installers pack separate modules supporting different install configurations, and unpack them at runtime as-needed for reduced size. Antivirus defenses hence struggle to distinguish benign NSIS installers from malicious ones. 135 | 136 | 3. Component-driven software also often performs a variety of obscure *API hooking* initializations during component loading and clean-up, which are implemented using RCG. As an example, Microsoft Office software dynamically redirects all calls to certain system API functions within its address space to dynamically generated wrapper functions. This allows it to modify the behaviors of late-loaded components without having to recompile them all each time the main application is updated. 137 |

138 | To hook a function *f* within an imported system DLL (e.g., `ntdll.dll`), it first allocates a fresh memory page *f'* and sets it both writable and executable. It next copies the first five code bytes from *f* to *f'*, and writes an instruction at *f'*+5 that jumps to *f*+5. Finally, it changes *f* to be writable and executable, and overwrites the first five code bytes of *f* with an instruction that jumps to *f'*. All subsequent calls to *f* are thereby redirected to *f'*, where new functionality can later be added dynamically before *f'* jumps to the preserved portion of *f*. 139 |

140 | Such hooking introduces many dangers that are difficult for CFI protections to secure without breaking the application or its components. Memory pages that are simultaneously writable and executable are susceptible to codeinjection attacks, as described previously. The RCG that implements the hooks includes unprotected jumps, which must be secured by CFI guard code. However, the guard code itself must be designed to be rewritable by more hooking, including placing instruction boundaries at addresses expected by the hooking code (*f*+5 in the above example). No known CFI algorithm can presently handle these complexities. 141 | 142 | ### 3. Compositional Defense Evaluation 143 | Some CFI solutions compose CFI controls with other defense layers, such as randomization-based defenses. Randomization defenses can be susceptible to other forms of attack, such as memory disclosure attacks. ConFIRM does not test such attacks, since their implementations are usually specific to each defense and not easy to generalize. 144 | 145 | Evaluation of composed defenses should therefore be conducted by composing other attacks with ConFIRM tests. For example, to test a CFI defense composed with stack canaries, one should first simulate attacks that attempt to steal the canary secret, and then modify any stack-smashing ConFIRM tests to use the stolen secret. Incompatibilities of the evaluated defense generally consist of the union of the incompatibilities of the composed defenses. 146 | 147 | ## Implementation 148 | To facilitate easier evaluation of the compatibility considerations outlined in the Compatibility Metrics Section along with their impact on security and performance, we developed the ConFIRM suite of CFI tests. ConFIRM consists of 24 programs written in C++ totalling about 2,300 lines of code. Each test isolates one of the compatibility metrics of the Compatibility Metrics Section (or in some cases a few closely related metrics) by emulating behaviors of COTS software products. Source-aware solutions can be evaluated by applying CFI code transforms to the source codes, whereas source-free solutions can be applied to native code after compilation with a compatible compiler (e.g., gcc, LLVM, or MSVC). Loop iteration counts are configurable, allowing some tests to be used as microbenchmarks. The tests are described as follows: 149 | 150 | **fptr.** This tests whether function calls through function pointers are suitably guarded or can be hijacked. Overhead is measured by calling a function through a function pointer in an intensive loop. 151 | 152 | **callback.** As discussed in the Compatibility Metrics Section, call sites of callback functions can be either guarded by a CFI mechanism directly, or located in immutable kernel modules that require some form of indirect control-flow protections. We therefore test whether a CFI mechanism can secure callback function calls in both cases. Overhead is measured by calling a function that takes a callback pointer parameter in an intensive loop. 153 | 154 | **load_time_dynlnk.** Load-time dynamic linking tests determine whether function calls to symbols that are exported by a dynamically linked library are suitably protected. Overhead is measured by calling a function that is exported by a dynamically linked library in an intensive loop. 155 | 156 | **run_time_dynlnk.** This tests whether a CFI mechanism supports runtime dynamic linking, whether it supports retrieving symbols from the dynamically linked library at runtime, and whether it guards function calls to the retrieved symbol. Overhead is measured by loading a dynamically linked library at runtime, calling a function exported by the library, and unloading the library in an intensive loop. 157 | 158 | **delay_load** *(Windows only)* **.** CFI compatibility with delayloaded DLLs is tested, including whether function calls to symbols that are exported by the delay-loaded DLLs are protected. Overhead is measured by calling a function that is exported by a delay-loaded DLL in an intensive loop. 159 | 160 | **data_symbl.** Data and function symbol imports and exports are tested, to determine whether any controls preserve their accessibility and operation. 161 | 162 | **vtbl_call.** Virtual function calls are exercised, whose call sites can be directly instrumented. Overhead is measured by calling virtual functions in an intensive loop. 163 | 164 | **code_coop.** This tests whether a CFI mechanism is robust against CODE-COOP attacks. For the object-oriented interfaces required to launch a CODE-COOP attack, we choose Microsoft COM API functions in Windows, and gtkmm API calls that are part of the C++ interface for GTK+ in Linux. 165 | 166 | **tail_call.** Tail call optimizations of indirect jumps are tested. Overhead is measured by tail-calling a function in a loop. 167 | 168 | **switch.** Indirect jumps associated with switch-case control-flow structures are tested, including their supporting data structures. Overhead is measured by executing a switch-case statement in an intensive loop. 169 | 170 | **ret.** Validation of return addresses (e.g., dynamically via shadow stack implementation, or statically by labeling call sites and callees with equivalence classes) is tested. Overhead is measured by calling a function that does nothing but return in an intensive loop. 171 | 172 | **unmatched_pair.** Unmatched call/return pairs resulting from exceptions and setjmp/longjmp are tested. 173 | 174 | **signal.** This test uses signal-handling in C to implement error-handling and exceptional control-flows. 175 | 176 | **cppeh.** C++ exception handling structures and control-flows are exercised. 177 | 178 | **seh** *(Windows only)* **.** SEH-style exception handling is tested for both hardware and software exceptions. This test also checks whether the CFI mechanism protects the exception handlers stored on the stack. 179 | 180 | **veh** *(Windows only)* **.** VEH-style exception handling is tested for both hardware and software exceptions. This test also checks whether the CFI mechanism protects callback function pointers passed to `AddVecoredExceptionHandler()`. 181 | 182 | **convention.** Several different calling conventions are tested, including conventions widely used in C/C++ languages on 32-bit and 64-bit x86 processors. 183 | 184 | **multithreading.** Safety of concurrent thread executions is tested. Specifically, one thread simulates a memory corruption exploit that attempts to smash another thread’s stack and break out of the CFI-enforced sandbox. 185 | 186 | **tls_callback** *(Windows source-free only)* **.** This tests whether static TLS callback table corruption is detected and blocked by the protection mechanism. 187 | 188 | **pic.** Semantic preservation of position-independent code is tested. 189 | 190 | **mem.** This test performs memory management API calls for legitimate and malicious purposes, and tests whether security controls permit the former but block the latter. 191 | 192 | **jit.** This test generates JIT code by first allocating writable memory pages, writing JIT code into those pages, making the pages executable, and then running the JIT code. To emulate behaviors of real-world JIT compilers, the JIT code performs different types of control-flow transfers, including calling back to the code of JIT compiler and calling functions located in other modules. 193 | 194 | **api_hook** *(Windows only)* **.** Dynamic API hooking is performed in the style described in the Compatibility Metrics Section. 195 | 196 | **unpacking** *(source-free only)* **.** Self-unpacking executable code is implemented using RCG. 197 | -------------------------------------------------------------------------------- /img/SL2logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareLanguagesSecurityLab/ConFIRM/601de444c5e665812778b61fc0fec5c91dbbedbc/img/SL2logo.png -------------------------------------------------------------------------------- /img/confirm_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareLanguagesSecurityLab/ConFIRM/601de444c5e665812778b61fc0fec5c91dbbedbc/img/confirm_flow.png -------------------------------------------------------------------------------- /src/api_hook.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | // This micro benchmark emulates a specific Windows API hooking behavior observed in 32 | // various component-driven software, including Microsoft Office software. Please 33 | // see the ConFIRM paper for detailed explanation. This benchmark redirects function 34 | // NtClose to a wrapper function, to show this API hooking behavior. 35 | 36 | #pragma warning( disable : 4005) 37 | #include "setup.h" 38 | #include 39 | 40 | // Make realNtClose a global variable as it's delared in AppvIsvSubsystems32.dll 41 | static FARPROC realNtClose; 42 | // A global randomized integer 43 | static int r; 44 | 45 | void cpyInt(DWORD startAddr, DWORD dwSize); 46 | void hookedNtClose(); 47 | 48 | int main(void) { 49 | HANDLE ghSemaphore; 50 | HMODULE hNtdll; 51 | SYSTEM_INFO info; 52 | DWORD dwPageSize; 53 | DWORD oldProtect; 54 | BOOL retVP; 55 | BOOL retCH; 56 | NTSTATUS status; 57 | NTSTATUS(*pNtClose) (HANDLE); 58 | 59 | // Get page size of current system. 60 | GetSystemInfo(&info); 61 | dwPageSize = info.dwPageSize; 62 | 63 | // ntdll.dll should be loaded. 64 | hNtdll = GetModuleHandle(L"ntdll.dll"); 65 | if (!hNtdll) 66 | { 67 | printf("ntdll is not loaded"); 68 | exit(1); 69 | } 70 | 71 | // Get function pointer to ntdll::NtClose. 72 | // pNtClose -> mov eax, 0c 73 | // pNtClose+5 -> xor ecx, ecx 74 | // ... 75 | pNtClose = (NTSTATUS(*)(HANDLE))GetProcAddress(hNtdll, "NtClose"); 76 | if (!pNtClose) 77 | { 78 | printf("GetProcAddress() failed requesting function NtClose()"); 79 | exit(1); 80 | } 81 | 82 | // Allocate memory for realNtClose. 83 | realNtClose = (FARPROC)VirtualAlloc( 84 | NULL, 85 | dwPageSize, 86 | MEM_COMMIT | MEM_RESERVE, 87 | PAGE_EXECUTE_READWRITE 88 | ); 89 | if (!realNtClose) 90 | { 91 | printf("VirtualAlloc() failed allocating for realNtClose()"); 92 | exit(1); 93 | } 94 | 95 | // Fill the allocated page by 0xCC (INT) 96 | cpyInt((DWORD)realNtClose, dwPageSize); 97 | 98 | // Write to realNtClose. 99 | // After writing: 100 | // realNtClose -> mov eax, 0c (same to the first 5 bytes of NtClose) 101 | // realNtClose+5 -> jmp pNtClose+5 (xor ecx, ecx) 102 | // INT (should never executed) 103 | __asm { 104 | // Copy the first 4 bytes from NtClose (in ntdll) to realNtClose. 105 | mov esi, pNtClose 106 | mov edi, realNtClose 107 | mov eax, dword ptr[esi] 108 | mov dword ptr[edi], eax 109 | 110 | // Copy the fifth byte 111 | add esi, 4 112 | add edi, 4 113 | mov al, byte ptr[esi] 114 | mov byte ptr[edi], al 115 | 116 | // Write a jmp instruction at offset 5 of realNtClose. 117 | inc edi 118 | mov byte ptr[edi], 0xe9 119 | mov eax, edi 120 | add eax, 5 121 | inc edi 122 | inc esi 123 | sub esi, eax 124 | mov dword ptr[edi], esi 125 | } 126 | 127 | // Make the first 5 bytes of ntdll::NtClose R+W+X. 128 | retVP = VirtualProtect(pNtClose, 5, PAGE_EXECUTE_READWRITE, &oldProtect); 129 | if (!retVP) 130 | { 131 | printf("VirtualProtect() failed on ntdll::NtClose -> R+W+X"); 132 | exit(1); 133 | } 134 | 135 | // Write the fst 5 bytes of ntdll::NtClose to force it jump to hookedNtClose. 136 | // After writing: 137 | // pNtClose -> jmp hookedNtClose 138 | // pNtClose+5 -> xor ecx, ecx 139 | // ... 140 | __asm { 141 | mov edi, pNtClose 142 | mov byte ptr[edi], 0xe9 143 | mov ecx, hookedNtClose 144 | mov eax, edi 145 | inc edi 146 | add eax, 5 147 | sub ecx, eax 148 | mov dword ptr[edi], ecx 149 | } 150 | 151 | // Make the first 5 bytes of ntdll::NtClose E+WriteCopy. 152 | retVP = VirtualProtect(pNtClose, 5, PAGE_EXECUTE_WRITECOPY, &oldProtect); 153 | if (!retVP) 154 | { 155 | printf("VirtualProtect() failed on ntdll::NtClose -> E+WriteCopy"); 156 | exit(1); 157 | } 158 | 159 | // Create a semaphore and then close the semaphore handle by calling NtClose(). 160 | ghSemaphore = CreateSemaphore( 161 | NULL, 162 | 1, 163 | 1, 164 | NULL); 165 | 166 | // Initialize seed 167 | srand((unsigned int)time(NULL)); 168 | // Close sematphore handle 169 | do 170 | { 171 | r = rand(); 172 | printf("Trying to close semaphore handle...\n"); 173 | status = pNtClose(ghSemaphore); 174 | } while (status != STATUS_SUCCESS); 175 | 176 | printf("Semaphore handle closed.\n"); 177 | 178 | return 0; 179 | } 180 | 181 | void cpyInt(DWORD startAddr, DWORD dwSize) 182 | { 183 | __asm { 184 | mov eax, 0xCCCCCCCC 185 | mov edi, startAddr 186 | mov ecx, dwSize 187 | shr ecx, 2 188 | rep stos dword ptr[edi] // this is semanticly equivelent to "rep stosd" 189 | } 190 | } 191 | 192 | // If randomized int r is even -> return STATUS_UNSUCCESSFUL 193 | // r is odd -> jump to realNtClose 194 | __declspec(naked) 195 | void hookedNtClose() 196 | { 197 | if (r % 2 == 0) 198 | { 199 | __asm { 200 | mov eax, 0xC0000001 201 | ret 202 | } 203 | } 204 | 205 | __asm { 206 | jmp realNtClose 207 | } 208 | 209 | printf("Program should not reach here --- impossible!"); 210 | 211 | __asm { 212 | ret 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/callback_linux.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | static int count_0 = 0, count_1 = 0, count_2 = 0; 34 | NANOSECOND start_time; 35 | NANOSECOND end_time; 36 | NANOSECOND total_time; 37 | 38 | // Define three callback functions 39 | void *theadProc0(void *); 40 | void *theadProc1(void *); 41 | void *theadProc2(void *); 42 | 43 | int main() 44 | { 45 | pthread_t threads[3]; 46 | 47 | // Record starting time 48 | start_time = get_wall_time(); 49 | 50 | // int pthread_create( 51 | // pthread_t *thread, 52 | // const pthread_attr_t *attr, 53 | // void *(*start_routine) (void *), 54 | // void *arg); 55 | // pthread_create() (signature above) takes a callback pointer (start_routine) 56 | // that points to a application-defined function to be executed by the new 57 | // created thread. 58 | 59 | // Create threads in an intensive loop. 60 | for (long long int i = 0; i < MAX_LOOP * CALTS; i++) 61 | { 62 | pthread_create(&threads[0], NULL, &theadProc0, NULL); 63 | pthread_create(&threads[1], NULL, &theadProc1, NULL); 64 | pthread_create(&threads[2], NULL, &theadProc2, NULL); 65 | } 66 | 67 | // Record ending time 68 | end_time = get_wall_time(); 69 | total_time = end_time - start_time; 70 | 71 | // Print time elapsed in the loop. 72 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 73 | 74 | // Print counts so that a compiler doesn't optimize too much. 75 | printf("%d, %d, %d\n", count_0, count_1, count_2); 76 | 77 | pthread_exit(NULL); 78 | } 79 | 80 | void *theadProc0(void *) 81 | { 82 | count_0++; 83 | pthread_exit(NULL); 84 | } 85 | 86 | void *theadProc1(void *) 87 | { 88 | count_1++; 89 | pthread_exit(NULL); 90 | } 91 | 92 | void *theadProc2(void *) 93 | { 94 | count_2++; 95 | pthread_exit(NULL); 96 | } 97 | -------------------------------------------------------------------------------- /src/callback_windows.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | static int count_1 = 0, count_2 = 0, count_3 = 0; 34 | NANOSECOND start_time; 35 | NANOSECOND end_time; 36 | NANOSECOND total_time; 37 | 38 | // Define three callback functions 39 | DWORD WINAPI theadProc1(LPVOID lpParam); 40 | DWORD WINAPI theadProc2(LPVOID lpParam); 41 | DWORD WINAPI theadProc3(LPVOID lpParam); 42 | 43 | int main() 44 | { 45 | HANDLE h1 = 0; 46 | HANDLE h2 = 0; 47 | HANDLE h3 = 0; 48 | HANDLE handles[3]; 49 | 50 | // Record starting time 51 | start_time = get_wall_time(); 52 | 53 | // HANDLE CreateThread( 54 | // LPSECURITY_ATTRIBUTES lpThreadAttributes, 55 | // SIZE_T dwStackSize, 56 | // LPTHREAD_START_ROUTINE lpStartAddress, 57 | // __drv_aliasesMem LPVOID lpParameter, 58 | // DWORD dwCreationFlags, 59 | // LPDWORD lpThreadId 60 | // ); 61 | // The CreateThread() API takes a callback pointer (lpStartAddress) that points 62 | // to a napplication-defined function to be executed by the new created thread. 63 | 64 | // Create threads and wait for them to terminate in an intensive loop. 65 | for (long long int i = 0; i < MAX_LOOP * CALTS; i++) 66 | { 67 | h1 = CreateThread(NULL, 0, theadProc1, NULL, 0, NULL); 68 | h2 = CreateThread(NULL, 0, theadProc2, NULL, 0, NULL); 69 | h3 = CreateThread(NULL, 0, theadProc3, NULL, 0, NULL); 70 | 71 | // Wait for the treads to terminate and close handles. 72 | handles[0] = h1; 73 | handles[1] = h2; 74 | handles[2] = h3; 75 | WaitForMultipleObjects(3, handles, TRUE, INFINITE); 76 | CloseHandle(h1); 77 | CloseHandle(h2); 78 | CloseHandle(h3); 79 | } 80 | 81 | // Record ending time 82 | end_time = get_wall_time(); 83 | total_time = end_time - start_time; 84 | 85 | // Print time elapsed in the loop. 86 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 87 | 88 | // Print counts so that a compiler doesn't optimize too much. 89 | printf("%d, %d, %d", count_1, count_2, count_3); 90 | 91 | return 0; 92 | } 93 | 94 | DWORD WINAPI theadProc1(LPVOID lpParam) 95 | { 96 | count_1++; 97 | return NULL; 98 | } 99 | 100 | DWORD WINAPI theadProc2(LPVOID lpParam) 101 | { 102 | count_2++; 103 | return NULL; 104 | } 105 | 106 | DWORD WINAPI theadProc3(LPVOID lpParam) 107 | { 108 | count_3++; 109 | return NULL; 110 | } 111 | -------------------------------------------------------------------------------- /src/code_coop_linux.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | /* For a detailed explanation of CODE-COOP attack, see the following publication: 32 | 33 | Wenhao Wang and Xiaoyang Xu and Kevin W. Hamlen. 34 | "Object Flow Integrity." In Proceedings of the 24th ACM Conference on Computer 35 | and Communications Security (CCS). */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | // Define a Gtk Window class with one button. 43 | class CODECOOP : public Gtk::Window 44 | { 45 | public: 46 | CODECOOP(); 47 | virtual ~CODECOOP(); 48 | protected: 49 | // Signal handlers: 50 | void on_button_clicked(); 51 | // Member widgets: 52 | Gtk::Button m_button; 53 | }; 54 | 55 | CODECOOP::CODECOOP() 56 | : m_button("This is a test for CODE-COOP attack") 57 | { 58 | set_border_width(10); 59 | m_button.signal_clicked().connect(sigc::mem_fun(*this, &CODECOOP::on_button_clicked)); 60 | add(m_button); 61 | m_button.show(); 62 | } 63 | 64 | CODECOOP::~CODECOOP() 65 | { 66 | } 67 | 68 | void CODECOOP::on_button_clicked() 69 | { 70 | std::cout << "This is a test for CODE-COOP attack" << std::endl; 71 | } 72 | 73 | int main (int argc, char *argv[]) 74 | { 75 | auto app = Gtk::Application::create(argc, argv, ""); 76 | 77 | CODECOOP codecoop; 78 | 79 | // function call that leads to buffer overflow 80 | char buffer[1]; 81 | printf("Any input can lead to buffer overwrite: \n"); 82 | scanf("%s", buffer); 83 | 84 | // Shows the window and returns when it is closed. 85 | // In run(), it calls member function of codecoop. The codecoop pointer is stored 86 | // on the stack so that the above buffer overwrite vulnerability can rewrite this 87 | // pointer with one that points to a counterfeit object. Although CFI solutions 88 | // can guarantee that app->run flows to a valid target, the function call to 89 | // other member function of codecoop in trusted module can therefore escape the 90 | // CFI sandbox. 91 | return app->run(codecoop); 92 | } 93 | -------------------------------------------------------------------------------- /src/code_coop_windows.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | /* For a detailed explanation of CODE-COOP attack, see the following publication: 32 | 33 | Wenhao Wang and Xiaoyang Xu and Kevin W. Hamlen. 34 | "Object Flow Integrity." In Proceedings of the 24th ACM Conference on Computer 35 | and Communications Security (CCS). */ 36 | 37 | #include "setup.h" 38 | #include "wininet.h" 39 | #include "winnls.h" 40 | #include "shobjidl.h" 41 | #include "objbase.h" 42 | #include "objidl.h" 43 | #include "shlguid.h" 44 | #include "shlobj.h" 45 | 46 | #pragma warning ( disable : 4789 ) 47 | 48 | int main() 49 | { 50 | HRESULT hres; 51 | IShellLink* pad; 52 | 53 | CoInitialize(NULL); 54 | 55 | // CoCreateInstance() obtains an object reference (pad) of ActiveDesktop. And 56 | // later QueryInterface() obtains a new interface (puk) to ActiveDesktop. 57 | hres = CoCreateInstance( 58 | CLSID_ActiveDesktop, 59 | NULL, 60 | CLSCTX_INPROC_SERVER, 61 | IID_IActiveDesktop, 62 | (LPVOID*)&pad 63 | ); 64 | 65 | if (SUCCEEDED(hres)) 66 | { 67 | // Code containing a data corruption vulnerability 68 | char buffer[1]; 69 | printf("Any input can lead to buffer overwrite: \n"); 70 | scanf("%s", buffer); 71 | 72 | // CFI solutions guarantee that the following function call targets a valid 73 | // QueryInterface(). Unfortunately, every implementation of QueryInterface() 74 | // calls other virtual functions (e.g. AddRef) by default. With the above 75 | // data corruption vulnerability, an attacker can tailer counterfeit object 76 | // and then redirect control flow to arbitrary code. 77 | IPersistFile* puk; 78 | hres = pad-> QueryInterface(IID_IUnknown, (LPVOID*)&puk); 79 | if (SUCCEEDED(hres)) 80 | { 81 | printf("QueryInterface succeed.\n"); 82 | } 83 | else 84 | { 85 | printf("QueryInterface failed.\n"); 86 | } 87 | } 88 | else 89 | { 90 | printf("CoCreateInstance failed.\n"); 91 | } 92 | 93 | CoUninitialize(); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /src/convention.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | // Caller-pop, variadic function. 34 | int CDECL variadicSum(int count, ...); 35 | 36 | // Callee-pop function. 37 | int STDCALL listSum(int count, const int * list); 38 | 39 | // Callee-pop FASTCALL function. 40 | // Caller tries to pass first two arguments using registers. 41 | int FASTCALL fastSum(int count, const int * list); 42 | 43 | // Callee-pop THISCALL functions. 44 | // "this" pointer is passed in ecx. Other arguments are pushed onto the stack. 45 | class CMath 46 | { 47 | private: 48 | int * list; 49 | int count; 50 | public: 51 | int THISCALL calculateSum(); 52 | int THISCALL calculateAverage(); 53 | void THISCALL setList(const int list_count, const int * int_list); 54 | }; 55 | 56 | // 64-bit conventions allow up to 14 and 4 parameters passing in registers, 57 | // on Linux and Windows respectively. They both use caller-pop conventions by default. 58 | // int and float arguments are passed using different registers. 59 | int IntSum(int count, ...); 60 | double DoubleSum(int count, ...); 61 | 62 | int main() 63 | { 64 | // Call a CDECL function. 65 | int variadicSum_ans = 0; 66 | variadicSum_ans = variadicSum(5, 1, 2, 3, 4, 5); 67 | if (variadicSum_ans == 15) 68 | { 69 | printf("CDECL passed\n"); 70 | } 71 | else 72 | { 73 | printf("CDECL failed!\n"); 74 | return -1; 75 | } 76 | 77 | // Call a STDCALL function. 78 | int listSum_ans = 0; 79 | int int_list1[5] = { 1, 3, 5, 7, 9 }; 80 | listSum_ans = listSum(sizeof(int_list1) / sizeof(int), int_list1); 81 | if (listSum_ans == 25) 82 | { 83 | printf("STDCALL passed\n"); 84 | } 85 | else 86 | { 87 | printf("STDCALL failed!\n"); 88 | return -1; 89 | } 90 | 91 | // Call a FASTCALL function 92 | int fastSum_ans = 0; 93 | int int_list2[4] = { 5, 3, 5, 1 }; 94 | fastSum_ans = fastSum(sizeof(int_list2) / sizeof(int), int_list2); 95 | if (fastSum_ans == 14) 96 | { 97 | printf("FASTCALL passed\n"); 98 | } 99 | else 100 | { 101 | printf("FASTCALL failed!\n"); 102 | return -1; 103 | } 104 | 105 | // Call THISCALL functions 106 | CMath * myCMath = new CMath; 107 | int int_list3[6] = { 2, 1, 6, 3, 8, 9 }; 108 | 109 | myCMath->setList(sizeof(int_list3) / sizeof(int), int_list3); 110 | int sum = myCMath->calculateSum(); 111 | int avg = myCMath->calculateAverage(); 112 | if ((sum == 29) && (avg == 4)) 113 | { 114 | printf("THISCALL passed\n"); 115 | } 116 | else 117 | { 118 | printf("THISCALL failed!\n"); 119 | return -1; 120 | } 121 | 122 | // Tests for 64-bit calling conventions. 123 | int intSum_ans = 0; 124 | intSum_ans = IntSum(16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); 125 | 126 | double doubleSum_ans = 0.0; 127 | doubleSum_ans = DoubleSum(16, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10, 11.11, 12.12, 13.13, 14.14, 15.15, 16.16); 128 | 129 | if ((intSum_ans == 136) && (doubleSum_ans - 141.41 <= 0.000000000001)) 130 | { 131 | printf("64bit conventions passed\n"); 132 | } 133 | else 134 | { 135 | printf("64bit conventions failed!\n"); 136 | return -1; 137 | } 138 | 139 | printf("All conventions passed\n"); 140 | return 0; 141 | } 142 | 143 | int THISCALL CMath::calculateAverage() 144 | { 145 | int sum = 0; 146 | int avg = 0; 147 | 148 | sum = this->calculateSum(); 149 | avg = sum / this->count; 150 | return avg; 151 | } 152 | 153 | int THISCALL CMath::calculateSum() 154 | { 155 | int sum = 0; 156 | for (int i = 0; i < this->count; i++) 157 | sum += (this->list)[i]; 158 | 159 | return sum; 160 | } 161 | 162 | void THISCALL CMath::setList(const int list_count, const int * int_list) 163 | { 164 | this->list = new int[list_count]; 165 | this->count = list_count; 166 | 167 | for (int i = 0; i < list_count; i++) 168 | (this->list)[i] = int_list[i]; 169 | } 170 | 171 | int FASTCALL fastSum(int count, const int * list) 172 | { 173 | int sum = 0; 174 | int i = 0; 175 | 176 | for (int i = 0; i < count; i++) 177 | sum += list[i]; 178 | 179 | return sum; 180 | } 181 | 182 | int STDCALL listSum(int count, const int * list) 183 | { 184 | int sum = 0; 185 | int i = 0; 186 | 187 | for (int i = 0; i < count; i++) 188 | sum += list[i]; 189 | 190 | return sum; 191 | } 192 | 193 | int CDECL variadicSum(int count, ...) 194 | { 195 | va_list ap; 196 | int sum = 0; 197 | 198 | va_start(ap, count); 199 | for (int i = 0; i < count; i++) 200 | sum += va_arg(ap, int); 201 | va_end(ap); 202 | 203 | return sum; 204 | } 205 | 206 | int IntSum(int count, ...) 207 | { 208 | va_list ap; 209 | int sum = 0; 210 | 211 | va_start(ap, count); 212 | for (int i = 0; i < count; i++) 213 | sum += va_arg(ap, int); 214 | va_end(ap); 215 | 216 | return sum; 217 | } 218 | 219 | double DoubleSum(int count, ...) 220 | { 221 | va_list ap; 222 | double sum = 0.0; 223 | double next = 0.0; 224 | 225 | va_start(ap, count); 226 | for (int i = 0; i < count; i++) 227 | sum += va_arg(ap, double); 228 | va_end(ap); 229 | 230 | return sum; 231 | } 232 | -------------------------------------------------------------------------------- /src/cppeh.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | void throwInt(); 34 | void throwBool(); 35 | static int int_catch_count = 0; 36 | static int bool_catch_count = 0; 37 | 38 | int main() 39 | { 40 | int r; 41 | 42 | // Initialize random seed 43 | srand((unsigned int)time(NULL)); 44 | 45 | // Throw and catch C++ exceptions in an intensive loop, to see if a CFI solution 46 | // being tested provides semantic transparency. 47 | for (long long int i = 0; i < MAX_LOOP * CPEHTS; ++i) 48 | { 49 | r = rand(); 50 | try 51 | { 52 | if (r % 2 == 0) 53 | throwInt(); 54 | else 55 | throwBool(); 56 | 57 | } 58 | catch (int e) 59 | { 60 | int_catch_count++; 61 | } 62 | catch (bool e) 63 | { 64 | bool_catch_count++; 65 | } 66 | } 67 | 68 | // Print results 69 | printf("int_catch_count is %d\n", int_catch_count); 70 | printf("bool_catch_count is %d\n", bool_catch_count); 71 | printf("C++ exception test passed."); 72 | 73 | return 0; 74 | } 75 | 76 | void throwInt() 77 | { 78 | try 79 | { 80 | throw 7; 81 | } 82 | catch (bool e) 83 | { 84 | bool_catch_count++; 85 | } 86 | } 87 | 88 | void throwBool() 89 | { 90 | try 91 | { 92 | throw true; 93 | } 94 | catch (int e) 95 | { 96 | int_catch_count++; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/data_symbl.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | #include "inc.h" 33 | 34 | int main() 35 | { 36 | int imp_null = -1; 37 | DWORD p_exp_null = NULL; 38 | 39 | 40 | imp_null = (int) exp_null; 41 | // After data movement, if imp_null is not NULL, the CFI work being tested must 42 | // have done something wrong. 43 | if (imp_null != 0) 44 | { 45 | printf("imp_null should be NULL (current value: %d).\n", imp_null); 46 | exit(1); 47 | } 48 | 49 | // Check whether an exported symbol can be read correctly via pointer. 50 | p_exp_null = &exp_null; 51 | if (*p_exp_null != 0) 52 | { 53 | printf("*p_exp_null should be NULL (current value: %d).\n", *p_exp_null); 54 | exit(1); 55 | } 56 | 57 | // Check whether the exported symbol can still be read correctly after some weird 58 | // pointer arithmetic. 59 | p_exp_null ++; 60 | p_exp_null += (DWORD)(imp_null * 1024); 61 | p_exp_null --; 62 | if (*p_exp_null != 0) 63 | { 64 | printf("*p_exp_null should be NULL (current value: %d).\n", *p_exp_null); 65 | exit(1); 66 | } 67 | 68 | printf("All tests passed.\n"); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /src/delay_load.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | // This microbenchmark should be compiled by Microsoft Visual Studio with additional 32 | // linker option /DELAYLOAD:"user32.dll", so that user32.dll would be delay loaded. 33 | 34 | #include "setup.h" 35 | 36 | NANOSECOND start_time; 37 | NANOSECOND end_time; 38 | NANOSECOND total_time; 39 | 40 | int main() 41 | { 42 | HWND hWindow = NULL; 43 | 44 | // Record starting time 45 | start_time = get_wall_time(); 46 | 47 | for (long long int i = 0; i < MAX_LOOP * DLTS; ++i) 48 | { 49 | // API GetForegroundWindow() is exported user32.dll. By delay-loading 50 | // user32.dll, it is not loaded into memory until GetForegroundWindow() is 51 | // being called. 52 | hWindow = GetForegroundWindow(); 53 | if (!hWindow) 54 | { 55 | printf("GetActiveWindow() failed.\n"); 56 | exit(1); 57 | } 58 | hWindow = NULL; 59 | } 60 | 61 | // Record ending time 62 | end_time = get_wall_time(); 63 | total_time = end_time - start_time; 64 | 65 | // Print time elapsed in the loop. 66 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /src/fptr.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | static int count_even = 0; 34 | static int count_odd = 0; 35 | NANOSECOND start_time; 36 | NANOSECOND end_time; 37 | NANOSECOND total_time; 38 | 39 | // Declare two functions with same signature. 40 | void printEven(int n); 41 | void printOdd(int n); 42 | 43 | int main() 44 | { 45 | // Declare a function pointer. Each call via this pointer would be a indirect call. 46 | // It can be either a register-indirect call or a memory-indirect call based on 47 | // different compiler options. 48 | void(*fptr) (int n); 49 | 50 | // Initialize random seed 51 | srand((unsigned int)time(NULL)); 52 | // Record starting time 53 | start_time = get_wall_time(); 54 | 55 | // call functions via a function pointer in an intensive loop. 56 | for (long long int i = 0; i < MAX_LOOP * FPTRTS; i++) 57 | { 58 | // Depending on parity of a randomized number, fptr(r) calls different functions. 59 | int r = rand(); 60 | if (r % 2 == 0) 61 | fptr = printEven; 62 | else 63 | fptr = printOdd; 64 | fptr(r); 65 | } 66 | 67 | // Record ending time, and calculate running time elapsed in the loop. 68 | end_time = get_wall_time(); 69 | total_time = end_time - start_time; 70 | 71 | // Print time elapsed in the loop. 72 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 73 | 74 | // Print counts so that a compiler doesn't optimize too much. 75 | printf("%d odd numbers\n", count_odd); 76 | printf("%d even numbers\n", count_even); 77 | 78 | return 0; 79 | } 80 | 81 | void printEven(int n) 82 | { 83 | count_even++; 84 | } 85 | void printOdd(int n) 86 | { 87 | count_odd++; 88 | } 89 | -------------------------------------------------------------------------------- /src/inc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "inc.h" 3 | 4 | #ifdef _WIN32 5 | #include 6 | #define EXPORTING_DLL 7 | 8 | BOOL APIENTRY DllMain( 9 | HANDLE hModule, // Handle to DLL module 10 | DWORD ul_reason_for_call, 11 | LPVOID lpReserved) // Reserved 12 | { 13 | switch (ul_reason_for_call) 14 | { 15 | case DLL_PROCESS_ATTACH: 16 | // A process is loading the DLL. 17 | break; 18 | 19 | case DLL_THREAD_ATTACH: 20 | // A process is creating a new thread. 21 | break; 22 | 23 | case DLL_THREAD_DETACH: 24 | // A thread exits normally. 25 | break; 26 | 27 | case DLL_PROCESS_DETACH: 28 | // A process unloads the DLL. 29 | break; 30 | } 31 | return TRUE; 32 | } 33 | 34 | #elif __linux__ 35 | #include 36 | #include "helper.h" 37 | #endif 38 | 39 | void increment(int &i) 40 | { 41 | if (i < INT_MAX) 42 | { 43 | i++; 44 | } 45 | return; 46 | } 47 | 48 | int exp_null = (int) NULL; 49 | -------------------------------------------------------------------------------- /src/inc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #ifdef EXPORTING_DLL 5 | extern "C" __declspec(dllexport) void increment(int &i); 6 | extern "C" __declspec(dllexport) int exp_null; 7 | #else 8 | extern "C" __declspec(dllimport) void increment(int &i); 9 | extern "C" __declspec(dllimport) int exp_null; 10 | #endif 11 | #elif __linux__ 12 | extern "C" void increment(int &i); 13 | extern "C" int exp_null; 14 | #endif 15 | -------------------------------------------------------------------------------- /src/jit.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | #if !(defined INTEL_X86 || AMD64) 34 | #error This benchmark contains x86/x64-specific assembly code that may be \ 35 | incompatible with the current hardware architecture. 36 | #endif 37 | 38 | void JITCALLBACKPTR(); 39 | 40 | typedef void(*CALLBACKPTR)(); 41 | 42 | BYTE JIT_code[] = { 43 | // Prologue 44 | 0x55, // push ebp/rbp 45 | 0x48, // dec eax 46 | // if compiled for 32bit otherwise extend ebp and esp to rbp and 47 | // rsp for next ins 48 | 0x8B, 0xEC, // mov ebp, esp 49 | 0x53, // push ebx/rbx 50 | 0x56, // push esi/rsi 51 | 0x57, // push edi/rdi 52 | 53 | // Computed call to a function in the untrusted module 54 | 0x48, // dec eax if compiled for 32bit otherwise extend ebx to rbx 55 | // for next ins 56 | 0xbb, // mov ebx, 0x00000000 57 | 0x00, 58 | 0x00, 59 | 0x00, 60 | 0x00, 61 | 0x90, 62 | 0x90, 63 | 0x90, 64 | 0x90, // 8 bytes of address need to be patched -- NOP is added so 65 | // that it works for both 32-bit and 64-bit machine 66 | 0xff, 0x13, // call ptr [ebx/rbx] 67 | 68 | // Epilogue 69 | 0x5F, // pop edi/rdi 70 | 0x5E, // pop esi/rsi 71 | 0x5b, // pop ebx/rbx 72 | 0x48, // dec eax if compiled for 32bit otherwise extend ebp and esp 73 | // to rbp and rsp for next ins 74 | 0x8B, 0xE5, // mov esp, ebp 75 | 0x5D, // pop ebp/rbp 76 | 0xC3 // retn 77 | }; 78 | 79 | int main() 80 | { 81 | 82 | #ifdef _WIN32 83 | SYSTEM_INFO info; 84 | DWORD dwPageSize; 85 | FARPROC pJIT; 86 | BOOL retVF; 87 | 88 | // Get page size of current system 89 | GetSystemInfo(&info); 90 | dwPageSize = info.dwPageSize; 91 | 92 | // Allocate a page of memory (RWX) 93 | pJIT = (FARPROC)VirtualAlloc( 94 | NULL, 95 | dwPageSize, 96 | MEM_COMMIT | MEM_RESERVE, 97 | PAGE_EXECUTE_READWRITE 98 | ); 99 | 100 | #elif __linux__ 101 | uint8_t *pJIT; 102 | int page_size; 103 | int fd; 104 | 105 | page_size = getpagesize(); 106 | 107 | // Allocate a page of memory (RWX) 108 | fd = open("/dev/zero", O_RDONLY); 109 | pJIT = (uint8_t *)mmap( 110 | NULL, 111 | page_size, 112 | PROT_READ | PROT_WRITE | PROT_EXEC, 113 | MAP_PRIVATE, 114 | fd, 115 | 0 116 | ); 117 | #endif 118 | 119 | if (!pJIT) 120 | { 121 | printf("Memory allocation failed for pJIT"); 122 | exit(1); 123 | } 124 | 125 | // Patch JIT_code 126 | CALLBACKPTR pJITCALLBACKPTR = &JITCALLBACKPTR; 127 | void *ppJITCALLBACKPTR = &pJITCALLBACKPTR; 128 | memcpy(&(JIT_code[9]), &ppJITCALLBACKPTR, sizeof(pJITCALLBACKPTR)); 129 | 130 | // Copy JIT_code to pJIT 131 | memcpy(pJIT, JIT_code, sizeof(JIT_code)); 132 | 133 | // Call pJIT 134 | ((CALLBACKPTR)pJIT)(); 135 | 136 | // Free the page allocated 137 | #ifdef _WIN32 138 | retVF = VirtualFree(pJIT, 0, MEM_RELEASE); 139 | if (!retVF) 140 | { 141 | printf("VirtualFree() failed freeing pJIT"); 142 | exit(1); 143 | } 144 | #elif __linux__ 145 | munmap(pJIT, page_size); 146 | #endif 147 | 148 | printf("jit test passed.\n"); 149 | return 0; 150 | } 151 | 152 | void JITCALLBACKPTR() 153 | { 154 | printf("This is a message in JITCALLBACKPTR()\n"); 155 | } 156 | -------------------------------------------------------------------------------- /src/load_time_dynlnk_linux.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | NANOSECOND start_time; 34 | NANOSECOND end_time; 35 | NANOSECOND total_time; 36 | 37 | int main() 38 | { 39 | char *p; 40 | int page_size; 41 | int fd; 42 | 43 | // Record starting time 44 | start_time = get_wall_time(); 45 | page_size = getpagesize(); 46 | 47 | // Call functions exported by a dynamically linked library in an intensive loop. 48 | for (long long int i = 0; i < MAX_LOOP * LTTX; ++i) 49 | { 50 | fd = open ("/dev/zero", O_RDONLY); 51 | p = (char *) mmap ( 52 | NULL, 53 | page_size, 54 | PROT_READ | PROT_WRITE, 55 | MAP_PRIVATE, 56 | fd, 57 | 0 58 | ); 59 | close (fd); 60 | 61 | if (!p) { 62 | perror("Couldn’t malloc(1024)"); 63 | exit(errno); 64 | } 65 | 66 | p[123] = 123; 67 | 68 | if (mprotect(p, page_size, PROT_NONE)) { 69 | perror("Couldn’t mprotect"); 70 | exit(errno); 71 | } 72 | 73 | munmap(p, page_size); 74 | } 75 | 76 | // Record ending time 77 | end_time = get_wall_time(); 78 | total_time = end_time - start_time; 79 | 80 | // Print time elapsed in the loop. 81 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /src/load_time_dynlnk_windows.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | NANOSECOND start_time; 34 | NANOSECOND end_time; 35 | NANOSECOND total_time; 36 | 37 | int main() 38 | { 39 | LPVOID base_addr = NULL; 40 | DWORD dwOldProtect; 41 | BOOL retVP = FALSE; 42 | BOOL retVF = FALSE; 43 | SIZE_T dwSize = 1; 44 | 45 | // Record starting time 46 | start_time = get_wall_time(); 47 | 48 | // Call functions exported by a dynamically linked library in an intensive loop. 49 | for (long long int i = 0; i < MAX_LOOP * LTTX; ++i) 50 | { 51 | base_addr = VirtualAlloc( 52 | NULL, 53 | dwSize, 54 | MEM_COMMIT, 55 | PAGE_READWRITE 56 | ); 57 | 58 | if (!base_addr) 59 | { 60 | printf("VirtualAlloc() failed...\n"); 61 | exit(1); 62 | } 63 | 64 | retVP = VirtualProtect( 65 | base_addr, 66 | dwSize, 67 | PAGE_READONLY, 68 | &dwOldProtect 69 | ); 70 | 71 | if (!retVP) 72 | { 73 | printf("VirtualProtect() failed...\n"); 74 | exit(1); 75 | } 76 | 77 | retVF = VirtualFree( 78 | base_addr, 79 | 0, 80 | MEM_RELEASE 81 | ); 82 | 83 | if (!retVF) 84 | { 85 | printf("VirtualFree() failed...\n"); 86 | exit(1); 87 | } 88 | } 89 | 90 | // Record ending time 91 | end_time = get_wall_time(); 92 | total_time = end_time - start_time; 93 | 94 | // Print time elapsed in the loop. 95 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /src/mem.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | void callee1(); 34 | void callee2(); 35 | // min estimated max size of callee1 and callee 2 36 | #define ESTIMATED_FUNC_SIZE 100 37 | static bool flag_1 = FALSE; 38 | static bool flag_2 = FALSE; 39 | 40 | typedef void(*FUNCPTR)(); 41 | 42 | int main() 43 | { 44 | SYSTEM_INFO info; 45 | DWORD dwPageSize; 46 | FARPROC caller; 47 | BOOL retVP; 48 | BOOL retVF; 49 | DWORD dummy; 50 | unsigned int size1; 51 | unsigned int size2; 52 | 53 | // Get page size of current system. 54 | GetSystemInfo(&info); 55 | dwPageSize = info.dwPageSize; 56 | 57 | // Allocate a page of memory (RW). 58 | caller = (FARPROC)VirtualAlloc( 59 | NULL, 60 | dwPageSize, 61 | MEM_COMMIT | MEM_RESERVE, 62 | PAGE_READWRITE 63 | ); 64 | if (!caller) 65 | { 66 | printf("Memory allocation failed for caller"); 67 | exit(1); 68 | } 69 | 70 | size1 = ((((unsigned int)callee1) + (ESTIMATED_FUNC_SIZE - 1)) / dwPageSize + 1) * dwPageSize - ((unsigned int)callee1); 71 | 72 | // Copy code to caller 73 | memcpy(caller, (void *)&callee1, size1); 74 | 75 | // Change memory protection to executable only. 76 | retVP = VirtualProtect( 77 | caller, 78 | dwPageSize, 79 | PAGE_EXECUTE, 80 | &dummy 81 | ); 82 | if (!retVP) 83 | { 84 | printf("VirtualProtect failed"); 85 | exit(1); 86 | } 87 | 88 | // Invoke caller, in which callee1 is called. 89 | ((FUNCPTR)caller)(); 90 | 91 | // Change memory protection to RWX. 92 | retVP = VirtualProtect( 93 | caller, 94 | dwPageSize, 95 | PAGE_EXECUTE_READWRITE, 96 | &dummy 97 | ); 98 | if (!retVP) 99 | { 100 | printf("VirtualProtect failed"); 101 | exit(1); 102 | } 103 | 104 | size2 = ((((unsigned int)callee2) + (ESTIMATED_FUNC_SIZE - 1)) / dwPageSize + 1) * dwPageSize - ((unsigned int)callee2); 105 | 106 | // Copy code to caller. 107 | memcpy(caller, (void *)&callee2, size2); 108 | 109 | // Invoke caller. This time caller2 is called. 110 | ((FUNCPTR)caller)(); 111 | 112 | // Free the page allocated. 113 | retVF = VirtualFree(caller, 0, MEM_RELEASE); 114 | if (!retVF) 115 | { 116 | printf("VirtualFree() failed freeing caller"); 117 | exit(1); 118 | } 119 | 120 | if (flag_1 && flag_2) 121 | { 122 | printf("mem test passed\n"); 123 | } 124 | else 125 | { 126 | printf("mem test failed\n"); 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | void callee1() 133 | { 134 | flag_1 = TRUE; 135 | } 136 | 137 | void callee2() 138 | { 139 | flag_2 = TRUE; 140 | } 141 | -------------------------------------------------------------------------------- /src/multithreading_linux32.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | #ifdef INTEL_X86 34 | // 35 | #elif AMD64 36 | #error This benchmark is designed for x86 architecture only. For x64, please use \ 37 | multithreading_linux64.cpp instead. 38 | #else 39 | #error This benchmark contains x86/x64-specific assembly code that may be \ 40 | incompatible with the current hardware architecture. 41 | #endif 42 | 43 | using namespace std; 44 | 45 | static int hChild; 46 | static unsigned long long int trials, hijacktramp_addr; 47 | static volatile int hijacked = 0; 48 | 49 | // This function runs the child thread that attempts to hijack the main thread. 50 | // The retaddr_ptr argument points to the main thread's return address slot. 51 | void *ChildThread(void * retaddr_ptr) 52 | { 53 | printf("Child thread started hijacking.\n"); 54 | 55 | // Repeatedly write into the main thread's return address slot. 56 | // The write is attempted times. 57 | asm ( 58 | " movq %0, %%rcx\n\t" 59 | "L:" 60 | " movq %1, (%2)\n\t" 61 | " loop L" 62 | : // OutputOperands : A comma-separated list of the C variables modified 63 | : "r" (trials), "r" (hijacktramp_addr), "r" (retaddr_ptr) // InputOperands : A comma-separated list of C expressions read 64 | : "rcx", "memory" // Clobbers : A comma-separated list of registers or other values changed 65 | ); 66 | 67 | // 0.1 second sleep for making sure hijacked has changed if it should 68 | usleep(100000); 69 | 70 | // If the hijack was successful, the main thread sets the global "hijacked" variable to 1. 71 | if (!hijacked) 72 | { 73 | printf("All trials complete. Hijack unsuccessful.\n"); 74 | exit(0); 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | int main(int argc, char* argv[]) 81 | { 82 | unsigned int idChild; 83 | pthread_t thread1; 84 | void * esp_addr; 85 | 86 | printf("Enter number of trials: "); 87 | scanf("%llu", &trials); 88 | 89 | int flag = 0; 90 | 91 | asm ( 92 | " leaq HIJACKTRAMP(%%rip), %%rax\n\t" 93 | " movq %%rax, %0\n\t" 94 | " leaq -8(%%rsp), %%rax\n\t" // Store the address of the forthcoming return address in esp_addr. 95 | " movq %%rax, %1\n\t" 96 | "HIJACKTRAMP:" 97 | : "=r" (hijacktramp_addr), "=r" (esp_addr) // OutputOperands : A comma-separated list of the C variables modified 98 | : // InputOperands : A comma-separated list of C expressions read 99 | : "rax", "memory" // Clobbers : A comma-separated list of registers or other values changed 100 | ); 101 | 102 | if (flag) { 103 | hijacked = 1; 104 | goto HIJACKED; 105 | } 106 | 107 | flag = 1; 108 | 109 | // Spawn the child (hijacker) thread. 110 | hChild = pthread_create( 111 | &thread1, 112 | NULL, 113 | ChildThread, 114 | esp_addr); 115 | 116 | if (hChild) { 117 | printf("Could not make child thread!\n"); 118 | abort(); 119 | } 120 | 121 | // Repeat a guarded return in the tightest possible infinite loop. 122 | asm ( 123 | " leaq L2(%rip), %rbx\n\t" 124 | "L1:" 125 | " call L3\n\t" 126 | "L2:" 127 | " jmp L1\n\t" 128 | "L3:" 129 | " ret" 130 | ); 131 | 132 | printf("Infinite loop ended normally---impossible!\n"); 133 | abort(); 134 | 135 | // If the hijacker is successful, the "ret" above will jump here. 136 | HIJACKED: 137 | 138 | // The child thread might still be running, so push a dummy return address for it to continue hijacking. 139 | asm ( 140 | "push $0" 141 | ); 142 | 143 | printf("Hijack successful!\n"); 144 | 145 | // Wait for the child thread to terminate normally. 146 | pthread_join(thread1, NULL); 147 | 148 | // Pop the dummy return address. 149 | asm ( 150 | "pop %rax" 151 | ); 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /src/multithreading_linux64.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | #ifdef AMD64 34 | // 35 | #elif INTEL_X86 36 | #error This benchmark is designed for x64 architecture only. For x86, please use \ 37 | multithreading_linux32.cpp instead. 38 | #else 39 | #error This benchmark contains x86/x64-specific assembly code that may be \ 40 | incompatible with the current hardware architecture. 41 | #endif 42 | 43 | using namespace std; 44 | 45 | static int hChild; 46 | static unsigned long long int trials, hijacktramp_addr; 47 | static volatile int hijacked = 0; 48 | 49 | // This function runs the child thread that attempts to hijack the main thread. 50 | // The retaddr_ptr argument points to the main thread's return address slot. 51 | void *ChildThread(void * retaddr_ptr) 52 | { 53 | printf("Child thread started hijacking.\n"); 54 | 55 | // Repeatedly write into the main thread's return address slot. 56 | // The write is attempted times. 57 | asm ( 58 | " movq %0, %%rcx\n\t" 59 | "L:" 60 | " movq %1, (%2)\n\t" 61 | " loop L" 62 | : // OutputOperands : A comma-separated list of the C variables modified 63 | : "r" (trials), "r" (hijacktramp_addr), "r" (retaddr_ptr) // InputOperands : A comma-separated list of C expressions read 64 | : "rcx", "memory" // Clobbers : A comma-separated list of registers or other values changed 65 | ); 66 | 67 | // 0.1 second sleep for making sure hijacked has changed if it should 68 | usleep(100000); 69 | 70 | // If the hijack was successful, the main thread sets the global "hijacked" variable to 1. 71 | if (!hijacked) 72 | { 73 | printf("All trials complete. Hijack unsuccessful.\n"); 74 | exit(0); 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | int main(int argc, char* argv[]) 81 | { 82 | unsigned int idChild; 83 | pthread_t thread1; 84 | void * esp_addr; 85 | 86 | printf("Enter number of trials: "); 87 | scanf("%llu", &trials); 88 | 89 | int flag = 0; 90 | 91 | asm ( 92 | " leaq HIJACKTRAMP(%%rip), %%rax\n\t" 93 | " movq %%rax, %0\n\t" 94 | " leaq -8(%%rsp), %%rax\n\t" // Store the address of the forthcoming return address in esp_addr. 95 | " movq %%rax, %1\n\t" 96 | "HIJACKTRAMP:" 97 | : "=r" (hijacktramp_addr), "=r" (esp_addr) // OutputOperands : A comma-separated list of the C variables modified 98 | : // InputOperands : A comma-separated list of C expressions read 99 | : "rax", "memory" // Clobbers : A comma-separated list of registers or other values changed 100 | ); 101 | 102 | if (flag) { 103 | hijacked = 1; 104 | goto HIJACKED; 105 | } 106 | 107 | flag = 1; 108 | 109 | // Spawn the child (hijacker) thread. 110 | hChild = pthread_create( 111 | &thread1, 112 | NULL, 113 | ChildThread, 114 | esp_addr); 115 | 116 | if (hChild) { 117 | printf("Could not make child thread!\n"); 118 | abort(); 119 | } 120 | 121 | // Repeat a guarded return in the tightest possible infinite loop. 122 | asm ( 123 | " leaq L2(%rip), %rbx\n\t" 124 | "L1:" 125 | " call L3\n\t" 126 | "L2:" 127 | " jmp L1\n\t" 128 | "L3:" 129 | " ret" 130 | ); 131 | 132 | printf("Infinite loop ended normally---impossible!\n"); 133 | abort(); 134 | 135 | // If the hijacker is successful, the "ret" above will jump here. 136 | HIJACKED: 137 | 138 | // The child thread might still be running, so push a dummy return address for it to continue hijacking. 139 | asm ( 140 | "push $0" 141 | ); 142 | 143 | printf("Hijack successful!\n"); 144 | 145 | // Wait for the child thread to terminate normally. 146 | pthread_join(thread1, NULL); 147 | 148 | // Pop the dummy return address. 149 | asm ( 150 | "pop %rax" 151 | ); 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /src/multithreading_windows.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | #ifdef INTEL_X86 34 | // 35 | #elif AMD64 36 | #error This benchmark is designed for x86 architecture only. 37 | #else 38 | #error This benchmark contains x86-specific assembly code that may be incompatible \ 39 | with the current hardware architecture. 40 | #endif 41 | 42 | static HANDLE hChild; 43 | static DWORD trials, hijack_addr; 44 | static volatile int hijacked = 0; 45 | 46 | // This function runs the child thread that attempts to hijack the main thread. 47 | // The retaddr_ptr argument points to the main thread's return address slot. 48 | DWORD WINAPI ChildThread(LPVOID retaddr_ptr) 49 | { 50 | // Repeatedly write into the main thread's return address slot. 51 | // The write is attempted times. 52 | _asm { 53 | mov eax, retaddr_ptr 54 | mov ebx, hijack_addr 55 | mov ecx, trials 56 | L : mov [eax], ebx 57 | loop L 58 | } 59 | 60 | // If the hijack was successful, the main thread sets the global "hijacked" variable to 1. 61 | if (!hijacked) 62 | { 63 | printf("All trials complete. Hijack unsuccessful.\n"); 64 | // The main thread loops infinitely, so to terminate it, we use ExitProcess. 65 | ExitProcess(0); 66 | } 67 | 68 | return 0; 69 | } 70 | 71 | int main(int argc, char* argv[]) 72 | { 73 | DWORD idChild; 74 | LPVOID esp_addr; 75 | 76 | printf("Enter number of trials: "); 77 | scanf_s("%u", &trials); 78 | 79 | _asm { 80 | mov hijack_addr, offset HIJACK // Store the address to which the hijacker should redirect in a global var. 81 | lea eax, [esp - 4] // Store the address of the forthcoming return address in esp_addr. 82 | mov esp_addr, eax 83 | } 84 | 85 | // Spawn the child (hijacker) thread. 86 | hChild = CreateThread( 87 | NULL, 88 | 0, 89 | ChildThread, 90 | esp_addr, 91 | 0, 92 | &idChild); 93 | if (!hChild) abort(); 94 | 95 | // Repeat a guarded return in the tightest possible infinite loop. 96 | _asm { 97 | mov eax, offset L2 98 | L1 : call L3 99 | L2 : jmp L1 100 | L3 : mov[esp], eax 101 | ret 102 | } 103 | 104 | printf("Infinite loop ended normally---impossible!\n"); 105 | abort(); 106 | 107 | // If the hijacker is successful, the "ret" above will jump here. 108 | HIJACK: 109 | hijacked = 1; 110 | 111 | _asm { 112 | push 0 // The child thread might still be running, so push a dummy return address for it to continue hijacking. 113 | } 114 | 115 | printf("Hijack successful!\n"); 116 | 117 | // Wait for the child thread to terminate normally. 118 | WaitForSingleObject(hChild, INFINITE); 119 | 120 | // Pop the dummy return address. 121 | _asm { pop eax } 122 | 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /src/ret.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | NANOSECOND start_time; 34 | NANOSECOND end_time; 35 | NANOSECOND total_time; 36 | 37 | // A function does nothing but return 38 | void retFunc(); 39 | 40 | int main() 41 | { 42 | // Record starting time 43 | start_time = get_wall_time(); 44 | 45 | // Call a function that does nothing but returns in an intensive loop. 46 | for (long long int i = 0; i < MAX_LOOP * RETTS; i++) 47 | { 48 | retFunc(); 49 | } 50 | 51 | // Record ending time 52 | end_time = get_wall_time(); 53 | total_time = end_time - start_time; 54 | 55 | // Print time elapsed in the loop. 56 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 57 | 58 | return 0; 59 | } 60 | 61 | #if (defined MSVC_ARCH || GNU_ARCH || CLANG_ARCH) 62 | void retFunc() 63 | { 64 | return; 65 | } 66 | #else 67 | #error This benchmark is designed for processor architectures supported by mainstream \ 68 | compilers, including MSVC, GCC, and LLVM. To run this benchmark on other platforms, \ 69 | users of ConFIRM can extend this source code as needed.\ 70 | #endif 71 | -------------------------------------------------------------------------------- /src/run_time_dynlnk.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | NANOSECOND start_time; 34 | NANOSECOND end_time; 35 | NANOSECOND total_time; 36 | 37 | // Define a function pointer type for retrieving function pointer 38 | // returned by GetProcAddress()/dlsym(). 39 | typedef void(*INC)(int&); 40 | 41 | int main() 42 | { 43 | #ifdef _WIN32 44 | HINSTANCE libHandle = NULL; 45 | BOOL retFree = FALSE; 46 | #elif __linux__ 47 | void *libHandle; 48 | char *error; 49 | #endif 50 | INC pInc = NULL; 51 | int count = 0; 52 | 53 | // record starting time 54 | start_time = get_wall_time(); 55 | 56 | for (long long int i = 0; i < MAX_LOOP * DYNLTS; ++i) 57 | { 58 | // Load an untrusted module libinc.dll/.so 59 | #ifdef _WIN32 60 | libHandle = LoadLibrary(L"libinc.dll"); 61 | #elif __linux__ 62 | libHandle = dlopen("./libinc.so", RTLD_LAZY); 63 | #endif 64 | if (!libHandle) 65 | { 66 | printf("Loading library failed.\n"); 67 | exit(1); 68 | } 69 | 70 | // Get a function pointer exported by libinc.dll/.so 71 | #ifdef _WIN32 72 | pInc = (INC)GetProcAddress(libHandle, "increment"); 73 | #elif __linux__ 74 | pInc = (INC) dlsym(libHandle, "increment"); 75 | #endif 76 | if (!pInc) 77 | { 78 | printf("Finding symbol failed.\n"); 79 | exit(1); 80 | } 81 | 82 | // Call the returned function. 83 | pInc(count); 84 | 85 | // Unload libinc.dll/.so 86 | #ifdef _WIN32 87 | retFree = FreeLibrary(libHandle); 88 | if (!retFree) 89 | { 90 | printf("FreeLibrary() failed.\n"); 91 | exit(1); 92 | } 93 | #elif __linux__ 94 | dlclose(libHandle); 95 | #endif 96 | } 97 | 98 | // record ending time 99 | end_time = get_wall_time(); 100 | total_time = end_time - start_time; 101 | 102 | // print results 103 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 104 | printf("count is %d\n", count); 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /src/seh.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | // This benchmark is Windows specific. 32 | 33 | #include "setup.h" 34 | 35 | void writeToMem(); 36 | static int except_count = 0; 37 | static int finally_count = 0; 38 | 39 | int main() 40 | { 41 | // Throw access violation exception and handle it using SEH in an intensive loop, 42 | // to see if a CFI solution being tested provides semantic transparency. 43 | for (long long int i = 0; i < MAX_LOOP * SEHTS; ++i) 44 | { 45 | __try 46 | { 47 | writeToMem(); 48 | } 49 | __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 50 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 51 | { 52 | except_count++; 53 | } 54 | } 55 | 56 | // Print results. 57 | printf("except_count is %d\nfinally_count is %d\n ", except_count++, finally_count); 58 | printf("SEH test passed."); 59 | 60 | return 0; 61 | } 62 | 63 | // A function that writes to invalid address. 64 | void writeToMem() 65 | { 66 | __try 67 | { 68 | __try 69 | { 70 | *(unsigned int*)0x0 = 0; 71 | } 72 | __finally 73 | { 74 | finally_count++; 75 | } 76 | } 77 | __except (GetExceptionCode() == EXCEPTION_FLT_DIVIDE_BY_ZERO ? 78 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 79 | { 80 | printf("This should not be printed --- impossible!\n"); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/setup.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | #ifdef _WIN32 34 | // In Windows, a time stamp is calculated as the current value of the performance 35 | // counter divided by the frequency of the performance counter. 36 | NANOSECOND get_wall_time() 37 | { 38 | LARGE_INTEGER time, frequency; 39 | QueryPerformanceFrequency(&frequency); 40 | QueryPerformanceCounter(&time); 41 | return (NANOSECOND)(time.QuadPart * BILLION / frequency.QuadPart); 42 | } 43 | 44 | #elif __linux__ 45 | // In Linux, elapsed time is calculated as a difference between two monotonic times. 46 | NANOSECOND get_wall_time() 47 | { 48 | struct timespec time; 49 | clock_gettime(CLOCK_MONOTONIC, &time); 50 | return (NANOSECOND)(BILLION * time.tv_sec + time.tv_nsec); 51 | } 52 | 53 | #else 54 | #endif 55 | -------------------------------------------------------------------------------- /src/setup.h: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | // This is the master configuration file. 32 | // Users of ConFIRM can specialize their own parameters. 33 | 34 | #pragma once 35 | 36 | // Benchmarks in Windows and Linux require different header files 37 | #ifdef _WIN32 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #elif __linux__ 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #define FALSE false 58 | #define BYTE unsigned char 59 | 60 | #else 61 | #endif 62 | 63 | // Loop iteration counts for different benchmarks. 64 | // With the current counts, each benchmark runs around 2 min. 65 | #define MAX_LOOP 1024L //base loop count 66 | #define CPEHTS 5 //cppeh 67 | #define SEHTS 5 //seh 68 | #define VEHTS 5 //veh 69 | #define DYNLTS 0.3 //run_time_dynlnk 70 | #define FPTRTS 500 //fptr 71 | //#define IMPDTS 6500 //data_symbl 72 | #define INDCTS 360 //tail_call 73 | #define JITCTS 2500 74 | #define CALTS 0.4 //callback 75 | #define LHWXTS 20 //signal 76 | #define LTTX 1.2 //load_time_dynlnk 77 | #define RETTS 5700 //ret 78 | #define SWTCTS 590 //switch 79 | #define VTABTS 460 //vtbl_call 80 | #define DLTS 500 81 | 82 | // Macros for different calling conventions in Windows and Linux 83 | #ifdef _WIN32 84 | #define CDECL __cdecl 85 | #define STDCALL __stdcall 86 | #define FASTCALL __fastcall 87 | #define THISCALL __thiscall 88 | 89 | #elif __linux__ 90 | #define CDECL __attribute__((cdecl)) 91 | #define STDCALL 92 | #define FASTCALL __attribute__((fastcall)) 93 | #define THISCALL __attribute__((thiscall)) 94 | 95 | #else 96 | #endif 97 | 98 | // A helper function that can be used to calculate elapsed time in nanosecond. 99 | #define NANOSECOND uint64_t 100 | #define BILLION 1000000000L 101 | extern NANOSECOND get_wall_time(); 102 | 103 | // Pre-defined compiler macros for x86/x64 104 | #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) 105 | #define AMD64 106 | #endif 107 | 108 | #if defined(i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__i386) || defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386) || defined(__THW_INTEL__) 109 | #define INTEL_X86 110 | #endif 111 | 112 | // Pre-defined compiler macros for processor architectures supported by different compilers. 113 | #if defined(_M_ALPHA) || defined(_M_AMD64) || defined(_M_X64) || defined(_M_ARM) || defined(_M_ARMT) || defined(_M_I86) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_PPC) 114 | #define MSVC_ARCH 115 | #endif 116 | 117 | #if defined(__alpha__) || defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(__arm__) || defined(__thumb__) || defined(__aarch64__) || defined(__bfin) || defined(__BFIN__) || defined(__convex__) || defined(__hppa__) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(__m68k__) || defined(__mips__) || defined(mips) || defined(__mips) || defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || defined(__ppc__) || defined(__ppc64__) || defined(__PPC__) || defined(__PPC64__) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(__sparc__) || defined(__sparc_v8__) || defined(__sparc_v9__) || defined(__sh__) || defined(__s390__) || defined(__s390x__) 118 | #define GNU_ARCH 119 | #endif 120 | 121 | #if defined(__zarch__) || defined(__x86_64__) || defined(__ARM_ARCH) || defined(__arm__) || defined(__aarch64__) 122 | #define CLANG_ARCH 123 | #endif 124 | -------------------------------------------------------------------------------- /src/signal.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include "setup.h" 35 | 36 | sigjmp_buf mark; 37 | 38 | // Define a hanlder that restores the environment saved by sigsetjmp. 39 | void myhandler(int signo) { 40 | siglongjmp(mark, -1); 41 | } 42 | 43 | // A function that writes to invalid address. 44 | void exception_loop(void) { 45 | char *p = NULL; 46 | *p = 5; 47 | } 48 | 49 | int main(void) { 50 | // Set up a signal handler that handles invalid memory reference (SIGSEGV). 51 | struct sigaction myhandle; 52 | myhandle.sa_handler = myhandler; 53 | sigemptyset(&myhandle.sa_mask); 54 | myhandle.sa_flags = SA_NODEFER; 55 | sigaction(SIGSEGV, &myhandle, NULL); 56 | 57 | // Write to invalid address in an intensive loop, to see if a CFI solution being tested 58 | // provides semantic transparency. 59 | long long int i = 0; 60 | sigsetjmp(mark, 0); 61 | if (i++ < MAX_LOOP * LHWXTS) 62 | exception_loop(); 63 | 64 | printf("signal test passed.\n"); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /src/switch.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | static int zero_count = 0; 34 | static int one_count = 0; 35 | static int two_count = 0; 36 | static int three_count = 0; 37 | const int divisor = 4; 38 | 39 | NANOSECOND start_time; 40 | NANOSECOND end_time; 41 | NANOSECOND total_time; 42 | 43 | int main() 44 | { 45 | int dividend = 0; 46 | int remainder = 0; 47 | 48 | // Initialize random seed 49 | srand((unsigned int)time(NULL)); 50 | // Record starting time 51 | start_time = get_wall_time(); 52 | 53 | // Execute a switch-case statement in an intensive loop. 54 | for (long long int i = 0; i < MAX_LOOP * SWTCTS; i++) 55 | { 56 | dividend = rand(); 57 | remainder = dividend % divisor; 58 | 59 | switch (remainder) 60 | { 61 | case 0: 62 | zero_count += 1; 63 | break; 64 | case 1: 65 | one_count += 1; 66 | break; 67 | case 2: 68 | two_count += 1; 69 | break; 70 | case 3: 71 | three_count += 1; 72 | break; 73 | default: 74 | printf("should not reach here -- impossible!"); 75 | } 76 | } 77 | 78 | // Record ending time 79 | end_time = get_wall_time(); 80 | total_time = end_time - start_time; 81 | 82 | // Print time elapsed in the loop. 83 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 84 | 85 | // Print counts so that a compiler doesn't optimize too much. 86 | printf("%d numbers have remainder of zero modulo %d.\n", zero_count, divisor); 87 | printf("%d numbers have remainder of one modulo %d.\n", one_count, divisor); 88 | printf("%d numbers have remainder of two modulo %d.\n", two_count, divisor); 89 | printf("%d numbers have remainder of three modulo %d.\n", three_count, divisor); 90 | 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /src/tail_call.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | static int zero_count = 0; 34 | static int one_count = 0; 35 | static int two_count = 0; 36 | static int three_count = 0; 37 | const int divisor = 4; 38 | 39 | NANOSECOND start_time; 40 | NANOSECOND end_time; 41 | NANOSECOND total_time; 42 | 43 | void helper(); 44 | void case0(); 45 | void case1(); 46 | void case2(); 47 | void case3(); 48 | 49 | int main() 50 | { 51 | // Initialize random seed 52 | srand((unsigned int)time(NULL)); 53 | // Record starting time 54 | start_time = get_wall_time(); 55 | 56 | // Call a function that ends with a tail-call in an intensive loop. 57 | for (long long int i = 0; i < MAX_LOOP * INDCTS; i++) 58 | { 59 | helper(); 60 | } 61 | 62 | // Record ending time 63 | end_time = get_wall_time(); 64 | total_time = end_time - start_time; 65 | 66 | // Print time elapsed in the loop. 67 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 68 | 69 | // Print counts so that a compiler doesn't optimize too much. 70 | printf("%d numbers have remainder of zero modulo %d.\n", zero_count, divisor); 71 | printf("%d numbers have remainder of one modulo %d.\n", one_count, divisor); 72 | printf("%d numbers have remainder of two modulo %d.\n", two_count, divisor); 73 | printf("%d numbers have remainder of three modulo %d.\n", three_count, divisor); 74 | } 75 | 76 | void helper() 77 | { 78 | void(*fptr) (); 79 | int r = rand(); 80 | int remainder = r % divisor; 81 | 82 | if (remainder == 0) 83 | fptr = case0; 84 | if (remainder == 1) 85 | fptr = case1; 86 | if (remainder == 2) 87 | fptr = case2; 88 | if (remainder == 3) 89 | fptr = case3; 90 | 91 | // Tail-call using a function pointer. 92 | fptr(); 93 | } 94 | 95 | void case0() 96 | { 97 | zero_count += 1; 98 | } 99 | 100 | void case1() 101 | { 102 | one_count += 1; 103 | } 104 | 105 | void case2() 106 | { 107 | two_count += 1; 108 | } 109 | 110 | void case3() 111 | { 112 | three_count += 1; 113 | } 114 | -------------------------------------------------------------------------------- /src/tls_callback.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | void NTAPI TLSEntry(PVOID DllHandle, DWORD dwReason, PVOID); 34 | DWORD WINAPI ThreadProc(CONST LPVOID lpParam); 35 | 36 | // Linker spec for using TLS callback 37 | #ifdef _WIN32 38 | #pragma comment (linker, "/INCLUDE:__tls_used") 39 | #pragma comment (linker, "/INCLUDE:_tls_callback") 40 | #else 41 | #pragma comment (linker, "/INCLUDE:_tls_used") 42 | #pragma comment (linker, "/INCLUDE:tls_callback") 43 | #endif 44 | #ifdef _WIN32 45 | #pragma data_seg(".CRT$XLF") 46 | EXTERN_C 47 | #else 48 | #pragma const_seg(".CRT$XLF") 49 | EXTERN_C const 50 | #endif 51 | PIMAGE_TLS_CALLBACK tls_callback = TLSEntry; 52 | #ifdef _WIN32 53 | #pragma data_seg() 54 | #else 55 | #pragma const_seg() 56 | #endif 57 | 58 | int main() 59 | { 60 | const int thread_count = 10; 61 | HANDLE handles[thread_count]; 62 | 63 | // Creating/terminating new thread invokes a TLS callback. 64 | for (int i = 0; i < thread_count; i++) 65 | { 66 | handles[i] = CreateThread(NULL, 0, &ThreadProc, 0, 0, NULL); 67 | } 68 | // Wairing for thread to terminate. 69 | WaitForMultipleObjects(thread_count, handles, TRUE, INFINITE); 70 | 71 | for (int i = 0; i < thread_count; i++) 72 | { 73 | CloseHandle(handles[i]); 74 | } 75 | 76 | printf("TLS callback test passed.\n"); 77 | 78 | return 0; 79 | } 80 | 81 | DWORD WINAPI ThreadProc(CONST LPVOID lpParam) 82 | { 83 | ExitThread(0); 84 | } 85 | 86 | void NTAPI TLSEntry(PVOID DllHandle, DWORD dwReason, PVOID) 87 | { 88 | if (dwReason == DLL_THREAD_ATTACH) 89 | { 90 | printf("DLL_THREAD_ATTACH\n"); 91 | } 92 | 93 | if (dwReason == DLL_THREAD_DETACH) 94 | { 95 | printf("DLL_THREAD_DETACH\n"); 96 | } 97 | 98 | if (dwReason == DLL_PROCESS_ATTACH) 99 | { 100 | printf("DLL_PROCESS_ATTACH\n"); 101 | } 102 | 103 | if (dwReason == DLL_PROCESS_DETACH) 104 | { 105 | printf("DLL_PROCESS_DETACH\n"); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/unmatched_pair.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | #include 33 | 34 | void exception_test(); 35 | void exception_callee1(); 36 | void exception_callee2(); 37 | 38 | jmp_buf buf; 39 | void longjmp_test(); 40 | void longjmp_callee1(); 41 | void longjmp_callee2(); 42 | 43 | int main() 44 | { 45 | // Check if a CFI solution can handle unmatched call/return pair due to exception. 46 | exception_test(); 47 | printf("exception_test passed\n\n"); 48 | 49 | // Check if a CFI solution can handle unmatched call/return pair due to longjmp. 50 | longjmp_test(); 51 | printf("longjmp_test passed\n"); 52 | 53 | return 0; 54 | } 55 | 56 | void exception_test() 57 | { 58 | try 59 | { 60 | printf("1. a message in exception_test try block\n"); 61 | exception_callee1(); 62 | } 63 | catch (int e) 64 | { 65 | printf("4. a message in exception_test catch block\n"); 66 | } 67 | } 68 | 69 | void exception_callee1() 70 | { 71 | printf("2. a message in exception_callee1\n"); 72 | exception_callee2(); 73 | } 74 | 75 | void exception_callee2() 76 | { 77 | printf("3. a message in exception_callee2\n"); 78 | 79 | // This exception being caught by the catch block in exception_test(), results in 80 | // popping stack frames from multiple calls, followed by a return at the end of 81 | // exception_test(). Shadow stack defenses that are implemented based on 82 | // call/return matching may be problematic. 83 | throw 7; 84 | } 85 | 86 | void longjmp_test() 87 | { 88 | printf("5. a message in longjmp_test\n"); 89 | // setjmp() returns 0 when called directly, so control flows to the else block. 90 | // The if block is executed as the jump target of longjmp(). 91 | if (setjmp(buf)) 92 | printf("8. a message after longjmp\n"); 93 | else 94 | longjmp_callee1(); 95 | } 96 | 97 | void longjmp_callee1() 98 | { 99 | printf("6. a message in longjmp_callee1\n"); 100 | longjmp_callee2(); 101 | } 102 | 103 | void longjmp_callee2() 104 | { 105 | printf("7. a message in longjmp_callee2\n"); 106 | 107 | // This longjmp to longjmp_test() leads to an unmatched call/return pair, 108 | // followed by a return from longjmp_test to main. 109 | longjmp(buf, 1); 110 | printf("-1, oops, should never reach this!\n"); 111 | } 112 | -------------------------------------------------------------------------------- /src/veh.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | // This benchmark is Windows specific. 32 | 33 | #include "setup.h" 34 | 35 | // Define a vectored exception handler. 36 | LONG WINAPI VectoredHandlerSkip(struct _EXCEPTION_POINTERS *ExceptionInfo); 37 | 38 | int main() 39 | { 40 | PVOID pv = NULL; 41 | 42 | // Register a vectored exception handler. 43 | pv = AddVectoredExceptionHandler(0, VectoredHandlerSkip); 44 | 45 | // Trigger a hardware exception by writing to DS:[0] in a loop, to check whether 46 | // a CFI solution being tested provides semantic transparency. 47 | for (long long int i = 0; i < MAX_LOOP * SEHTS; ++i) 48 | { 49 | *(unsigned int*)0x0 = 0; 50 | } 51 | 52 | // Remove the vectored exception handler. 53 | RemoveVectoredExceptionHandler(pv); 54 | 55 | // Print results 56 | printf("VEH test passed\n"); 57 | return 0; 58 | } 59 | 60 | LONG WINAPI VectoredHandlerSkip(struct _EXCEPTION_POINTERS *ExceptionInfo) 61 | { 62 | PCONTEXT Context; 63 | Context = ExceptionInfo->ContextRecord; 64 | 65 | // Add program counter by 1 66 | #ifdef AMD64 67 | Context->Rip = Context->Rip + 1; 68 | #elif defined INTEL_X86 69 | Context->Eip = Context->Eip + 1; 70 | #else 71 | #error This benchmark contains x86/x64-specific assembly code that may be \ 72 | incompatible with the current hardware architecture. 73 | #endif 74 | 75 | // Continue execution with the new EIP value. 76 | return EXCEPTION_CONTINUE_EXECUTION; 77 | } 78 | -------------------------------------------------------------------------------- /src/vtbl_call.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Copyright (c) 2019 Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, and Kevin Hamlen * 3 | * The University of Texas at Dallas * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the "Software"), to deal in * 7 | * the Software without restriction, including without limitation the rights to * 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 9 | * the Software, and to permit persons to whom the Software is furnished to do so, * 10 | * subject to the following conditions: * 11 | * * 12 | * The above copyright notice and this permission notice shall be included in all * 13 | * copies or substantial portions of the Software. * 14 | * * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 21 | *************************************************************************************/ 22 | 23 | /* This file is part of the ConFIRM test suite, whose initial documentation can be 24 | found in the following publication: 25 | 26 | Xiaoyang Xu, Masoud Ghaffarinia, Wenhao Wang, Kevin W. Hamlen, and Zhiqiang Lin. 27 | "ConFIRM: Evaluating Compatibility and Relevance of Control-flow Integrity 28 | Protections for Modern Software." In Proceedings of the 28th USENIX Security 29 | Symposium, August 2019. */ 30 | 31 | #include "setup.h" 32 | 33 | // Base class 34 | class base 35 | { 36 | public: 37 | int count_even = 0; 38 | int count_odd = 0; 39 | 40 | virtual int random() { return 0; }; 41 | virtual void accEven() {}; 42 | virtual void accOdd() {}; 43 | virtual bool isOdd(int) { return FALSE; }; 44 | }; 45 | 46 | // Derived class 47 | class derived: public base 48 | { 49 | public: 50 | int random() 51 | { 52 | return rand(); 53 | } 54 | 55 | void accEven() 56 | { 57 | count_even++; 58 | } 59 | 60 | void accOdd() 61 | { 62 | count_odd++; 63 | } 64 | 65 | bool isOdd(int n) 66 | { 67 | return (n % 2); 68 | } 69 | }; 70 | 71 | NANOSECOND start_time; 72 | NANOSECOND end_time; 73 | NANOSECOND total_time; 74 | 75 | int main() 76 | { 77 | // Define a derived class instance and a pointer that has type of base class 78 | derived p; 79 | base *pn = &p; 80 | int n; 81 | 82 | // Initialize random seed 83 | srand((unsigned int)time(NULL)); 84 | // Record starting time 85 | start_time = get_wall_time(); 86 | 87 | // Call virtual functions in an intensive loop 88 | for (long long int i = 0; i < MAX_LOOP * VTABTS; ++i) 89 | { 90 | n = pn->random(); 91 | if (pn->isOdd(n)) 92 | { 93 | pn->accOdd(); 94 | } 95 | else 96 | { 97 | pn->accEven(); 98 | } 99 | } 100 | 101 | // Record ending time 102 | end_time = get_wall_time(); 103 | total_time = end_time - start_time; 104 | 105 | // Print time elapsed in the loop. 106 | printf("total time in nanoseconds is %llu\n", (long long unsigned int) total_time); 107 | 108 | // Print counts so that a compiler doesn't optimize too much. 109 | printf("%d odd numbers\n", pn->count_odd); 110 | printf("%d even numbers\n", pn->count_even); 111 | 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /xu19-confirm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoftwareLanguagesSecurityLab/ConFIRM/601de444c5e665812778b61fc0fec5c91dbbedbc/xu19-confirm.pdf --------------------------------------------------------------------------------