| 1 | #include "sanitizer_common/sanitizer_asm.h" |
| 2 | #include "builtins/assembly.h" |
| 3 | |
| 4 | // The content of this file is AArch64-only: |
| 5 | #if defined(__aarch64__) |
| 6 | |
| 7 | // The responsibility of the HWASan entry point in compiler-rt is to primarily |
| 8 | // readjust the stack from the callee and save the current register values to |
| 9 | // the stack. |
| 10 | // This entry point function should be called from a __hwasan_check_* symbol. |
| 11 | // These are generated during a lowering pass in the backend, and are found in |
| 12 | // AArch64AsmPrinter::EmitHwasanMemaccessSymbols(). Please look there for |
| 13 | // further information. |
| 14 | // The __hwasan_check_* caller of this function should have expanded the stack |
| 15 | // and saved the previous values of x0, x1, x29, and x30. This function will |
| 16 | // "consume" these saved values and treats it as part of its own stack frame. |
| 17 | // In this sense, the __hwasan_check_* callee and this function "share" a stack |
| 18 | // frame. This allows us to omit having unwinding information (.cfi_*) present |
| 19 | // in every __hwasan_check_* function, therefore reducing binary size. This is |
| 20 | // particularly important as hwasan_check_* instances are duplicated in every |
| 21 | // translation unit where HWASan is enabled. |
| 22 | // This function calls HwasanTagMismatch to step back into the C++ code that |
| 23 | // completes the stack unwinding and error printing. This function is is not |
| 24 | // permitted to return. |
| 25 | |
| 26 | |
| 27 | // Frame from __hwasan_check_: |
| 28 | // | ... | |
| 29 | // | ... | |
| 30 | // | Previous stack frames... | |
| 31 | // +=================================+ |
| 32 | // | Unused 8-bytes for maintaining | |
| 33 | // | 16-byte SP alignment. | |
| 34 | // +---------------------------------+ |
| 35 | // | Return address (x30) for caller | |
| 36 | // | of __hwasan_check_*. | |
| 37 | // +---------------------------------+ |
| 38 | // | Frame address (x29) for caller | |
| 39 | // | of __hwasan_check_* | |
| 40 | // +---------------------------------+ <-- [SP + 232] |
| 41 | // | ... | |
| 42 | // | | |
| 43 | // | Stack frame space for x2 - x28. | |
| 44 | // | | |
| 45 | // | ... | |
| 46 | // +---------------------------------+ <-- [SP + 16] |
| 47 | // | | |
| 48 | // | Saved x1, as __hwasan_check_* | |
| 49 | // | clobbers it. | |
| 50 | // +---------------------------------+ |
| 51 | // | Saved x0, likewise above. | |
| 52 | // +---------------------------------+ <-- [x30 / SP] |
| 53 | |
| 54 | // This function takes two arguments: |
| 55 | // * x0: The data address. |
| 56 | // * x1: The encoded access info for the failing access. |
| 57 | |
| 58 | // This function has two entry points. The first, __hwasan_tag_mismatch, is used |
| 59 | // by clients that were compiled without short tag checks (i.e. binaries built |
| 60 | // by older compilers and binaries targeting older runtimes). In this case the |
| 61 | // outlined tag check will be missing the code handling short tags (which won't |
| 62 | // be used in the binary's own stack variables but may be used on the heap |
| 63 | // or stack variables in other binaries), so the check needs to be done here. |
| 64 | // |
| 65 | // The second, __hwasan_tag_mismatch_v2, is used by binaries targeting newer |
| 66 | // runtimes. This entry point bypasses the short tag check since it will have |
| 67 | // already been done as part of the outlined tag check. Since tag mismatches are |
| 68 | // uncommon, there isn't a significant performance benefit to being able to |
| 69 | // bypass the check; the main benefits are that we can sometimes avoid |
| 70 | // clobbering the x17 register in error reports, and that the program will have |
| 71 | // a runtime dependency on the __hwasan_tag_mismatch_v2 symbol therefore it will |
| 72 | // fail to start up given an older (i.e. incompatible) runtime. |
| 73 | .section .text |
| 74 | .file "hwasan_tag_mismatch_aarch64.S" |
| 75 | .global __hwasan_tag_mismatch |
| 76 | .type __hwasan_tag_mismatch, %function |
| 77 | __hwasan_tag_mismatch: |
| 78 | BTI_J |
| 79 | |
| 80 | // Compute the granule position one past the end of the access. |
| 81 | mov x16, #1 |
| 82 | and x17, x1, #0xf |
| 83 | lsl x16, x16, x17 |
| 84 | and x17, x0, #0xf |
| 85 | add x17, x16, x17 |
| 86 | |
| 87 | // Load the shadow byte again and check whether it is a short tag within the |
| 88 | // range of the granule position computed above. |
| 89 | ubfx x16, x0, #4, #52 |
| 90 | ldrb w16, [x9, x16] |
| 91 | cmp w16, #0xf |
| 92 | b.hi mismatch |
| 93 | cmp w16, w17 |
| 94 | b.lo mismatch |
| 95 | |
| 96 | // Load the real tag from the last byte of the granule and compare against |
| 97 | // the pointer tag. |
| 98 | orr x16, x0, #0xf |
| 99 | ldrb w16, [x16] |
| 100 | cmp x16, x0, lsr #56 |
| 101 | b.ne mismatch |
| 102 | |
| 103 | // Restore x0, x1 and sp to their values from before the __hwasan_tag_mismatch |
| 104 | // call and resume execution. |
| 105 | ldp x0, x1, [sp], #256 |
| 106 | ret |
| 107 | |
| 108 | .global __hwasan_tag_mismatch_v2 |
| 109 | .type __hwasan_tag_mismatch_v2, %function |
| 110 | __hwasan_tag_mismatch_v2: |
| 111 | // Avoid using global label, to prevent "relocation out of range". |
| 112 | mismatch: |
| 113 | CFI_STARTPROC |
| 114 | BTI_J |
| 115 | |
| 116 | // Set the CFA to be the return address for caller of __hwasan_check_*. Note |
| 117 | // that we do not emit CFI predicates to describe the contents of this stack |
| 118 | // frame, as this proxy entry point should never be debugged. The contents |
| 119 | // are static and are handled by the unwinder after calling |
| 120 | // __hwasan_tag_mismatch. The frame pointer is already correctly setup |
| 121 | // by __hwasan_check_*. |
| 122 | add x29, sp, #232 |
| 123 | CFI_DEF_CFA(w29, 24) |
| 124 | CFI_OFFSET(w30, -16) |
| 125 | CFI_OFFSET(w29, -24) |
| 126 | |
| 127 | // Save the rest of the registers into the preallocated space left by |
| 128 | // __hwasan_check. |
| 129 | str x28, [sp, #224] |
| 130 | stp x26, x27, [sp, #208] |
| 131 | stp x24, x25, [sp, #192] |
| 132 | stp x22, x23, [sp, #176] |
| 133 | stp x20, x21, [sp, #160] |
| 134 | stp x18, x19, [sp, #144] |
| 135 | stp x16, x17, [sp, #128] |
| 136 | stp x14, x15, [sp, #112] |
| 137 | stp x12, x13, [sp, #96] |
| 138 | stp x10, x11, [sp, #80] |
| 139 | stp x8, x9, [sp, #64] |
| 140 | stp x6, x7, [sp, #48] |
| 141 | stp x4, x5, [sp, #32] |
| 142 | stp x2, x3, [sp, #16] |
| 143 | |
| 144 | // Pass the address of the frame to __hwasan_tag_mismatch4, so that it can |
| 145 | // extract the saved registers from this frame without having to worry about |
| 146 | // finding this frame. |
| 147 | mov x2, sp |
| 148 | |
| 149 | bl __hwasan_tag_mismatch4 |
| 150 | CFI_ENDPROC |
| 151 | |
| 152 | .Lfunc_end0: |
| 153 | .size __hwasan_tag_mismatch, .Lfunc_end0-__hwasan_tag_mismatch |
| 154 | |
| 155 | #endif // defined(__aarch64__) |
| 156 | |
| 157 | // We do not need executable stack. |
| 158 | NO_EXEC_STACK_DIRECTIVE |
| 159 | |
| 160 | GNU_PROPERTY_BTI_PAC |
| 161 | |