1 // Copyright (c) 2016, Linaro Limited
2 // Modified for HelenOS use by Jiří Zárevúcky.
3 // Adaptations for ESP-IDF Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26 
27 #include <stdbool.h>
28 #include <inttypes.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include "esp_system.h"
34 #include "esp_rom_sys.h"
35 #include "hal/cpu_hal.h"
36 
37 
38 struct source_location {
39     const char *file_name;
40     uint32_t line;
41     uint32_t column;
42 };
43 
44 struct type_descriptor {
45     uint16_t type_kind;
46     uint16_t type_info;
47     char type_name[];
48 };
49 
50 struct type_mismatch_data {
51     struct source_location loc;
52     struct type_descriptor *type;
53     unsigned long alignment;
54     unsigned char type_check_kind;
55 };
56 
57 struct type_mismatch_data_v1 {
58     struct source_location loc;
59     struct type_descriptor *type;
60     unsigned char log_alignment;
61     unsigned char type_check_kind;
62 };
63 
64 struct overflow_data {
65     struct source_location loc;
66     struct type_descriptor *type;
67 };
68 
69 struct shift_out_of_bounds_data {
70     struct source_location loc;
71     struct type_descriptor *lhs_type;
72     struct type_descriptor *rhs_type;
73 };
74 
75 struct out_of_bounds_data {
76     struct source_location loc;
77     struct type_descriptor *array_type;
78     struct type_descriptor *index_type;
79 };
80 
81 struct unreachable_data {
82     struct source_location loc;
83 };
84 
85 struct vla_bound_data {
86     struct source_location loc;
87     struct type_descriptor *type;
88 };
89 
90 struct invalid_value_data {
91     struct source_location loc;
92     struct type_descriptor *type;
93 };
94 
95 struct nonnull_arg_data {
96     struct source_location loc;
97 };
98 
99 struct nonnull_return_data {
100     struct source_location loc;
101     struct source_location attr_loc;
102 };
103 
104 struct pointer_overflow_data {
105     struct source_location loc;
106 };
107 
108 struct invalid_builtin_data {
109     struct source_location loc;
110     unsigned char kind;
111 };
112 
113 
114 static void __ubsan_default_handler(struct source_location *loc, const char *func) __attribute__((noreturn));
115 
116 /*
117  * When compiling with -fsanitize=undefined the compiler expects functions
118  * with the following signatures. The functions are never called directly,
119  * only when undefined behavior is detected in instrumented code.
120  */
121 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, unsigned long ptr);
122 void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, unsigned long ptr);
123 void __ubsan_handle_add_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
124 void __ubsan_handle_sub_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
125 void __ubsan_handle_mul_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
126 void __ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long old_val);
127 void __ubsan_handle_divrem_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
128 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data, unsigned long lhs, unsigned long rhs);
129 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, unsigned long idx);
130 void __ubsan_handle_missing_return(struct unreachable_data *data);
131 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data, unsigned long bound);
132 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data, unsigned long val);
133 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data);
134 void __ubsan_handle_nonnull_return(struct nonnull_return_data *data);
135 void __ubsan_handle_builtin_unreachable(struct unreachable_data *data);
136 void __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
137                                      unsigned long base, unsigned long result);
138 
__ubsan_maybe_debugbreak(void)139 static void __ubsan_maybe_debugbreak(void)
140 {
141     if (cpu_hal_is_debugger_attached()) {
142         cpu_hal_break();
143     }
144 }
145 
__ubsan_default_handler(struct source_location * loc,const char * func)146 static void __ubsan_default_handler(struct source_location *loc, const char *func)
147 {
148     /* Although the source location is available here, it is not printed:
149      *
150      * - We could use "snprintf", but that uses a lot of stack, and may allocate memory,
151      *   so is not safe from UBSAN handler.
152      * - Alternatively, "itoa" could be used. However itoa doesn't take the remaining
153      *   string length as as argument and is therefore unsafe (nor does it return
154      *   the number of characters written). itoa is also not present in ESP32-S2 ROM,
155      *   and would need to be placed into IRAM on that chip.
156      * - Third option is to print the message using esp_rom_printf, and not pass anything
157      *   to esp_system_abort. However we'd like to capture this information, e.g. for the
158      *   purpose of including the abort reason into core dumps.
159      *
160      * Since the source file and line number are already printed while decoding
161      * the panic backtrace, not printing the line number here seems to be an okay choice.
162      */
163     char msg[60] = {};
164     (void) strlcat(msg, "Undefined behavior of type ", sizeof(msg));
165     (void) strlcat(msg, func + strlen("__ubsan_handle_"), sizeof(msg));
166     esp_system_abort(msg);
167 }
168 
__ubsan_handle_type_mismatch(struct type_mismatch_data * data,unsigned long ptr)169 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
170                                   unsigned long ptr)
171 {
172     __ubsan_maybe_debugbreak();
173     __ubsan_default_handler(&data->loc, __func__);
174 }
175 
__ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 * data,unsigned long ptr)176 void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data,
177                                      unsigned long ptr)
178 {
179     __ubsan_maybe_debugbreak();
180     __ubsan_default_handler(&data->loc, __func__);
181 }
182 
__ubsan_handle_add_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)183 void __ubsan_handle_add_overflow(struct overflow_data *data,
184                                  unsigned long lhs,
185                                  unsigned long rhs)
186 {
187     __ubsan_maybe_debugbreak();
188     __ubsan_default_handler(&data->loc, __func__);
189 }
190 
__ubsan_handle_sub_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)191 void __ubsan_handle_sub_overflow(struct overflow_data *data,
192                                  unsigned long lhs,
193                                  unsigned long rhs)
194 {
195     __ubsan_maybe_debugbreak();
196     __ubsan_default_handler(&data->loc, __func__);
197 }
198 
__ubsan_handle_mul_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)199 void __ubsan_handle_mul_overflow(struct overflow_data *data,
200                                  unsigned long lhs,
201                                  unsigned long rhs)
202 {
203     __ubsan_maybe_debugbreak();
204     __ubsan_default_handler(&data->loc, __func__);
205 }
206 
__ubsan_handle_negate_overflow(struct overflow_data * data,unsigned long old_val)207 void __ubsan_handle_negate_overflow(struct overflow_data *data,
208                                     unsigned long old_val)
209 {
210     __ubsan_maybe_debugbreak();
211     __ubsan_default_handler(&data->loc, __func__);
212 }
213 
__ubsan_handle_divrem_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)214 void __ubsan_handle_divrem_overflow(struct overflow_data *data,
215                                     unsigned long lhs,
216                                     unsigned long rhs)
217 {
218     __ubsan_maybe_debugbreak();
219     __ubsan_default_handler(&data->loc, __func__);
220 }
221 
__ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data * data,unsigned long lhs,unsigned long rhs)222 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
223                                         unsigned long lhs,
224                                         unsigned long rhs)
225 {
226     if (rhs == 32) {
227         return;
228     }
229     __ubsan_maybe_debugbreak();
230     __ubsan_default_handler(&data->loc, __func__);
231 }
232 
__ubsan_handle_out_of_bounds(struct out_of_bounds_data * data,unsigned long idx)233 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
234                                   unsigned long idx)
235 {
236     __ubsan_maybe_debugbreak();
237     __ubsan_default_handler(&data->loc, __func__);
238 }
239 
__ubsan_handle_missing_return(struct unreachable_data * data)240 void __ubsan_handle_missing_return(struct unreachable_data *data)
241 {
242     __ubsan_maybe_debugbreak();
243     __ubsan_default_handler(&data->loc, __func__);
244 }
245 
__ubsan_handle_vla_bound_not_positive(struct vla_bound_data * data,unsigned long bound)246 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
247         unsigned long bound)
248 {
249     __ubsan_maybe_debugbreak();
250     __ubsan_default_handler(&data->loc, __func__);
251 }
252 
__ubsan_handle_load_invalid_value(struct invalid_value_data * data,unsigned long val)253 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
254                                        unsigned long val)
255 {
256     __ubsan_maybe_debugbreak();
257     __ubsan_default_handler(&data->loc, __func__);
258 }
259 
__ubsan_handle_nonnull_arg(struct nonnull_arg_data * data)260 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
261 {
262     __ubsan_maybe_debugbreak();
263     __ubsan_default_handler(&data->loc, __func__);
264 }
265 
__ubsan_handle_nonnull_return(struct nonnull_return_data * data)266 void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
267 {
268     __ubsan_maybe_debugbreak();
269     __ubsan_default_handler(&data->loc, __func__);
270 }
271 
__ubsan_handle_builtin_unreachable(struct unreachable_data * data)272 void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
273 {
274     __ubsan_maybe_debugbreak();
275     __ubsan_default_handler(&data->loc, __func__);
276 }
277 
__ubsan_handle_pointer_overflow(struct pointer_overflow_data * data,unsigned long base,unsigned long result)278 void __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
279                                      unsigned long base, unsigned long result)
280 {
281     __ubsan_maybe_debugbreak();
282     __ubsan_default_handler(&data->loc, __func__);
283 }
284 
__ubsan_handle_invalid_builtin(struct invalid_builtin_data * data)285 void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
286 {
287     __ubsan_maybe_debugbreak();
288     __ubsan_default_handler(&data->loc, __func__);
289 }
290 
291 /* Hook for the linker to include this object file */
__ubsan_include(void)292 void __ubsan_include(void)
293 {
294 }
295