tap: fix the coverity warning
[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_PUSH(src, n)                                        \
80   do                                                                          \
81     {                                                                         \
82       const void *clib_mem_overflow_src__ = (src);                            \
83       size_t clib_mem_overflow_n__ = (n);                                     \
84       u64 clib_mem_overflow_shadow__;                                         \
85       sanitizer_unpoison_push__ (&clib_mem_overflow_shadow__,                 \
86                                  clib_mem_overflow_src__,                     \
87                                  clib_mem_overflow_n__)
88
89 #define CLIB_MEM_OVERFLOW_POP()                                               \
90   sanitizer_unpoison_pop__ (&clib_mem_overflow_shadow__,                      \
91                             clib_mem_overflow_src__, clib_mem_overflow_n__);  \
92   }                                                                           \
93   while (0)
94
95 #define CLIB_MEM_OVERFLOW_LOAD(src)                                           \
96   ({                                                                          \
97     typeof (*(src)) *clib_mem_overflow_load_src__ = (src),                    \
98                     clib_mem_overflow_load_ret__;                             \
99     CLIB_MEM_OVERFLOW_PUSH (clib_mem_overflow_load_src__,                     \
100                             sizeof (*clib_mem_overflow_load_src__));          \
101     clib_mem_overflow_load_ret__ = *clib_mem_overflow_load_src__;             \
102     CLIB_MEM_OVERFLOW_POP ();                                                 \
103     clib_mem_overflow_load_ret__;                                             \
104   })
105
106 static_always_inline void
107 CLIB_MEM_POISON_LEN (void *src, size_t oldlen, size_t newlen)
108 {
109   if (oldlen > newlen)
110     CLIB_MEM_POISON (src + newlen, oldlen - newlen);
111   else if (newlen > oldlen)
112     CLIB_MEM_UNPOISON (src + oldlen, newlen - oldlen);
113 }
114
115 #else /* CLIB_SANITIZE_ADDR */
116
117 #define CLIB_NOSANITIZE_ADDR
118 #define CLIB_MEM_POISON(a, s)                   (void)(a)
119 #define CLIB_MEM_UNPOISON(a, s)                 (void)(a)
120 #define CLIB_MEM_OVERFLOW_PUSH(a, b)            (void) (a)
121 #define CLIB_MEM_OVERFLOW_POP()
122 #define CLIB_MEM_OVERFLOW_LOAD(src) (*(src))
123 #define CLIB_MEM_POISON_LEN(a, b, c)
124
125 #endif /* CLIB_SANITIZE_ADDR */
126
127 /*
128  * clang tends to force alignment of all sections when compiling for address
129  * sanitizer. This confuse VPP plugin infra, prevent clang to do that
130  * On the contrary, GCC does not support this kind of attribute on sections
131  * sigh.
132  */
133 #ifdef __clang__
134 #define CLIB_NOSANITIZE_PLUGIN_REG_SECTION      CLIB_NOSANITIZE_ADDR
135 #else
136 #define CLIB_NOSANITIZE_PLUGIN_REG_SECTION
137 #endif
138
139 #endif /* _included_clib_sanitizer_h */
140
141 /*
142  * fd.io coding-style-patch-verification: ON
143  *
144  * Local Variables:
145  * eval: (c-set-style "gnu")
146  * End:
147  */