Unintended integer overflows can cause memory corruption or information disclosure vulnerabilities in variables associated with memory accesses or memory allocations. To combat this, we added Clang's UndefinedBehaviorSanitizer (UBSan) signed and unsigned integer overflow sanitizers to harden the media framework in Android 7.0. In Android 9, we expanded UBSan to cover more components and improved build system support for it.
This is designed to add checks around arithmetic operations / instructions—which might overflow—to safely abort a process if an overflow does happen. These sanitizers can mitigate an entire class of memory corruption and information disclosure vulnerabilities where the root cause is an integer overflow, such as the original Stagefright vulnerability.
Examples and source
Integer Overflow Sanitization (IntSan) is provided by the compiler and adds
instrumentation into the binary during compile time to detect arithmetic
overflows. It is enabled by default in various components throughout the
platform, for example
/platform/external/libnl/Android.bp
.
Implementation
IntSan uses UBSan's signed and unsigned integer overflow sanitizers. This mitigation is enabled on a per-module level. It helps keep critical components of Android secure and should not be disabled.
We strongly encourage you to enable Integer Overflow Sanitization for additional components. Ideal candidates are privileged native code or native code that parses untrusted user input. There is a small performance overhead associated with the sanitizer that is dependent on code's usage and the prevalence of arithmetic operations. Expect a small overhead percentage and test if performance is a concern.
Supporting IntSan in makefiles
To enable IntSan in a makefile, add:
LOCAL_SANITIZE := integer_overflow # Optional features LOCAL_SANITIZE_DIAG := integer_overflow LOCAL_SANITIZE_BLACKLIST := modulename_blacklist.txt
LOCAL_SANITIZE
takes a comma separated list of sanitizers, withinteger_overflow
being a pre-packaged set of options for the individual signed and unsigned integer overflow sanitizers with a default blacklist.LOCAL_SANITIZE_DIAG
turns on diagnostics mode for the sanitizers. Use diagnostics mode only during testing because this will not abort on overflows, completely negating the security advantage of the mitigation. See Troubleshooting for additional details.LOCAL_SANITIZE_BLACKLIST
allows you to specify a blacklist file to prevent functions and source files from being sanitized. See Troubleshooting for additional details.
If you want more granular control, enable the sanitizers individually using one or both flags:
LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow
Supporting IntSan in blueprint files
To enable integer overflow sanitization in a blueprint file, such as
/platform/external/libnl/Android.bp
,
add:
sanitize: { integer_overflow: true, diag: { integer_overflow: true, }, blacklist: "modulename_blacklist.txt", },
As with make files, the integer_overflow
property is a pre-packaged
set of options for the individual signed and unsigned integer overflow
sanitizers with a default
blacklist.
The diag
set of properties enables diagnostics mode for the
sanitizers. Use diagnostics mode only during testing. Diagnostics mode doesn't
abort on overflows, which completely negates the security advantage of the
mitigation in user builds. See Troubleshooting for additional details.
The blacklist
property allows specification of a blacklist file
that allows developers to prevent functions and source files from being
sanitized. See Troubleshooting for
additional details.
To enable the sanitizers individually, use:
sanitize: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"], diag: { misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow",], }, blacklist: "modulename_blacklist.txt", },
Troubleshooting
If you are enabling integer overflow sanitization in new components, or rely on platform libraries that have had integer overflow sanitization, you may run into a few issues with benign integer overflows causing aborts. You should test components with sanitization enabled to ensure benign overflows can be surfaced.
To find, aborts caused by sanitization in user builds, search for
SIGABRT
crashes with Abort messages indicating an overflow caught
by UBSan, such as:
pid: ###, tid: ###, name: Binder:### >>> /system/bin/surfaceflinger <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'ubsan: sub-overflow'
The stack trace should include the function causing the abort, however, overflows that occur in inline functions may not be evident in the stack trace.
To more easily determine the root cause, enable diagnostics in the library triggering the abort and attempt to reproduce the error. With diagnostics enabled, the process will not abort and will instead continue to run. Not aborting helps maximize the number of benign overflows in a particular execution path without having to recompile after fixing each bug. Diagnostics produces an error message which includes the line number and source file causing the abort:
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')
Once the problematic arithmetic operation is located, ensure that the overflow is benign and intended (e.g. has no security implications). You can address the sanitizer abort by:
- Refactoring the code to avoid the overflow (example)
- Overflow explicitly via Clang's __builtin_*_overflow functions (example)
- Disabling sanitization in the function by specifying the
no_sanitize
attribute (example) - Disabling sanitization of a function or source file via a blacklist file (example)
You should use the most granular solution possible. For example, a large function with many arithmetic operations and a single overflowing operation should have the single operation refactored rather than the entire function blacklisted.
Common patterns that may result in benign overflows include:
- Implicit casts where an unsigned overflow occurs before being cast to a signed type (example)
- Linked list deletions which decrements the loop index on deletion (example)
- Assigning an unsigned type to -1 instead of specifying the actual max value (example)
- Loops which decrement an unsigned integer in the condition (example, example)
It is recommended that developers assure that cases where the sanitizer detects an overflow that it is indeed benign with no unintended side-effects or security implications before disabling sanitization.
Disabling IntSan
You can disable IntSan with blacklists or function attributes. Disable sparingly and only when refactoring the code is otherwise unreasonable or if there is problematic performance overhead.
See the upstream Clang documentation for more information on disabling IntSan with function attributes and blacklist file formatting. Blacklisting should be scoped to the particular sanitizer by using section names specifying the target sanitizer to avoid impacting other sanitizers.
Validation
Currently, there are no CTS test specifically for Integer Overflow Sanitization. Instead, make sure that CTS tests pass with or without IntSan enabled to verify that it is not impacting the device.