Clang: Hardware-Assisted AddressSanitizer Design Documentation

signa111 pts0 comments

Hardware-assisted AddressSanitizer Design Documentation — Clang 24.0.0git documentation

Clang 24.0.0git documentation

Hardware-assisted AddressSanitizer Design Documentation

«  ABI tags<br>::<br>Contents<br>::<br>Constant Interpreter  »

Hardware-assisted AddressSanitizer Design Documentation¶

This page is a design document for<br>hardware-assisted AddressSanitizer (or HWASAN )<br>a tool similar to AddressSanitizer,<br>but based on partial hardware assistance.

Introduction¶

AddressSanitizer<br>tags every 8 bytes of the application memory with a 1 byte tag (using shadow memory),<br>uses redzones to find buffer-overflows and<br>quarantine to find use-after-free.<br>The redzones, the quarantine, and, to a lesser extent, the shadow, are the<br>sources of AddressSanitizer’s memory overhead.<br>See the AddressSanitizer paper for details.

AArch64 has Address Tagging (or top-byte-ignore, TBI), a hardware feature that allows<br>software to use the 8 most significant bits of a 64-bit pointer as<br>a tag. HWASAN uses Address Tagging<br>to implement a memory safety tool, similar to AddressSanitizer,<br>but with smaller memory overhead and slightly different (mostly better)<br>accuracy guarantees.

Intel’s Linear Address Masking (LAM) also provides address tagging for<br>x86_64, though it is not widely available in hardware yet. For x86_64, HWASAN<br>has a limited implementation using page aliasing instead.

Algorithm¶

Every heap/stack/global memory object is forcibly aligned by TG bytes<br>(TG is e.g. 16 or 64). We call TG the tagging granularity .

For every such object a random TS-bit tag T is chosen (TS, or tag size, is e.g. 4 or 8)

The pointer to the object is tagged with T.

The memory for the object is also tagged with T (using a TG=>1 shadow memory)

Every load and store is instrumented to read the memory tag and compare it<br>with the pointer tag, exception is raised on tag mismatch.

For a more detailed discussion of this approach see https://arxiv.org/pdf/1802.09517.pdf

Short granules¶

A short granule is a granule of size between 1 and TG-1 bytes. The size<br>of a short granule is stored at the location in shadow memory where the<br>granule’s tag is normally stored, while the granule’s actual tag is stored<br>in the last byte of the granule. This means that in order to verify that a<br>pointer tag matches a memory tag, HWASAN must check for two possibilities:

the pointer tag is equal to the memory tag in shadow memory, or

the shadow memory tag is actually a short granule size, the value being loaded<br>is in bounds of the granule and the pointer tag is equal to the last byte of<br>the granule.

Pointer tags between 1 to TG-1 are possible and are as likely as any other<br>tag. This means that these tags in memory have two interpretations: the full<br>tag interpretation (where the pointer tag is between 1 and TG-1 and the<br>last byte of the granule is ordinary data) and the short tag interpretation<br>(where the pointer tag is stored in the granule).

When HWASAN detects an error near a memory tag between 1 and TG-1, it<br>will show both the memory tag and the last byte of the granule. Currently,<br>it is up to the user to disambiguate the two possibilities.

Instrumentation¶

Memory Accesses¶

In the majority of cases, memory accesses are prefixed with a call to<br>an outlined instruction sequence that verifies the tags. The code size<br>and performance overhead of the call is reduced by using a custom calling<br>convention that

preserves most registers, and

is specialized to the register containing the address, and the type and<br>size of the memory access.

Currently, the following sequence is used:

// int foo(int *a) { return *a; }<br>// clang -O2 --target=aarch64-linux-android30 -fsanitize=hwaddress -S -o - load.c<br>[...]<br>foo:<br>stp x30, x20, [sp, #-16]!<br>adrp x20, :got:__hwasan_shadow // load shadow address from GOT into x20<br>ldr x20, [x20, :got_lo12:__hwasan_shadow]<br>bl __hwasan_check_x0_2_short_v2 // call outlined tag check<br>// (arguments: x0 = address, x20 = shadow base;<br>// "2" encodes the access type and size)<br>ldr w0, [x0] // inline load<br>ldp x30, x20, [sp], #16<br>ret

[...]<br>__hwasan_check_x0_2_short_v2:<br>sbfx x16, x0, #4, #52 // shadow offset<br>ldrb w16, [x20, x16] // load shadow tag<br>cmp x16, x0, lsr #56 // extract address tag, compare with shadow tag<br>b.ne .Ltmp0 // jump to short tag handler on mismatch<br>.Ltmp1:<br>ret<br>.Ltmp0:<br>cmp w16, #15 // is this a short tag?<br>b.hi .Ltmp2 // if not, error<br>and x17, x0, #0xf // find the address's position in the short granule<br>add x17, x17, #3 // adjust to the position of the last byte loaded<br>cmp w16, w17 // check that position is in bounds<br>b.ls .Ltmp2 // if not, error<br>orr x16, x0, #0xf // compute address of last byte of granule<br>ldrb w16, [x16] // load tag from it<br>cmp x16, x0, lsr #56 // compare with pointer tag<br>b.eq .Ltmp1 // if matches, continue<br>.Ltmp2:<br>stp x0, x1, [sp, #-256]! // save original x0, x1 on stack (they will be overwritten)<br>stp x29, x30, [sp, #232] // create frame record<br>mov x1, #2 // set x1 to a constant indicating the type of failure<br>adrp x16,...

memory granule shadow addresssanitizer address pointer

Related Articles