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