| #ifndef _included_clib_sanitizer_h |
| #define _included_clib_sanitizer_h |
| |
| #ifdef CLIB_SANITIZE_ADDR |
| |
| #include <sanitizer/asan_interface.h> |
| #include <vppinfra/clib.h> |
| #include <vppinfra/error_bootstrap.h> |
| |
| typedef struct |
| { |
| size_t shadow_scale; |
| size_t shadow_offset; |
| } clib_sanitizer_main_t; |
| |
| extern clib_sanitizer_main_t sanitizer_main; |
| |
| #define CLIB_NOSANITIZE_ADDR __attribute__((no_sanitize_address)) |
| #define CLIB_MEM_POISON(a, s) ASAN_POISON_MEMORY_REGION((a), (s)) |
| #define CLIB_MEM_UNPOISON(a, s) ASAN_UNPOISON_MEMORY_REGION((a), (s)) |
| |
| #define CLIB_MEM_OVERFLOW_MAX 64 |
| |
| static_always_inline void |
| sanitizer_unpoison__ (u64 *restrict *shadow_ptr, size_t *shadow_len, |
| const void *ptr, size_t len) |
| { |
| size_t scale, off; |
| |
| if (PREDICT_FALSE (~0 == sanitizer_main.shadow_scale)) |
| __asan_get_shadow_mapping (&sanitizer_main.shadow_scale, |
| &sanitizer_main.shadow_offset); |
| |
| scale = sanitizer_main.shadow_scale; |
| off = sanitizer_main.shadow_offset; |
| |
| /* compute the shadow address and length */ |
| *shadow_len = len >> scale; |
| ASSERT (*shadow_len <= CLIB_MEM_OVERFLOW_MAX); |
| *shadow_ptr = (void *) (((clib_address_t) ptr >> scale) + off); |
| } |
| |
| static_always_inline CLIB_NOSANITIZE_ADDR void |
| sanitizer_unpoison_push__ (u64 *restrict shadow, const void *ptr, size_t len) |
| { |
| u64 *restrict shadow_ptr; |
| size_t shadow_len; |
| int i; |
| |
| sanitizer_unpoison__ (&shadow_ptr, &shadow_len, ptr, len); |
| |
| /* save the shadow area */ |
| for (i = 0; i < shadow_len; i++) |
| shadow[i] = shadow_ptr[i]; |
| |
| /* unpoison */ |
| for (i = 0; i < shadow_len; i++) |
| shadow_ptr[i] = 0; |
| } |
| |
| static_always_inline CLIB_NOSANITIZE_ADDR void |
| sanitizer_unpoison_pop__ (const u64 *restrict shadow, const void *ptr, |
| size_t len) |
| { |
| u64 *restrict shadow_ptr; |
| size_t shadow_len; |
| int i; |
| |
| sanitizer_unpoison__ (&shadow_ptr, &shadow_len, ptr, len); |
| |
| /* restore the shadow area */ |
| for (i = 0; i < shadow_len; i++) |
| { |
| ASSERT (0 == shadow_ptr[i]); |
| shadow_ptr[i] = shadow[i]; |
| } |
| } |
| |
| #define CLIB_MEM_OVERFLOW(f, src, n) \ |
| ({ \ |
| typeof (f) clib_mem_overflow_ret__; \ |
| const void *clib_mem_overflow_src__ = (src); \ |
| size_t clib_mem_overflow_n__ = (n); \ |
| u64 clib_mem_overflow_shadow__[CLIB_MEM_OVERFLOW_MAX]; \ |
| sanitizer_unpoison_push__ (clib_mem_overflow_shadow__, \ |
| clib_mem_overflow_src__, \ |
| clib_mem_overflow_n__); \ |
| clib_mem_overflow_ret__ = f; \ |
| sanitizer_unpoison_pop__ (clib_mem_overflow_shadow__, \ |
| clib_mem_overflow_src__, \ |
| clib_mem_overflow_n__); \ |
| clib_mem_overflow_ret__; \ |
| }) |
| |
| #define CLIB_MEM_OVERFLOW_LOAD(f, src) \ |
| ({ \ |
| typeof(src) clib_mem_overflow_load_src__ = (src); \ |
| CLIB_MEM_OVERFLOW(f(clib_mem_overflow_load_src__), clib_mem_overflow_load_src__, sizeof(typeof(f(clib_mem_overflow_load_src__)))); \ |
| }) |
| |
| static_always_inline void |
| CLIB_MEM_POISON_LEN (void *src, size_t oldlen, size_t newlen) |
| { |
| if (oldlen > newlen) |
| CLIB_MEM_POISON (src + newlen, oldlen - newlen); |
| else if (newlen > oldlen) |
| CLIB_MEM_UNPOISON (src + oldlen, newlen - oldlen); |
| } |
| |
| #else /* CLIB_SANITIZE_ADDR */ |
| |
| #define CLIB_NOSANITIZE_ADDR |
| #define CLIB_MEM_POISON(a, s) (void)(a) |
| #define CLIB_MEM_UNPOISON(a, s) (void)(a) |
| #define CLIB_MEM_OVERFLOW(a, b, c) a |
| #define CLIB_MEM_OVERFLOW_LOAD(f, src) f(src) |
| #define CLIB_MEM_POISON_LEN(a, b, c) |
| |
| #endif /* CLIB_SANITIZE_ADDR */ |
| |
| /* |
| * clang tends to force alignment of all sections when compiling for address |
| * sanitizer. This confuse VPP plugin infra, prevent clang to do that |
| * On the contrary, GCC does not support this kind of attribute on sections |
| * sigh. |
| */ |
| #ifdef __clang__ |
| #define CLIB_NOSANITIZE_PLUGIN_REG_SECTION CLIB_NOSANITIZE_ADDR |
| #else |
| #define CLIB_NOSANITIZE_PLUGIN_REG_SECTION |
| #endif |
| |
| #endif /* _included_clib_sanitizer_h */ |
| |
| /* |
| * fd.io coding-style-patch-verification: ON |
| * |
| * Local Variables: |
| * eval: (c-set-style "gnu") |
| * End: |
| */ |