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