Fine-Grained Control-Flow Integrity Through Binary Hardening [chapter]

Mathias Payer, Antonio Barresi, Thomas R. Gross
2015 Lecture Notes in Computer Science  
Applications written in low-level languages without type or memory safety are prone to memory corruption. Attackers gain code execution capabilities through memory corruption despite all currently deployed defenses. Control-Flow Integrity (CFI) is a promising security property that restricts indirect control-flow transfers to a static set of well-known locations. We present Lockdown, a modular, fine-grained CFI policy that protects binary-only applications and libraries without requiring
more » ... ode. Lockdown adaptively discovers the control-flow graph of a running process based on the executed code. The sandbox component of Lockdown restricts interactions between different shared objects to imported and exported functions by enforcing fine-grained CFI checks using information from a trusted dynamic loader. A shadow stack enforces precise integrity for function returns. Our prototype implementation shows that Lockdown results in low performance overhead and a security analysis discusses any remaining gadgets. in their precision due to an over-approximation of the target sets where too many targets are allowed (these coarse-grained CFI policies can be exploited by attackers [8, 14, 17] ), (ii) the need to recompile applications [4, 16, 34, 38, 45, 47, 49] , (iii) no support (or protection) for shared libraries [1, 4, 16, 33, 38, 47] , or (iv) no stack integrity protection [12, 34, 45, 48, 51, 52] . Modular CFI (MCFI) [34] recently added support for shared libraries but a recompilation of the application and all libraries is required. Furthermore, MCFI might require source code changes in the application, comes with its own libc implementation, which makes it less flexible, and does not support C++ code. COOP [40] presents an attack against CFI mechanisms that are unaware of C++ semantics for virtual function calls. Both MCFI and COOP were developed concurrently with Lockdown. This paper presents Lockdown, a modular fine-grained CFI policy that supports any legacy binary. All indirect control-flow transfers are instrumented with security checks through dynamic binary translation. The target-sets for finegrained CFI are approximated based on import and export definitions used in applications and libraries and a dynamic on-the-fly binary analysis for addresses of function pointers that are taken during the execution of the application. Using this approach, Lockdown adjusts the control-flow graph at runtime as code is being executed, growing the CFG when new code is executed, shrinking the CFG when libraries are unloaded. To protect against all forms of Return-Oriented Programming (ROP), Lockdown employs a shadow stack that enforces precise integrity of return instruction pointers. A shadow stack is stricter than a CFI check as the CFI check would allow the return instruction to target any possible call site of the current function while the shadow stack only allows the return to target the actual caller (by keeping state through the call/return relationship). A prototype implementation of our fine-grained CFI policy results in 19% average performance overhead for SPEC CPU2006 (which is on the same order as fine-grained source-level CFI implementations) and the performance overhead for Apache 2.2 is between 1.83% and 7.87% (depending on the configuration). This paper makes the following contributions:
doi:10.1007/978-3-319-20550-2_8 fatcat:imb2l3voebeqxbwkg4dvwvubjq