1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2016, Linaro Limited
4 */
5
6 #include <compiler.h>
7 #include <kernel/panic.h>
8 #include <string.h>
9 #include <trace.h>
10 #include <types_ext.h>
11
12 struct source_location {
13 const char *file_name;
14 uint32_t line;
15 uint32_t column;
16 };
17
18 struct type_descriptor {
19 uint16_t type_kind;
20 uint16_t type_info;
21 char type_name[1];
22 };
23
24 struct type_mismatch_data {
25 struct source_location loc;
26 struct type_descriptor *type;
27 unsigned long alignment;
28 unsigned char type_check_kind;
29 };
30
31 struct overflow_data {
32 struct source_location loc;
33 struct type_descriptor *type;
34 };
35
36 struct shift_out_of_bounds_data {
37 struct source_location loc;
38 struct type_descriptor *lhs_type;
39 struct type_descriptor *rhs_type;
40 };
41
42 struct out_of_bounds_data {
43 struct source_location loc;
44 struct type_descriptor *array_type;
45 struct type_descriptor *index_type;
46 };
47
48 struct unreachable_data {
49 struct source_location loc;
50 };
51
52 struct vla_bound_data {
53 struct source_location loc;
54 struct type_descriptor *type;
55 };
56
57 struct invalid_value_data {
58 struct source_location loc;
59 struct type_descriptor *type;
60 };
61
62 struct nonnull_arg_data {
63 struct source_location loc;
64 };
65
66 struct invalid_builtin_data {
67 struct source_location loc;
68 unsigned char kind;
69 };
70
71 /*
72 * When compiling with -fsanitize=undefined the compiler expects functions
73 * with the following signatures. The functions are never called directly,
74 * only when undefined behavior is detected in instrumented code.
75 */
76 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
77 unsigned long ptr);
78 void __ubsan_handle_type_mismatch_v1(void *data_, void *ptr);
79 void __ubsan_handle_add_overflow(void *data_, void *lhs, void *rhs);
80 void __ubsan_handle_sub_overflow(void *data_, void *lhs, void *rhs);
81 void __ubsan_handle_mul_overflow(void *data_, void *lhs, void *rhs);
82 void __ubsan_handle_negate_overflow(void *data_, void *old_val);
83 void __ubsan_handle_divrem_overflow(void *data_, void *lhs, void *rhs);
84 void __ubsan_handle_pointer_overflow(void *data_, void *lhs, void *rhs);
85 void __ubsan_handle_shift_out_of_bounds(void *data_, void *lhs, void *rhs);
86 void __ubsan_handle_out_of_bounds(void *data_, void *idx);
87 void __ubsan_handle_builtin_unreachable(void *data_);
88 void __ubsan_handle_missing_return(void *data_);
89 void __ubsan_handle_vla_bound_not_positive(void *data_, void *bound);
90 void __ubsan_handle_load_invalid_value(void *data_, void *val);
91 void __ubsan_handle_nonnull_arg(void *data_
92 #if __GCC_VERSION < 60000
93 , size_t arg_no
94 #endif
95 );
96 void __ubsan_handle_invalid_builtin(void *data_);
97
98 static bool ubsan_panic = true;
99
ubsan_handle_error(const char * func,struct source_location * loc,bool should_panic)100 static void ubsan_handle_error(const char *func, struct source_location *loc,
101 bool should_panic)
102 {
103 const char *f = func;
104 const char func_prefix[] = "__ubsan_handle";
105
106 if (!memcmp(f, func_prefix, sizeof(func_prefix) - 1))
107 f += sizeof(func_prefix);
108
109 EMSG_RAW("Undefined behavior %s at %s:%" PRIu32 " col %" PRIu32,
110 f, loc->file_name, loc->line, loc->column);
111
112 if (should_panic)
113 panic();
114 }
115
__ubsan_handle_type_mismatch(struct type_mismatch_data * data,unsigned long ptr __unused)116 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
117 unsigned long ptr __unused)
118 {
119 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
120 }
121
__ubsan_handle_type_mismatch_v1(void * data_,void * ptr __unused)122 void __ubsan_handle_type_mismatch_v1(void *data_, void *ptr __unused)
123 {
124 struct type_mismatch_data *data = data_;
125
126 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
127 }
128
__ubsan_handle_add_overflow(void * data_,void * lhs __unused,void * rhs __unused)129 void __ubsan_handle_add_overflow(void *data_, void *lhs __unused,
130 void *rhs __unused)
131 {
132 struct overflow_data *data = data_;
133
134 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
135 }
136
__ubsan_handle_sub_overflow(void * data_,void * lhs __unused,void * rhs __unused)137 void __ubsan_handle_sub_overflow(void *data_, void *lhs __unused,
138 void *rhs __unused)
139 {
140 struct overflow_data *data = data_;
141
142 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
143 }
144
__ubsan_handle_mul_overflow(void * data_,void * lhs __unused,void * rhs __unused)145 void __ubsan_handle_mul_overflow(void *data_, void *lhs __unused,
146 void *rhs __unused)
147 {
148 struct overflow_data *data = data_;
149
150 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
151 }
152
__ubsan_handle_negate_overflow(void * data_,void * old_val __unused)153 void __ubsan_handle_negate_overflow(void *data_, void *old_val __unused)
154 {
155 struct overflow_data *data = data_;
156
157 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
158 }
159
__ubsan_handle_divrem_overflow(void * data_,void * lhs __unused,void * rhs __unused)160 void __ubsan_handle_divrem_overflow(void *data_, void *lhs __unused,
161 void *rhs __unused)
162 {
163 struct overflow_data *data = data_;
164
165 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
166 }
167
__ubsan_handle_pointer_overflow(void * data_,void * lhs __unused,void * rhs __unused)168 void __ubsan_handle_pointer_overflow(void *data_, void *lhs __unused,
169 void *rhs __unused)
170 {
171 struct overflow_data *data = data_;
172
173 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
174 }
175
__ubsan_handle_shift_out_of_bounds(void * data_,void * lhs __unused,void * rhs __unused)176 void __ubsan_handle_shift_out_of_bounds(void *data_, void *lhs __unused,
177 void *rhs __unused)
178 {
179 struct shift_out_of_bounds_data *data = data_;
180
181 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
182 }
183
__ubsan_handle_out_of_bounds(void * data_,void * idx __unused)184 void __ubsan_handle_out_of_bounds(void *data_, void *idx __unused)
185 {
186 struct out_of_bounds_data *data = data_;
187
188 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
189 }
190
__ubsan_handle_builtin_unreachable(void * data_)191 void __ubsan_handle_builtin_unreachable(void *data_)
192 {
193 struct unreachable_data *data = data_;
194
195 ubsan_handle_error(__func__, &data->loc, false);
196 panic();
197 }
198
__ubsan_handle_missing_return(void * data_)199 void __noreturn __ubsan_handle_missing_return(void *data_)
200 {
201 struct unreachable_data *data = data_;
202
203 ubsan_handle_error(__func__, &data->loc, false);
204 panic();
205 }
206
__ubsan_handle_vla_bound_not_positive(void * data_,void * bound __unused)207 void __ubsan_handle_vla_bound_not_positive(void *data_, void *bound __unused)
208 {
209 struct vla_bound_data *data = data_;
210
211 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
212 }
213
__ubsan_handle_load_invalid_value(void * data_,void * val __unused)214 void __ubsan_handle_load_invalid_value(void *data_, void *val __unused)
215 {
216 struct invalid_value_data *data = data_;
217
218 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
219 }
220
__ubsan_handle_nonnull_arg(void * data_,size_t arg_no __unused)221 void __ubsan_handle_nonnull_arg(void *data_
222 #if __GCC_VERSION < 60000
223 , size_t arg_no __unused
224 #endif
225 )
226 {
227 struct nonnull_arg_data *data = data_;
228
229 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
230 }
231
__ubsan_handle_invalid_builtin(void * data_)232 void __ubsan_handle_invalid_builtin(void *data_)
233 {
234 struct invalid_builtin_data *data = data_;
235
236 ubsan_handle_error(__func__, &data->loc, ubsan_panic);
237 }
238