| 1 | //===-- scudo/interface.h ---------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef SCUDO_INTERFACE_H_ |
| 10 | #define SCUDO_INTERFACE_H_ |
| 11 | |
| 12 | #include <stddef.h> |
| 13 | #include <stdint.h> |
| 14 | |
| 15 | extern "C" { |
| 16 | |
| 17 | __attribute__((weak)) const char *__scudo_default_options(void); |
| 18 | |
| 19 | // Post-allocation & pre-deallocation hooks. |
| 20 | __attribute__((weak)) void __scudo_allocate_hook(void *ptr, size_t size); |
| 21 | __attribute__((weak)) void __scudo_deallocate_hook(void *ptr); |
| 22 | |
| 23 | // `realloc` involves both deallocation and allocation but they are not reported |
| 24 | // atomically. In one specific case which may keep taking a snapshot right in |
| 25 | // the middle of `realloc` reporting the deallocation and allocation, it may |
| 26 | // confuse the user by missing memory from `realloc`. To alleviate that case, |
| 27 | // define the two `realloc` hooks to get the knowledge of the bundled hook |
| 28 | // calls. These hooks are optional and should only be used when a hooks user |
| 29 | // wants to track reallocs more closely. |
| 30 | // |
| 31 | // See more details in the comment of `realloc` in wrapper_c.inc. |
| 32 | __attribute__((weak)) void |
| 33 | __scudo_realloc_allocate_hook(void *old_ptr, void *new_ptr, size_t size); |
| 34 | __attribute__((weak)) void __scudo_realloc_deallocate_hook(void *old_ptr); |
| 35 | |
| 36 | void __scudo_print_stats(void); |
| 37 | |
| 38 | typedef void (*iterate_callback)(uintptr_t base, size_t size, void *arg); |
| 39 | |
| 40 | // Determine the likely cause of a tag check fault or other memory protection |
| 41 | // error on a system with memory tagging support. The results are returned via |
| 42 | // the error_info data structure. Up to three possible causes are returned in |
| 43 | // the reports array, in decreasing order of probability. The remaining elements |
| 44 | // of reports are zero-initialized. |
| 45 | // |
| 46 | // This function may be called from a different process from the one that |
| 47 | // crashed. In this case, various data structures must be copied from the |
| 48 | // crashing process to the process that analyzes the crash. |
| 49 | // |
| 50 | // This interface is not guaranteed to be stable and may change at any time. |
| 51 | // Furthermore, the version of scudo in the crashing process must be the same as |
| 52 | // the version in the process that analyzes the crash. |
| 53 | // |
| 54 | // fault_addr is the fault address. On aarch64 this is available in the system |
| 55 | // register FAR_ELx, or siginfo.si_addr in Linux 5.11 or above. This address |
| 56 | // must include the pointer tag; this is available if SA_EXPOSE_TAGBITS was set |
| 57 | // in sigaction.sa_flags when the signal handler was registered. Note that the |
| 58 | // kernel strips the tag from the field sigcontext.fault_address, so this |
| 59 | // address is not suitable to be passed as fault_addr. |
| 60 | // |
| 61 | // stack_depot is a pointer to the stack depot data structure, which may be |
| 62 | // obtained by calling the function __scudo_get_stack_depot_addr() in the |
| 63 | // crashing process. The size of the stack depot is available by calling the |
| 64 | // function __scudo_get_stack_depot_size(). |
| 65 | // |
| 66 | // region_info is a pointer to the region info data structure, which may be |
| 67 | // obtained by calling the function __scudo_get_region_info_addr() in the |
| 68 | // crashing process. The size of the region info is available by calling the |
| 69 | // function __scudo_get_region_info_size(). |
| 70 | // |
| 71 | // memory is a pointer to a region of memory surrounding the fault address. |
| 72 | // The more memory available via this pointer, the more likely it is that the |
| 73 | // function will be able to analyze a crash correctly. It is recommended to |
| 74 | // provide an amount of memory equal to 16 * the primary allocator's largest |
| 75 | // size class either side of the fault address. |
| 76 | // |
| 77 | // memory_tags is a pointer to an array of memory tags for the memory accessed |
| 78 | // via memory. Each byte of this array corresponds to a region of memory of size |
| 79 | // equal to the architecturally defined memory tag granule size (16 on aarch64). |
| 80 | // |
| 81 | // memory_addr is the start address of memory in the crashing process's address |
| 82 | // space. |
| 83 | // |
| 84 | // memory_size is the size of the memory region referred to by the memory |
| 85 | // pointer. |
| 86 | void __scudo_get_error_info(struct scudo_error_info *error_info, |
| 87 | uintptr_t fault_addr, const char *stack_depot, |
| 88 | size_t stack_depot_size, const char *region_info, |
| 89 | const char *ring_buffer, size_t ring_buffer_size, |
| 90 | const char *memory, const char *memory_tags, |
| 91 | uintptr_t memory_addr, size_t memory_size); |
| 92 | |
| 93 | enum scudo_error_type { |
| 94 | UNKNOWN, |
| 95 | USE_AFTER_FREE, |
| 96 | BUFFER_OVERFLOW, |
| 97 | BUFFER_UNDERFLOW, |
| 98 | }; |
| 99 | |
| 100 | struct scudo_error_report { |
| 101 | enum scudo_error_type error_type; |
| 102 | |
| 103 | uintptr_t allocation_address; |
| 104 | uintptr_t allocation_size; |
| 105 | |
| 106 | uint32_t allocation_tid; |
| 107 | uintptr_t allocation_trace[64]; |
| 108 | |
| 109 | uint32_t deallocation_tid; |
| 110 | uintptr_t deallocation_trace[64]; |
| 111 | }; |
| 112 | |
| 113 | struct scudo_error_info { |
| 114 | struct scudo_error_report reports[3]; |
| 115 | }; |
| 116 | |
| 117 | const char *__scudo_get_stack_depot_addr(void); |
| 118 | size_t __scudo_get_stack_depot_size(void); |
| 119 | |
| 120 | const char *__scudo_get_region_info_addr(void); |
| 121 | size_t __scudo_get_region_info_size(void); |
| 122 | |
| 123 | const char *__scudo_get_ring_buffer_addr(void); |
| 124 | size_t __scudo_get_ring_buffer_size(void); |
| 125 | |
| 126 | #ifndef M_DECAY_TIME |
| 127 | #define M_DECAY_TIME -100 |
| 128 | #endif |
| 129 | |
| 130 | #ifndef M_PURGE |
| 131 | #define M_PURGE -101 |
| 132 | #endif |
| 133 | |
| 134 | #ifndef M_PURGE_ALL |
| 135 | #define M_PURGE_ALL -104 |
| 136 | #endif |
| 137 | |
| 138 | // Tune the allocator's choice of memory tags to make it more likely that |
| 139 | // a certain class of memory errors will be detected. The value argument should |
| 140 | // be one of the M_MEMTAG_TUNING_* constants below. |
| 141 | #ifndef M_MEMTAG_TUNING |
| 142 | #define M_MEMTAG_TUNING -102 |
| 143 | #endif |
| 144 | |
| 145 | // Per-thread memory initialization tuning. The value argument should be one of: |
| 146 | // 1: Disable automatic heap initialization and, where possible, memory tagging, |
| 147 | // on this thread. |
| 148 | // 0: Normal behavior. |
| 149 | #ifndef M_THREAD_DISABLE_MEM_INIT |
| 150 | #define M_THREAD_DISABLE_MEM_INIT -103 |
| 151 | #endif |
| 152 | |
| 153 | #ifndef M_CACHE_COUNT_MAX |
| 154 | #define M_CACHE_COUNT_MAX -200 |
| 155 | #endif |
| 156 | |
| 157 | #ifndef M_CACHE_SIZE_MAX |
| 158 | #define M_CACHE_SIZE_MAX -201 |
| 159 | #endif |
| 160 | |
| 161 | #ifndef M_TSDS_COUNT_MAX |
| 162 | #define M_TSDS_COUNT_MAX -202 |
| 163 | #endif |
| 164 | |
| 165 | // Tune for buffer overflows. |
| 166 | #ifndef M_MEMTAG_TUNING_BUFFER_OVERFLOW |
| 167 | #define M_MEMTAG_TUNING_BUFFER_OVERFLOW 0 |
| 168 | #endif |
| 169 | |
| 170 | // Tune for use-after-free. |
| 171 | #ifndef M_MEMTAG_TUNING_UAF |
| 172 | #define M_MEMTAG_TUNING_UAF 1 |
| 173 | #endif |
| 174 | |
| 175 | // Print internal stats to the log. |
| 176 | #ifndef M_LOG_STATS |
| 177 | #define M_LOG_STATS -205 |
| 178 | #endif |
| 179 | |
| 180 | } // extern "C" |
| 181 | |
| 182 | #endif // SCUDO_INTERFACE_H_ |
| 183 | |