Hardware-assisted AddressSanitizer

See Understanding HWASan reports for information on how to read HWASan crashes!

Hardware-assisted AddressSanitizer (HWASan) is a memory error detection tool similar to AddressSanitizer. HWASan uses a lot less RAM compared to ASan, which makes it suitable for whole system sanitization. HWASan is only available on Android 10 and higher, and only on AArch64 hardware.

Although primarily useful for C/C++ code, HWASan can also help debug Java code that causes crashes in C/C++ used to implement Java interfaces. It's helpful because it catches memory errors when they happen, pointing you directly at the responsible code.

You can flash prebuilt HWASan images to supported Pixel devices from ci.android.com (detailed setup instructions).

Compared to classic ASan, HWASan has:

  • Similar CPU overhead (~2x)
  • Similar code size overhead (40 – 50%)
  • Much smaller RAM overhead (10% – 35%)

HWASan detects the same set of bugs as ASan:

  • Stack and heap buffer overflow/underflow
  • Heap use after free
  • Stack use outside scope
  • Double free/wild free

Additionally, HWASan detects stack use after return.

HWASan (same as ASan) is compatible with UBSan, both can be enabled on a target at the same time.

Implementation details and limitations

HWASan is based on the memory tagging approach, where a small random tag value is associated both with pointers and with ranges of memory addresses. For a memory access to be valid, the pointer and memory tags have to match. HWASan relies on ARMv8 feature top byte ignore (TBI), also called virtual address tagging, to store the pointer tag in the highest bits of the address.

You can read more about the design of HWASan on the Clang documentation site.

By design, HWASan doesn't have ASan's limited-size redzones for detecting overflows or ASan's limited-capacity quarantine for detecting use after free. For this reason, HWASan can detect a bug no matter how large the overflow is or how long ago the memory was deallocated. This gives HWASan a big advantage over ASan.

However, HWASan has a limited number of possible tag values (256), which means that there is a 0.4% probability of missing any bug during one execution of the program.

Requirements

Recent versions (4.14+) of the common Android kernel support HWASan out-of-the-box. The Android 10 specific branches do not have support for HWASan.

Userspace support for HWASan is available starting with Android 11.

If you are working with a different kernel, HWASan requires the Linux kernel to accept tagged pointers in system call arguments. Support for this was implemented in the following upstream patchsets:

If you are building with a custom toolchain, make sure that it includes everything up to LLVM commit c336557f.

Use HWASan

Use the following commands to build the entire platform using HWASan:

lunch aosp_walleye-userdebug # (or any other product)
export SANITIZE_TARGET=hwaddress
m -j

For convenience, you can add the SANITIZE_TARGET setting to a product definition, similar to aosp_coral_hwasan.

For users familiar with AddressSanitizer, a lot of build complexity is gone:

  • No need to run make twice.
  • Incremental builds work out of the box.
  • No need to flash userdata.

Some AddressSanitizer restrictions are also gone:

  • Static executables are supported.
  • It’s OK to skip sanitization of any target other than libc. Unlike with ASan there is no requirement that if a library is sanitized, then any executable that links it must be, too.

Switching between HWASan and regular images at the same (or higher) build number can be done freely. Wiping the device is not required.

To skip sanitization of a module, use LOCAL_NOSANITIZE := hwaddress (Android.mk) or sanitize: { hwaddress: false } (Android.bp).

Sanitize individual targets

HWASan can be enabled per-target in a regular (unsanitized) build, as long as libc.so is also sanitized. Add hwaddress: true to the sanitize block in "libc_defaults" in bionic/libc/Android.bp. Then do the same in the target you are working on.

Note that sanitizing libc enables tagging of heap memory allocations system-wide, as well as the checking of the tags for memory operations inside libc.so. This may catch bugs even in binaries that HWASan was not enabled on if the bad memory access is in libc.so (ex. pthread_mutex_unlock() on a delete()ed mutex).

It is not necessary to change any build files if the whole platform is built using HWASan.

Flashstation

For development purposes, you can flash a HWASan-enabled build of AOSP onto a Pixel device with unlocked bootloader using Flashstation. Select the _hwasan target, e.g. aosp_flame_hwasan-userdebug. See the NDK documentation for HWASan for app developers for more details.

Better stack traces

HWASan uses a fast, frame-pointer-based unwinder to record a stack trace for every memory allocation and deallocation event in the program. Android enables frame pointers in AArch64 code by default, so this works great in practice. If you need to unwind through managed code, set HWASAN_OPTIONS=fast_unwind_on_malloc=0 in the process environment. Note that bad memory access stack traces use the "slow" unwinder by default; this setting only affects allocation and deallocation traces. This option can be very CPU-intensive, depending on the load.

Symbolization

See Symbolization in "Understanding HWASan reports".

HWASan in apps

Similar to AddressSanitizer, HWASan can't see into Java code, but it can detect bugs in the JNI libraries. Until Android 14, running HWASan apps on a non-HWASan device was not supported.

On a HWASan device, apps can be checked with HWASan by building their code with SANITIZE_TARGET:=hwaddress in Make, or -fsanitize=hwaddress in compiler flags. On a non-HWASan device (running Android 14 or newer), a wrap.sh file setting LD_HWASAN=1 has to be added. See the app developer documentation for more details.