vppinfra: asan: fix overflow support
[vpp.git] / src / vppinfra / sanitizer.h
1 #ifndef _included_clib_sanitizer_h
2 #define _included_clib_sanitizer_h
3
4 #ifdef CLIB_SANITIZE_ADDR
5
6 #include <sanitizer/asan_interface.h>
7 #include <vppinfra/clib.h>
8 #include <vppinfra/error_bootstrap.h>
9
10 typedef struct
11 {
12   size_t shadow_scale;
13   size_t shadow_offset;
14 } clib_sanitizer_main_t;
15
16 extern clib_sanitizer_main_t sanitizer_main;
17
18 #define CLIB_NOSANITIZE_ADDR    __attribute__((no_sanitize_address))
19 #define CLIB_MEM_POISON(a, s)   ASAN_POISON_MEMORY_REGION((a), (s))
20 #define CLIB_MEM_UNPOISON(a, s) ASAN_UNPOISON_MEMORY_REGION((a), (s))
21
22 #define CLIB_MEM_OVERFLOW_MAX 64
23
24 static_always_inline void
25 sanitizer_unpoison__ (u64 *restrict *shadow_ptr, size_t *shadow_len,
26                       const void *ptr, size_t len)
27 {
28   size_t scale, off;
29
30   if (PREDICT_FALSE (~0 == sanitizer_main.shadow_scale))
31     __asan_get_shadow_mapping (&sanitizer_main.shadow_scale,
32                                &sanitizer_main.shadow_offset);
33
34   scale = sanitizer_main.shadow_scale;
35   off = sanitizer_main.shadow_offset;
36
37   /* compute the shadow address and length */
38   *shadow_len = len >> scale;
39   ASSERT (*shadow_len <= CLIB_MEM_OVERFLOW_MAX);
40   *shadow_ptr = (void *) (((clib_address_t) ptr >> scale) + off);
41 }
42
43 static_always_inline CLIB_NOSANITIZE_ADDR void
44 sanitizer_unpoison_push__ (u64 *restrict shadow, const void *ptr, size_t len)
45 {
46   u64 *restrict shadow_ptr;
47   size_t shadow_len;
48   int i;
49
50   sanitizer_unpoison__ (&shadow_ptr, &shadow_len, ptr, len);
51
52   /* save the shadow area */
53   for (i = 0; i < shadow_len; i++)
54     shadow[i] = shadow_ptr[i];
55
56   /* unpoison */
57   for (i = 0; i < shadow_len; i++)
58     shadow_ptr[i] = 0;
59 }
60
61 static_always_inline CLIB_NOSANITIZE_ADDR void
62 sanitizer_unpoison_pop__ (const u64 *restrict shadow, const void *ptr,
63                           size_t len)
64 {
65   u64 *restrict shadow_ptr;
66   size_t shadow_len;
67   int i;
68
69   sanitizer_unpoison__ (&shadow_ptr, &shadow_len, ptr, len);
70
71   /* restore the shadow area */
72   for (i = 0; i < shadow_len; i++)
73     {
74       ASSERT (0 == shadow_ptr[i]);
75       shadow_ptr[i] = shadow[i];
76     }
77 }
78
79 #define CLIB_MEM_OVERFLOW(f, src, n)                                          \
80   ({                                                                          \
81     typeof (f) clib_mem_overflow_ret__;                                       \
82     const void *clib_mem_overflow_src__ = (src);                              \
83     size_t clib_mem_overflow_n__ = (n);                                       \
84     u64 clib_mem_overflow_shadow__[CLIB_MEM_OVERFLOW_MAX];                    \
85     sanitizer_unpoison_push__ (clib_mem_overflow_shadow__,                    \
86                                clib_mem_overflow_src__,                       \
87                                clib_mem_overflow_n__);                        \
88     clib_mem_overflow_ret__ = f;                                              \
89     sanitizer_unpoison_pop__ (clib_mem_overflow_shadow__,                     \
90                               clib_mem_overflow_src__,                        \
91                               clib_mem_overflow_n__);                         \
92     clib_mem_overflow_ret__;                                                  \
93   })
94
95 #define CLIB_MEM_OVERFLOW_LOAD(f, src) \
96   ({ \
97    typeof(src) clib_mem_overflow_load_src__ = (src); \
98    CLIB_MEM_OVERFLOW(f(clib_mem_overflow_load_src__), clib_mem_overflow_load_src__, sizeof(typeof(f(clib_mem_overflow_load_src__)))); \
99    })
100
101 static_always_inline void
102 CLIB_MEM_POISON_LEN (void *src, size_t oldlen, size_t newlen)
103 {
104   if (oldlen > newlen)
105     CLIB_MEM_POISON (src + newlen, oldlen - newlen);
106   else if (newlen > oldlen)
107     CLIB_MEM_UNPOISON (src + oldlen, newlen - oldlen);
108 }
109
110 #else /* CLIB_SANITIZE_ADDR */
111
112 #define CLIB_NOSANITIZE_ADDR
113 #define CLIB_MEM_POISON(a, s)                   (void)(a)
114 #define CLIB_MEM_UNPOISON(a, s)                 (void)(a)
115 #define CLIB_MEM_OVERFLOW(a, b, c)              a
116 #define CLIB_MEM_OVERFLOW_LOAD(f, src)          f(src)
117 #define CLIB_MEM_POISON_LEN(a, b, c)
118
119 #endif /* CLIB_SANITIZE_ADDR */
120
121 /*
122  * clang tends to force alignment of all sections when compiling for address
123  * sanitizer. This confuse VPP plugin infra, prevent clang to do that
124  * On the contrary, GCC does not support this kind of attribute on sections
125  * sigh.
126  */
127 #ifdef __clang__
128 #define CLIB_NOSANITIZE_PLUGIN_REG_SECTION      CLIB_NOSANITIZE_ADDR
129 #else
130 #define CLIB_NOSANITIZE_PLUGIN_REG_SECTION
131 #endif
132
133 #endif /* _included_clib_sanitizer_h */
134
135 /*
136  * fd.io coding-style-patch-verification: ON
137  *
138  * Local Variables:
139  * eval: (c-set-style "gnu")
140  * End:
141  */