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 /*
67  * When compiling with -fsanitize=undefined the compiler expects functions
68  * with the following signatures. The functions are never called directly,
69  * only when undefined behavior is detected in instrumented code.
70  */
71 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
72 				  unsigned long ptr);
73 void __ubsan_handle_add_overflow(struct overflow_data *data,
74 				  unsigned long lhs, unsigned long rhs);
75 void __ubsan_handle_sub_overflow(struct overflow_data *data,
76 				  unsigned long lhs, unsigned long rhs);
77 void __ubsan_handle_mul_overflow(struct overflow_data *data,
78 				  unsigned long lhs, unsigned long rhs);
79 void __ubsan_handle_negate_overflow(struct overflow_data *data,
80 				    unsigned long old_val);
81 void __ubsan_handle_divrem_overflow(struct overflow_data *data,
82 				    unsigned long lhs, unsigned long rhs);
83 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
84 					unsigned long lhs, unsigned long rhs);
85 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
86 				  unsigned long idx);
87 void __ubsan_handle_unreachable(struct unreachable_data *data);
88 void __ubsan_handle_missing_return(struct unreachable_data *data);
89 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
90 					   unsigned long bound);
91 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
92 				       unsigned long val);
93 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data
94 #if __GCC_VERSION < 60000
95 				, size_t arg_no
96 #endif
97 			       );
98 
print_loc(const char * func,struct source_location * loc)99 static void print_loc(const char *func, struct source_location *loc)
100 {
101 	const char *f = func;
102 	const char func_prefix[] = "__ubsan_handle";
103 
104 	if (!memcmp(f, func_prefix, sizeof(func_prefix) - 1))
105 		f += sizeof(func_prefix);
106 
107 	EMSG_RAW("Undefined behavior %s at %s:%" PRIu32 " col %" PRIu32,
108 		 f, loc->file_name, loc->line, loc->column);
109 }
110 
111 
112 static volatile bool ubsan_panic = true;
113 
__ubsan_handle_type_mismatch(struct type_mismatch_data * data,unsigned long ptr __unused)114 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
115 				  unsigned long ptr __unused)
116 {
117 	print_loc(__func__, &data->loc);
118 	if (ubsan_panic)
119 		panic();
120 }
121 
__ubsan_handle_add_overflow(struct overflow_data * data,unsigned long lhs __unused,unsigned long rhs __unused)122 void __ubsan_handle_add_overflow(struct overflow_data *data,
123 				 unsigned long lhs __unused,
124 				 unsigned long rhs __unused)
125 {
126 	print_loc(__func__, &data->loc);
127 	if (ubsan_panic)
128 		panic();
129 }
130 
__ubsan_handle_sub_overflow(struct overflow_data * data,unsigned long lhs __unused,unsigned long rhs __unused)131 void __ubsan_handle_sub_overflow(struct overflow_data *data,
132 				 unsigned long lhs __unused,
133 				 unsigned long rhs __unused)
134 {
135 	print_loc(__func__, &data->loc);
136 	if (ubsan_panic)
137 		panic();
138 }
139 
__ubsan_handle_mul_overflow(struct overflow_data * data,unsigned long lhs __unused,unsigned long rhs __unused)140 void __ubsan_handle_mul_overflow(struct overflow_data *data,
141 				 unsigned long lhs __unused,
142 				 unsigned long rhs __unused)
143 {
144 	print_loc(__func__, &data->loc);
145 	if (ubsan_panic)
146 		panic();
147 }
148 
__ubsan_handle_negate_overflow(struct overflow_data * data,unsigned long old_val __unused)149 void __ubsan_handle_negate_overflow(struct overflow_data *data,
150 				    unsigned long old_val __unused)
151 {
152 	print_loc(__func__, &data->loc);
153 	if (ubsan_panic)
154 		panic();
155 }
156 
__ubsan_handle_divrem_overflow(struct overflow_data * data,unsigned long lhs __unused,unsigned long rhs __unused)157 void __ubsan_handle_divrem_overflow(struct overflow_data *data,
158 				    unsigned long lhs __unused,
159 				    unsigned long rhs __unused)
160 {
161 	print_loc(__func__, &data->loc);
162 	if (ubsan_panic)
163 		panic();
164 }
165 
__ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data * data,unsigned long lhs __unused,unsigned long rhs __unused)166 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
167 					unsigned long lhs __unused,
168 					unsigned long rhs __unused)
169 {
170 	print_loc(__func__, &data->loc);
171 	if (ubsan_panic)
172 		panic();
173 }
174 
__ubsan_handle_out_of_bounds(struct out_of_bounds_data * data,unsigned long idx __unused)175 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
176 				  unsigned long idx __unused)
177 {
178 	print_loc(__func__, &data->loc);
179 	if (ubsan_panic)
180 		panic();
181 }
182 
__ubsan_handle_unreachable(struct unreachable_data * data)183 void __ubsan_handle_unreachable(struct unreachable_data *data)
184 {
185 	print_loc(__func__, &data->loc);
186 	if (ubsan_panic)
187 		panic();
188 }
189 
__ubsan_handle_missing_return(struct unreachable_data * data)190 void __noreturn __ubsan_handle_missing_return(struct unreachable_data *data)
191 {
192 	print_loc(__func__, &data->loc);
193 	panic();
194 }
195 
__ubsan_handle_vla_bound_not_positive(struct vla_bound_data * data,unsigned long bound __unused)196 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
197 					   unsigned long bound __unused)
198 {
199 	print_loc(__func__, &data->loc);
200 	if (ubsan_panic)
201 		panic();
202 }
203 
__ubsan_handle_load_invalid_value(struct invalid_value_data * data,unsigned long val __unused)204 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
205 				       unsigned long val __unused)
206 {
207 	print_loc(__func__, &data->loc);
208 	if (ubsan_panic)
209 		panic();
210 }
211 
__ubsan_handle_nonnull_arg(struct nonnull_arg_data * data,size_t arg_no __unused)212 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data
213 #if __GCC_VERSION < 60000
214 				, size_t arg_no __unused
215 #endif
216 			       )
217 {
218 	print_loc(__func__, &data->loc);
219 	if (ubsan_panic)
220 		panic();
221 }
222