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