Object Type Integrity for C++ Virtual Dispatch
Total Page:16
File Type:pdf, Size:1020Kb
CFIXX: Object Type Integrity for C++ Virtual Dispatch Nathan Burow Derrick McKee Scott A. Carr Mathias Payer Purdue University Purdue University Purdue University Purdue University [email protected] [email protected] [email protected] [email protected] Abstract—C++ relies on object type information for dynamic the program’s control-flow, frequently by redirecting dynamic dispatch and casting. The association of type information to an dispatch [5]. This is a form of code-reuse and indeed Return object is implemented via the virtual table pointer, which is Oriented Programming (ROP) [32], [8] attacks have been stored in the object itself. C++ has neither memory nor type specialized for C++ [33]. To the best of our knowledge, no safety, adversaries may therefore overwrite an object’s type. If existing work fully explores how vulnerable C++’s dynamic the corrupted type is used for dynamic dispatch, the attacker dispatch is to these attacks, or is capable of stopping the full has hijacked the application’s control flow. This vulnerability is widespread and commonly exploited. Firefox, Chrome, and spectrum of attacks on dynamic dispatch. other major C++ applications are network facing, commonly C++ uses dynamic dispatch to implement polymorphism. attacked, and make significant use of dynamic dispatch. Control- A key feature of polymorphism is that objects which inherit Flow Integrity (CFI) is the state of the art policy for efficient mitigation of control flow hijacking attacks. CFI mechanisms from a base class can be up cast to that base class, while still determine statically (i.e., at compile time) the set of functions retaining their own implementations of any virtual methods. that are valid at a given call site, based on C++ semantics. We Put another way, an object’s underlying type – the class it was propose an orthogonal policy, Object Type Integrity (OTI), that allocated as – determines the behavior of dynamic dispatch. dynamically tracks object types. Consequently, instead of allowing Consequently, one call site on a base class can have different a set of targets for each dynamic dispatch on an object, only the behavior depending on the type of the object at runtime. single, correct target for the object’s type is allowed. Dynamic dispatch is used to determine which implementation To show the efficacy of OTI, we present CFIXX, which of the virtual method should be invoked. C++ relies on virtual enforces OTI. CFIXX enforces OTI by dynamically tracking table pointers to implement dynamic dispatch. Virtual table the type of each object and enforcing its integrity against pointers tie an object to its underlying type and thus determine arbitrary writes. CFIXX has minimal overhead on CPU bound the correct target for the dispatch. For dispatch, Object Type applications such as SPEC CPU2006- 4.98%. On key applications Integrity (OTI) enforces that the correct object type is used (the like Chromium, CFIXX has negligible overhead on JavaScript one assigned by the constructor when the object was allocated). benchmarks: 2.03% on Octane, 1.99% on Kraken, and 2.80% on Dynamic dispatch leverages the virtual table pointer to identify JetStream. We show that CFIXX can be deployed in conjunction the type of an object, OTI therefore requires integrity of the with CFI, providing a significant security improvement. virtual table pointer. I. INTRODUCTION Violations of OTI are possible because virtual table pointers are fundamentally required to be in writeable memory. Each Web browsers are among the most commonly used polymorphic object (i.e., an object with virtual methods) needs and most complex applications running on today’s systems. a virtual table pointer, and can exist anywhere in memory. Browsers are responsible for correctly processing arbitrary Consequently, the virtual table pointer has to be included in input in the form of web pages, including large and complex the memory representation of the object. As C++ has neither web applications with a threat model that includes an adversary memory nor type safety, having virtual table pointers in the with (restricted) code execution through JavaScript. Conse- objects exposes them to corruption. Once virtual table pointers quently, browsers are some of the most commonly attacked have been corrupted – and OTI violated – the attacker has programs. The major web browsers (Firefox, Chrome, Safari, successfully corrupted control flow information. The attacker and Internet Explorer/Edge) are written primarily in C++, then forces that object to be used for dynamic dispatch, which does not enforce type safety and is prone to use after hijacking the control flow of the program. Given control over free (UaF) and other memory safety errors. Attackers now the program’s control flow, she can mount a code reuse attack, increasingly use type safety and UaF vulnerabilities to hijack leading to arbitrary execution. Observe that code reuse attacks operate in three stages: (i) Permission to freely reproduce all or part of this paper for noncommercial an initial memory or type safety violation, (ii) corruption of purposes is granted provided that copies bear this notice and the full citation on the first page. Reproduction for commercial purposes is strictly prohibited control data, and (iii) the control flow hijack [34]. The current without the prior written consent of the Internet Society, the first-named author state-of-the art for efficiently mitigating code-reuse attacks (for reproduction of an entire paper only), and the author’s employer if the is Control-Flow Integrity (CFI) [3], [29], [37], [9], which paper was prepared within the scope of employment. mitigates the third step of the attack by limiting the control NDSS ’18, 18-21 February 2018, San Diego, CA, USA Copyright 2018 Internet Society, ISBN 1-1891562-49-5 flow to paths that are valid in the program’s control flow http://dx.doi.org/10.14722/ndss.2018.23279 graph. CFI mechanisms specialized to deal with C++ dynamic dispatch [37], [9] leverage the class hierarchy when computing results, our prototype OTI enforcement mechanism, CFIXX, the set of valid targets for virtual dispatch sites, increasing is open source: https://github.com/HexHive/CFIXX. precision. Despite the precision added by class hierarchy information, the target set can be large enough for the attacker Our contributions are: to find sufficient gadgets to achieve her desired goals [11], 1) A new defense policy, Object Type Integrity (OTI), [18], [10], [33]. Each overridden virtual function increases which mitigates all known attacks on dynamic dis- imprecision, as all implementations must be in the same target patch. set. For large C++ applications, such as web browsers, these 2) A defense mechanism that enforces OTI, CFIXX, and sets are surprisingly large in practice, see Section III-C for an evaluation of the prototype on SPEC CPU2006– details. including libc++, and Chromium. CFI’s weakness – over-approximate target sets – is not 3) A demonstration of how to efficiently use MPX to fundamental to the problem of preventing dynamic dispatch integrity protect arbitrary regions of memory. from being used for code-reuse attacks. At runtime there is only one correct target for any virtual call. The correct target II. C++ DYNAMIC DISPATCH is dictated by the dynamic type of the object used to make the virtual call. The alias analysis problem prevents static Dynamic dispatch is a key part of polymorphism in C++, analysis from determining the dynamic type of the object at allowing classes to override implementations of virtual func- the virtual call site. Indeed, any case where static analysis can tions that they inherit. Figure 1 contains a simple code exam- determine the exact type, as opposed to a set of types, should ple illustrating virtual functions, overriding implementations, be devirtualized as an optimization. Consequently, a security and the associated memory layout. C++ implements dynamic mechanism must leverage runtime information to correctly dispatch by maintaining a mapping from each object to its track an object’s type and secure dynamic dispatch on that underlying type – and thus the true implementation of the object, as opposed to the static, compile time information that object’s virtual functions. At each virtual call site, two things CFI policies rely on. occur: 1) the appropriate function is determined from the object’s virtual table, and 2) an indirect call to that function is We propose a new defense policy, Object Type Integrity made. The correctness of dynamic dispatch thus depends on (OTI) which guarantees that an object’s type cannot be mod- the integrity of the mapping from an object to its underlying ified by an adversary, i.e., integrity protecting it, thereby type, i.e., object type integrity. guaranteeing the correctness of dynamic dispatch on that object. OTI thus mitigates the second step of a code-reuse The object type mapping at the core of dynamic dispatch is attack by preventing key application control flow data from implemented by creating a virtual table for each polymorphic being corrupted. OTI tracks the assigned type for every object class. The virtual table consists of function pointers to the at runtime. Consequently, when the object’s type is used for a correct implementation of each of the class’s virtual functions. dynamic dispatch, OTI can verify that the type is uncorrupted. The compiler populates the virtual tables with the correct Further, OTI requires that each object has a known type, thus function pointers, and is responsible for managing the virtual preventing the attacker from injecting objects [33], and using function name to virtual table index mapping. The virtual them for dynamic dispatch. OTI distinguishes itself from CFI tables are fixed at compile time, and mapped read only at by intervening one stage earlier in the attack, and by being runtime. Each object of a class is given a virtual table pointer fully precise, instead of relying on target sets.