| <html devsite> |
| <head> |
| <title>Control Flow Integrity</title> |
| <meta name="project_path" value="/_project.yaml" /> |
| <meta name="book_path" value="/_book.yaml" /> |
| </head> |
| <body> |
| <!-- |
| Copyright 2018 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| //www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <p> |
| As of 2016, about 86% of all vulnerabilities on Android are memory safety |
| related. Most vulnerabilities are exploited by attackers changing the normal |
| control flow of an application to perform arbitrary malicious activities with |
| all the privileges of the exploited application. |
| <a href="https://clang.llvm.org/docs/ControlFlowIntegrity.html">Control flow |
| integrity</a> (CFI) is a security mechanism that disallows changes to the |
| original control flow graph of a compiled binary, making it significantly harder |
| to perform such attacks. |
| </p> |
| <p> |
| In Android 8.1, we enabled LLVM's implementation of CFI in the media stack. In |
| Android 9, we enabled CFI in more components and also the kernel. System CFI is |
| on by default but you need to enable kernel CFI. |
| </p> |
| <p> |
| LLVM's CFI requires compiling with |
| <a href="https://llvm.org/docs/LinkTimeOptimization.html">Link-Time Optimization |
| (LTO)</a>. LTO preserves the LLVM bitcode representation of object files until |
| link-time, which allows the compiler to better reason about what optimizations |
| can be performed. Enabling LTO reduces the size of the final binary and improves |
| performance, but increases compile time. In testing on Android, the combination |
| of LTO and CFI results in negligible overhead to code size and performance; in a |
| few cases both improved. |
| </p> |
| <p> |
| For more technical details about CFI and how other forward-control checks are |
| handled, see the <a |
| href="https://clang.llvm.org/docs/ControlFlowIntegrityDesign.html">LLVM design |
| documentation</a>. |
| </p> |
| |
| <h2 id="examples">Examples and source</h2> |
| <p> |
| CFI is provided by the compiler and adds instrumentation into the binary during |
| compile time. We support CFI in the Clang toolchain and the Android build system |
| in AOSP. |
| </p> |
| <p> |
| CFI is enabled by default for Arm64 devices for the set of components in |
| <code><a |
| href="https://android.googlesource.com/platform/build/+/master/target/product/cfi-common.mk">/platform/build/target/product/cfi-common.mk</a></code>. |
| It's also directly enabled in a set of media components' makefiles/blueprint |
| files, such as <code><a |
| href="https://android.googlesource.com/platform/frameworks/av/+/master/media/libmedia/Android.bp#117">/platform/frameworks/av/media/libmedia/Android.bp</a></code> |
| and <code><a |
| href="https://android.googlesource.com/platform/frameworks/av/+/master/cmds/stagefright/Android.mk#188">/platform/frameworks/av/cmds/stagefright/Android.mk</a></code>. |
| |
| <h2 id="system-cfi">Implementing system CFI</h2> |
| <p> |
| CFI is enabled by default if you use Clang and the Android build system. |
| Because CFI helps keep Android users safe, you should not disable it. |
| </p> |
| <p> |
| In fact, we strongly encourage you to enable CFI for additional components. |
| Ideal candidates are privileged native code, or native code that processes |
| untrusted user input. If you're using clang and the Android build system, you |
| can enable CFI in new components by adding a few lines to your makefiles or |
| blueprint files. |
| </p> |
| |
| <h3 id="cf-in-mk">Supporting CFI in makefiles</h3> |
| <p> |
| To enable CFI in a make file, such as <code><a |
| href="https://android.googlesource.com/platform/frameworks/av/+/master/cmds/stagefright/Android.mk#188">/platform/frameworks/av/cmds/stagefright/Android.mk</a></code>, |
| add: |
| |
| |
| |
| <pre |
| class="prettyprint">LOCAL_SANITIZE := cfi |
| # Optional features |
| LOCAL_SANITIZE_DIAG := cfi |
| LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt</pre> |
| <ul> |
| <li><code>LOCAL_SANITIZE</code> specifies CFI as the sanitizer during the |
| build.</li> |
| <li><code>LOCAL_SANITIZE_DIAG</code> turns on diagnostic mode for CFI. |
| Diagnostic mode prints out additional debug information in logcat during |
| crashes, which is useful while developing and testing your builds. Make |
| sure to remove diagnostic mode on productions builds, though.</li> |
| <li><code>LOCAL_SANITIZE_BLACKLIST</code> allows components to selectively |
| disable CFI instrumentation for individual functions or source files. You |
| can use a blacklist as a last resort to fix any user-facing issues that |
| might otherwise exist. For more details, see |
| <a href="#disabling-cfi">Disabling CFI</a>.</li> |
| </ul> |
| <h3 id="cfi-in-bp">Supporting CFI in blueprint files</h3> |
| <p> |
| To enable CFI in a blueprint file, such as <code><a |
| href="https://android.googlesource.com/platform/frameworks/av/+/master/media/libmedia/Android.bp#117">/platform/frameworks/av/media/libmedia/Android.bp</a></code>, |
| add:</p> |
| |
| |
| |
| <pre class="prettyprint"> sanitize: { |
| cfi: true, |
| diag: { |
| cfi: true, |
| }, |
| blacklist: "cfi_blacklist.txt", |
| },</pre> |
| |
| <h3 id="troubleshooting">Troubleshooting</h3> |
| <p> |
| If you're enabling CFI in new components, you may run into a few issues with |
| <em>function type mismatch errors</em> and <em>assembly code type mismatch |
| errors</em>. |
| </p> |
| <p> |
| Function type mismatch errors occur because CFI restricts indirect calls to only |
| jump to functions that have the same dynamic type as the static type used in the |
| call. CFI restricts virtual and non-virtual member function calls to only jump |
| to objects that are a derived class of the static type of the object used to |
| make the call. This means, when you have code that violates either of these |
| assumptions, the instrumentation that CFI adds will abort. For example, the |
| stack trace shows a SIGABRT and logcat contains a line about control flow |
| integrity finding a mismatch. |
| </p> |
| <p> |
| To fix this, ensure that the called function has the same type that was |
| statically declared. Here are two example CLs: |
| </p> |
| <ul> |
| <li><strong>Bluetooth</strong>: |
| <a href="https://android-review.googlesource.com/c/platform/system/bt/+/532377">/c/platform/system/bt/+/532377</a></li> |
| <li><strong>NFC</strong>: |
| <a href="https://android-review.googlesource.com/c/platform/system/nfc/+/527858">/c/platform/system/nfc/+/527858</a></li> |
| </ul> |
| <p> |
| Another possible issue is trying to enable CFI in code that contains indirect |
| calls to assembly. Because assembly code is not typed, this results in a type |
| mismatch. |
| </p> |
| <p> |
| To fix this, create native code wrappers for each assembly call, and give the |
| wrappers the same function signature as the calling poiner. The wrapper can then |
| directly call the assembly code. Because direct branches are not instrumented by |
| CFI (they cannot be repointed at runtime and so do not pose a security risk), |
| this will fix the issue. |
| </p> |
| <p> |
| If there are too many assembly functions and they cannot all be fixed, you can |
| also blacklist all functions that contain indirect calls to assembly. This is |
| not recommended as it disables CFI checks on these functions, thereby opening |
| attack surface. |
| </p> |
| <h3 id="disabling-cfi">Disabling CFI</h3> |
| <p> |
| We didn't observe any performance overhead, so you shouldn't need to disable |
| CFI. However, if there is a user-facing impact, you can selectively disable CFI |
| for individual functions or source files by supplying a sanitizer blacklist file |
| at compile time. The blacklist instructs the compiler to disable CFI |
| instrumentation in specified locations. |
| </p> |
| <p> |
| The Android build system provides support for per-component blacklists (allowing |
| you to choose source files or individual functions that will not receive CFI |
| instrumentation) for both Make and Soong. For more details on the format of a |
| blacklist file, see the <a |
| href="https://clang.llvm.org/docs/ControlFlowIntegrity.html#blacklist">upstream |
| Clang docs</a>. |
| </p> |
| |
| <h2 id="validation">Validation</h2> |
| <p> |
| Currently, there are no CTS test specifically for CFI. Instead, make sure that |
| CTS tests pass with or without CFI enabled to verify that CFI isn't impacting |
| the device. |
| </p> |
| </body> |
| </html> |