Friday, September 12, 2025
HomeCyber SecurityHandle Sanitizer for Naked-metal Firmware

Handle Sanitizer for Naked-metal Firmware


With regular enhancements to Android userspace and kernel safety, we’ve observed an growing curiosity from safety researchers directed in direction of decrease stage firmware. This space has historically obtained much less scrutiny, however is important to system safety. We have now beforehand mentioned how we’ve been prioritizing firmware safety, and apply mitigations in a firmware setting to mitigate unknown vulnerabilities.

On this publish we’ll present how the Kernel Handle Sanitizer (KASan) can be utilized to proactively uncover vulnerabilities earlier within the improvement lifecycle. Regardless of the slim software implied by its identify, KASan is relevant to a wide-range of firmware targets. Utilizing KASan enabled builds throughout testing and/or fuzzing may also help catch reminiscence corruption vulnerabilities and stability points earlier than they land on person gadgets. We have already used KASan in some firmware targets to proactively discover and repair 40+ reminiscence security bugs and vulnerabilities, together with a few of important severity.

Together with this weblog publish we’re releasing a small venture which demonstrates an implementation of KASan for bare-metal targets leveraging the QEMU system emulator. Readers can check with this implementation for technical particulars whereas following the weblog publish.

Handle Sanitizer (ASan) overview

Handle sanitizer is a compiler-based instrumentation device used to determine invalid reminiscence entry operations throughout runtime. It’s able to detecting the next lessons of temporal and spatial reminiscence security bugs:

  • out-of-bounds reminiscence entry
  • use-after-free
  • double/invalid free
  • use-after-return

ASan depends on the compiler to instrument code with dynamic checks for digital addresses utilized in load/retailer operations. A separate runtime library defines the instrumentation hooks for the heap reminiscence and error reporting. For many user-space targets (comparable to aarch64-linux-android) ASan might be enabled as merely as utilizing the -fsanitize=tackle compiler possibility for Clang as a consequence of present assist of this goal each within the toolchain and within the libclang_rt runtime.

Nonetheless, the state of affairs is relatively totally different for bare-metal code which is ceaselessly constructed with the none system targets, comparable to arm-none-eabi. In contrast to conventional user-space applications, bare-metal code working inside an embedded system typically doesn’t have a standard runtime implementation. As such, LLVM can’t present a default runtime for these environments.

To supply customized implementations for the mandatory runtime routines, the Clang toolchain exposes an interface for tackle sanitization by the -fsanitize=kernel-address compiler possibility. The KASan runtime routines applied within the Linux kernel function an ideal instance of outline a KASan runtime for targets which aren’t supported by default with -fsanitize=tackle. We’ll reveal use the model of tackle sanitizer initially constructed for the kernel on different bare-metal targets.

KASan 101

Let’s check out the KASan main constructing blocks from a high-level perspective (a radical clarification of how ASan works under-the-hood is offered on this whitepaper).

The primary thought behind KASan is that each reminiscence entry operation, comparable to load/retailer directions and reminiscence copy capabilities (for instance, memmove and memcpy), are instrumented with code which performs verification of the vacation spot/supply reminiscence areas. KASan solely permits the reminiscence entry operations which use legitimate reminiscence areas. When KASan detects reminiscence entry to a reminiscence area which is invalid (that’s, the reminiscence has been already freed or entry is out-of-bounds) then it studies this violation to the system.

The state of reminiscence areas coated by KASan is maintained in a devoted space known as shadow reminiscence. Each byte within the shadow reminiscence corresponds to a single fixed-size reminiscence area coated by KASan (usually 8-bytes) and encodes its state: whether or not the corresponding reminiscence area has been allotted or freed and what number of bytes within the reminiscence area are accessible.

Due to this fact, to allow KASan for a bare-metal goal we would wish to implement the instrumentation routines which confirm validity of reminiscence areas in reminiscence entry operations and report KASan violations to the system. As well as we might additionally have to implement shadow reminiscence administration to trace the state of reminiscence areas which we need to be coated with KASan.

Enabling KASan for bare-metal firmware

KASan shadow reminiscence

The very first step in enabling KASan for firmware is to order a ample quantity of DRAM for shadow reminiscence. It is a reminiscence area the place every byte is utilized by KASan to trace the state of an 8-byte area. This implies accommodating the shadow reminiscence requires a devoted reminiscence area equal to 1/eighth the dimensions of the tackle house coated by KASan.

KASan maps each 8-byte aligned tackle from the DRAM area into the shadow reminiscence utilizing the next system:

shadow_address = (target_address >> 3 ) + shadow_memory_base

the place target_address is the tackle of a 8-byte reminiscence area which we need to cowl with KASan and shadow_memory_base is the bottom tackle of the shadow reminiscence space.

Implement a KASan runtime

As soon as we’ve the shadow reminiscence monitoring the state of each single 8-byte reminiscence area of DRAM we have to implement the mandatory runtime routines which KASan instrumentation is determined by. For reference, a complete checklist of runtime routines wanted for KASan might be discovered within the linux/mm/kasan/kasan.h Linux kernel header. Nonetheless, it won’t be essential to implement all of them and within the following textual content we deal with those which have been wanted to allow KASan for our goal firmware for example.

Reminiscence entry test

The routines __asan_loadXX_noabort, __asan_storeXX_noabort carry out verification of reminiscence entry at runtime. The image XX denotes measurement of reminiscence entry and goes as an influence of two ranging from 1 as much as 16. The toolchain devices each reminiscence load and retailer operations with these capabilities in order that they’re invoked earlier than the reminiscence entry operation occurs. These routines take as enter a pointer to the goal reminiscence area to test it towards the shadow reminiscence.

If the area state offered by shadow reminiscence doesn’t reveal a violation, then these capabilities return to the caller. But when any violations (for instance, the reminiscence area is accessed after it has been deallocated or there’s an out-of-bounds entry) are revealed, then these capabilities report the KASan violation by:

  • Producing a call-stack.
  • Capturing context across the reminiscence areas.
  • Logging the error.
  • Aborting/crashing the system (optionally available)

Shadow reminiscence administration

The routine __asan_set_shadow_YY is used to poison shadow reminiscence for a given tackle. This routine is utilized by the toolchain instrumentation to replace the state of reminiscence areas. For instance, the KASan runtime would use this operate to mark reminiscence for native variables on the stack as accessible/poisoned within the epilogue/prologue of the operate respectively.

This routine takes as enter a goal reminiscence tackle and units the corresponding byte in shadow reminiscence to the worth of YY. Right here is an instance of some YY values for shadow reminiscence to encode state of 8-byte reminiscence areas:

  • 0x00 — all the 8-byte area is accessible
  • 0x01-0x07 — solely the primary bytes within the reminiscence area are accessible
  • 0xf1 — not accessible: stack left purple zone
  • 0xf2 — not accessible: stack mid purple zone
  • 0xf3 — not accessible: stack proper purple zone
  • 0xfa — not accessible: globals purple zone
  • 0xff — not accessible

Overlaying world variables

The routines __asan_register_globals, __asan_unregister_globals are used to poison/unpoison reminiscence for world variables. The KASan runtime calls these capabilities whereas processing world constructors/destructors. As an example, the routine __asan_register_globals is invoked for each world variable. It takes as an argument a pointer to a knowledge construction which describes the goal world variable: the construction supplies the beginning tackle of the variable, its measurement not together with the purple zone and measurement of the worldwide variable with the purple zone.

The purple zone is further padding the compiler inserts after the variable to extend the probability of detecting an out-of-bounds reminiscence entry. Pink zones guarantee there’s further house between adjoining world variables. It’s the duty of __asan_register_globals routine to mark the corresponding shadow reminiscence as accessible for the variable and as poisoned for the purple zone.

Because the readers may infer from its identify, the routine __asan_unregister_globals is invoked whereas processing world destructors and is meant to poison shadow reminiscence for the goal world variable. Consequently, any reminiscence entry to such a world will trigger a KASan violation.

Reminiscence copy capabilities

The KASan compiler instrumentation routines __asan_loadXX_noabort, __asan_storeXX_noabort mentioned above are used to confirm particular person reminiscence load and retailer operations comparable to, studying or writing an array ingredient or dereferencing a pointer. Nonetheless, these routines do not cowl reminiscence entry in bulk-memory copy capabilities comparable to memcpy, memmove, and memset. In lots of instances these capabilities are offered by the runtime library or applied in meeting to optimize for efficiency.

Due to this fact, so as to have the ability to catch invalid reminiscence entry in these capabilities, we would wish to supply sanitized variations of memcpy, memmove, and memset capabilities in our KASan implementation which might confirm reminiscence buffers to be legitimate reminiscence areas.

Avoiding false positives for noreturn capabilities

One other routine required by KASan is __asan_handle_no_return, to carry out cleanup earlier than a noreturn operate and keep away from false positives on the stack. KASan provides purple zones round stack variables at first of every operate, and removes them on the finish. If a operate doesn’t return usually (for instance, in case of longjmp-like capabilities and exception dealing with), purple zones have to be eliminated explicitly with __asan_handle_no_return.

Hook heap reminiscence allocation routines

Naked-metal code within the overwhelming majority of instances supplies its personal heap implementation. It’s our duty to implement an instrumented model of heap reminiscence allocation and releasing routines which allow KASan to detect reminiscence corruption bugs on the heap.

Basically, we would wish to instrument the reminiscence allocator with the code which unpoisons KASan shadow reminiscence equivalent to the allotted reminiscence buffer. Moreover, we could need to insert an additional poisoned purple zone reminiscence (which accessing would then generate a KASan violation) to the top of the allotted buffer to extend the probability of catching out-of-bounds reminiscence reads/writes.

Equally, within the reminiscence deallocation routine (comparable to free) we would wish to poison the shadow reminiscence equivalent to the free buffer in order that any subsequent entry (comparable to, use-after-free) would generate a KASan violation.

We are able to go even additional by inserting the freed reminiscence buffer right into a quarantine as a substitute of instantly returning the free reminiscence again to the allocator. This fashion, the freed reminiscence buffer is suspended in quarantine for a while and could have its KASan shadow bytes poisoned for an extended time period, growing the likelihood of catching a use-after-free entry to this buffer.

Allow KASan for heap, stack and world variables

With all the mandatory constructing blocks applied we’re able to allow KASan for our bare-metal code by making use of the next compiler choices whereas constructing the goal with the LLVM toolchain.

The -fsanitize=kernel-address Clang possibility instructs the compiler to instrument reminiscence load/retailer operations with the KASan verification routines.

We use the -asan-mapping-offset LLVM possibility to point the place we wish our shadow reminiscence to be situated. As an example, let’s assume that we want to cowl tackle vary 0x40000000 – 0x4fffffff and we need to hold shadow reminiscence at tackle 0x4A700000. So, we might use -mllvm -asan-mapping-offset=0x42700000 as 0x40000000 >> 3 + 0x42700000 == 0x4A700000.

To cowl globals and stack variables with KASan we would wish to move further choices to the compiler: -mllvm -asan-stack=1 -mllvm -asan-globals=1. It’s price mentioning that instrumenting each globals and stack variables will possible lead to a rise in measurement of the corresponding reminiscence which could should be accounted for within the linker script.

Lastly, to forestall important improve in measurement of the code part as a consequence of KASan instrumentation we instruct the compiler to all the time define KASan checks utilizing the -mllvm -asan-instrumentation-with-call-threshold=0 possibility. In any other case, the compiler may inline

__asan_loadXX_noabort, __asan_storeXX_noabort routines for load/retailer operations leading to bloating the generated object code.

LLVM has historically solely supported sanitizers with runtimes for particular targets with predefined runtimes, nonetheless we’ve upstreamed LLVM sanitizer assist for bare-metal targets beneath the idea that the runtime might be outlined for the actual goal. You’ll want the newest model of Clang to profit from this.

Conclusion

Following these steps we managed to allow KASan for a firmware goal and use it in pre-production check builds. This led to early discovery of reminiscence corruption points that have been simply remediated because of the actionable studies produced by KASan. These builds can be utilized with fuzzers to detect edge case bugs that ordinary testing fails to set off, but which may have important safety implications.

Our work with KASan is only one instance of the a number of methods the Android workforce is exploring to additional safe bare-metal firmware within the Android Platform. Ideally we need to keep away from introducing reminiscence security vulnerabilities within the first place so we’re working to deal with this drawback by adoption of memory-safe Rust in bare-metal environments. The Android workforce has developed Rust coaching which covers bare-metal Rust extensively. We extremely encourage others to discover Rust (or different memory-safe languages) as a substitute for C/C++ of their firmware.

You probably have any questions, please attain out – we’re right here to assist!

Acknowledgements: Thanks to Roger Piqueras Jover for contributions to this publish, and to Evgenii Stepanov for upstreaming LLVM assist for bare-metal sanitizers. Particular thanks additionally to our colleagues who contribute and assist our firmware safety efforts: Sami Tolvanen, Stephan Somogyi, Stephan Chen, Dominik Maier, Xuan Xing, Farzan Karimi, Pirama Arumuga Nainar, Stephen Hines.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments