[clang] 7931e8e - Update hwasan docs to cover outlined checks and globals.

Peter Collingbourne via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 6 17:44:55 PST 2020


Author: Peter Collingbourne
Date: 2020-02-06T17:44:43-08:00
New Revision: 7931e8eee3dafe64101dcc1aaaae88276ba81071

URL: https://github.com/llvm/llvm-project/commit/7931e8eee3dafe64101dcc1aaaae88276ba81071
DIFF: https://github.com/llvm/llvm-project/commit/7931e8eee3dafe64101dcc1aaaae88276ba81071.diff

LOG: Update hwasan docs to cover outlined checks and globals.

Differential Revision: https://reviews.llvm.org/D74150

Added: 
    

Modified: 
    clang/docs/HardwareAssistedAddressSanitizerDesign.rst

Removed: 
    


################################################################################
diff  --git a/clang/docs/HardwareAssistedAddressSanitizerDesign.rst b/clang/docs/HardwareAssistedAddressSanitizerDesign.rst
index d02dc00057fe..0e6c6902cfb3 100644
--- a/clang/docs/HardwareAssistedAddressSanitizerDesign.rst
+++ b/clang/docs/HardwareAssistedAddressSanitizerDesign.rst
@@ -67,43 +67,59 @@ Instrumentation
 
 Memory Accesses
 ---------------
-All memory accesses are prefixed with an inline instruction sequence that
-verifies the tags. Currently, the following sequence is used:
+In the majority of cases, memory accesses are prefixed with a call to
+an outlined instruction sequence that verifies the tags. The code size
+and performance overhead of the call is reduced by using a custom calling
+convention that
+
+* preserves most registers, and
+* is specialized to the register containing the address, and the type and
+  size of the memory access.
+
+Currently, the following sequence is used:
 
 .. code-block:: none
 
   // int foo(int *a) { return *a; }
-  // clang -O2 --target=aarch64-linux -fsanitize=hwaddress -fsanitize-recover=hwaddress -c load.c
+  // clang -O2 --target=aarch64-linux-android30 -fsanitize=hwaddress -S -o - load.c
+  [...]
   foo:
-       0:	90000008 	adrp	x8, 0 <__hwasan_shadow>
-       4:	f9400108 	ldr	x8, [x8]         // shadow base (to be resolved by the loader)
-       8:	d344dc09 	ubfx	x9, x0, #4, #52  // shadow offset
-       c:	38696909 	ldrb	w9, [x8, x9]     // load shadow tag
-      10:	d378fc08 	lsr	x8, x0, #56      // extract address tag
-      14:	6b09011f 	cmp	w8, w9           // compare tags
-      18:	54000061 	b.ne	24 <foo+0x24>    // jump to short tag handler on mismatch
-      1c:	b9400000 	ldr	w0, [x0]         // original load
-      20:	d65f03c0 	ret
-      24:	7100413f 	cmp	w9, #0x10        // is this a short tag?
-      28:	54000142 	b.cs	50 <foo+0x50>    // if not, trap
-      2c:	12000c0a 	and	w10, w0, #0xf    // find the address's position in the short granule
-      30:	11000d4a 	add	w10, w10, #0x3   // adjust to the position of the last byte loaded
-      34:	6b09015f 	cmp	w10, w9          // check that position is in bounds
-      38:	540000c2 	b.cs	50 <foo+0x50>    // if not, trap
-      3c:	9240dc09 	and	x9, x0, #0xffffffffffffff
-      40:	b2400d29 	orr	x9, x9, #0xf     // compute address of last byte of granule
-      44:	39400129 	ldrb	w9, [x9]         // load tag from it
-      48:	6b09011f 	cmp	w8, w9           // compare with pointer tag
-      4c:	54fffe80 	b.eq	1c <foo+0x1c>    // if so, continue
-      50:	d4212440 	brk	#0x922           // otherwise trap
-      54:	b9400000 	ldr	w0, [x0]         // tail duplicated original load (to handle recovery)
-      58:	d65f03c0 	ret
-
-Alternatively, memory accesses are prefixed with a function call.
-On AArch64, a function call is used by default in trapping mode. The code size
-and performance overhead of the call is reduced by using a custom calling
-convention that preserves most registers and is specialized to the register
-containing the address and the type and size of the memory access.
+        str     x30, [sp, #-16]!
+        adrp    x9, :got:__hwasan_shadow                // load shadow address from GOT into x9
+        ldr     x9, [x9, :got_lo12:__hwasan_shadow]
+        bl      __hwasan_check_x0_2_short               // call outlined tag check
+                                                        // (arguments: x0 = address, x9 = shadow base;
+                                                        // "2" encodes the access type and size)
+        ldr     w0, [x0]                                // inline load
+        ldr     x30, [sp], #16
+        ret
+
+  [...]
+  __hwasan_check_x0_2_short:
+        ubfx    x16, x0, #4, #52                        // shadow offset
+        ldrb    w16, [x9, x16]                          // load shadow tag
+        cmp     x16, x0, lsr #56                        // extract address tag, compare with shadow tag
+        b.ne    .Ltmp0                                  // jump to short tag handler on mismatch
+  .Ltmp1:
+        ret
+  .Ltmp0:
+        cmp     w16, #15                                // is this a short tag?
+        b.hi    .Ltmp2                                  // if not, error
+        and     x17, x0, #0xf                           // find the address's position in the short granule
+        add     x17, x17, #3                            // adjust to the position of the last byte loaded
+        cmp     w16, w17                                // check that position is in bounds
+        b.ls    .Ltmp2                                  // if not, error
+        orr     x16, x0, #0xf                           // compute address of last byte of granule
+        ldrb    w16, [x16]                              // load tag from it
+        cmp     x16, x0, lsr #56                        // compare with pointer tag
+        b.eq    .Ltmp1                                  // if matches, continue
+  .Ltmp2:
+        stp     x0, x1, [sp, #-256]!                    // save original x0, x1 on stack (they will be overwritten)
+        stp     x29, x30, [sp, #232]                    // create frame record
+        mov     x1, #2                                  // set x1 to a constant indicating the type of failure
+        adrp    x16, :got:__hwasan_tag_mismatch_v2      // call runtime function to save remaining registers and report error
+        ldr     x16, [x16, :got_lo12:__hwasan_tag_mismatch_v2] // (load address from GOT to avoid potential register clobbers in delay load handler)
+        br      x16
 
 Heap
 ----
@@ -131,7 +147,67 @@ but could be optional.
 Globals
 -------
 
-TODO: details.
+Most globals in HWASAN instrumented code are tagged. This is accomplished
+using the following mechanisms:
+
+  * The address of each global has a static tag associated with it. The first
+    defined global in a translation unit has a pseudorandom tag associated
+    with it, based on the hash of the file path. Subsequent global tags are
+    incremental from the previously-assigned tag.
+
+  * The global's tag is added to its symbol address in the object file's symbol
+    table. This causes the global's address to be tagged when its address is
+    taken.
+
+  * When the address of a global is taken directly (i.e. not via the GOT), a special
+    instruction sequence needs to be used to add the tag to the address,
+    because the tag would otherwise take the address outside of the small code
+    model (4GB on AArch64). No changes are required when the address is taken
+    via the GOT because the address stored in the GOT will contain the tag.
+
+  * An associated ``hwasan_globals`` section is emitted for each tagged global,
+    which indicates the address of the global, its size and its tag.  These
+    sections are concatenated by the linker into a single ``hwasan_globals``
+    section that is enumerated by the runtime (via an ELF note) when a binary
+    is loaded and the memory is tagged accordingly.
+
+A complete example is given below:
+
+.. code-block:: none
+
+  // int x = 1; int *f() { return &x; }
+  // clang -O2 --target=aarch64-linux-android30 -fsanitize=hwaddress -S -o - global.c
+
+  [...]
+  f:
+        adrp    x0, :pg_hi21_nc:x            // set bits 12-63 to upper bits of untagged address
+        movk    x0, #:prel_g3:x+0x100000000  // set bits 48-63 to tag
+        add     x0, x0, :lo12:x              // set bits 0-11 to lower bits of address
+        ret
+
+  [...]
+        .data
+  .Lx.hwasan:
+        .word   1
+
+        .globl  x
+        .set x, .Lx.hwasan+0x2d00000000000000
+
+  [...]
+        .section        .note.hwasan.globals,"aG", at note,hwasan.module_ctor,comdat
+  .Lhwasan.note:
+        .word   8                            // namesz
+        .word   8                            // descsz
+        .word   3                            // NT_LLVM_HWASAN_GLOBALS
+        .asciz  "LLVM\000\000\000"
+        .word   __start_hwasan_globals-.Lhwasan.note
+        .word   __stop_hwasan_globals-.Lhwasan.note
+
+  [...]
+        .section        hwasan_globals,"ao", at progbits,.Lx.hwasan,unique,2
+  .Lx.hwasan.descriptor:
+        .word   .Lx.hwasan-.Lx.hwasan.descriptor
+        .word   0x2d000004                   // tag = 0x2d, size = 4
 
 Error reporting
 ---------------


        


More information about the cfe-commits mailing list