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