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