1//
2//
3//
4// Source:
5// https://github.com/rayanmargham/NyauxKC/blob/master/kernel/src/mem/sanitizers/UBsan/ubsan.c
6//
7// Thank you Nyaux!
8//
9//
10
11#include <console/crash.h>
12#include <console/panic.h>
13#include <console/printf.h>
14#include <stdint.h>
15#include <string.h>
16
17#define is_aligned(value, align) (((value) & ((align) - 1)) == 0)
18
19typedef struct {
20 const char *filename;
21 uint32_t line;
22 uint32_t column;
23} source_location_t;
24
25#define ubsan_panic(loc, fmt, ...) \
26 do { \
27 char _ubsan_msg[CRASH_MSG_MAX]; \
28 snprintf(_ubsan_msg, sizeof(_ubsan_msg), fmt, ##__VA_ARGS__); \
29 const source_location_t *_sloc = (const source_location_t *) (loc); \
30 crash_full(&(struct crash_context){ \
31 .source = CRASH_SOURCE_UBSAN, \
32 .formats = CRASH_FMT_DEFAULT, \
33 .file = (_sloc && _sloc->filename) ? _sloc->filename : __FILE__, \
34 .line = _sloc ? (int) _sloc->line : __LINE__, \
35 .func = __func__, \
36 .msg = _ubsan_msg, \
37 }); \
38 } while (0)
39
40#define HALT ubsan_panic(NULL, "UBSAN violation asserted");
41
42typedef struct {
43 uint16_t kind;
44 uint16_t info;
45 char name[];
46} type_descriptor_t;
47
48typedef struct {
49 source_location_t location;
50} data_only_location_t;
51
52typedef struct {
53 source_location_t location;
54 type_descriptor_t *type;
55} data_location_type_t;
56
57typedef struct {
58 source_location_t location;
59 type_descriptor_t *type;
60} data_load_invalid_value_t;
61
62typedef struct {
63 source_location_t location;
64 source_location_t attr_location;
65 int arg_index;
66} data_nonnull_arg_t;
67
68typedef struct {
69 source_location_t location;
70 type_descriptor_t *lhs_type;
71 type_descriptor_t *rhs_type;
72} data_shift_out_of_bounds_t;
73
74typedef struct {
75 source_location_t location;
76 type_descriptor_t *array_type;
77 type_descriptor_t *index_type;
78} data_out_of_bounds_t;
79
80typedef struct {
81 source_location_t location;
82 type_descriptor_t *type;
83 uint8_t alignment;
84 uint8_t type_check_kind;
85} data_type_mismatch_t;
86
87typedef struct {
88 source_location_t location;
89 source_location_t assumption_location;
90 type_descriptor_t *type;
91} data_alignment_assumption_t;
92
93typedef struct {
94 source_location_t location;
95 type_descriptor_t *from_type;
96 type_descriptor_t *to_type;
97 uint8_t kind;
98} data_implicit_conversion_t;
99
100typedef struct {
101 source_location_t location;
102 uint8_t kind;
103} data_invalid_builtin_t;
104struct ubsan_function_type_mismatch_data {
105 source_location_t location;
106 struct type_descriptor_t *type;
107};
108const char *kind_to_type(uint16_t kind) {
109 const char *type;
110 switch (kind) {
111 case 0: type = "integer"; break;
112 case 1: type = "float"; break;
113 default: type = "unknown"; break;
114 }
115 return type;
116}
117
118unsigned int info_to_bits(uint16_t info) {
119 return 1 << (info >> 1);
120}
121void __ubsan_handle_load_invalid_value(data_load_invalid_value_t *data,
122 uintptr_t value) {
123 printf(format: "UBSAN: load_invalid_value @ %s:%u:%u {value: %#lx}\n",
124 data->location.filename, data->location.line, data->location.column,
125 value);
126 HALT
127}
128void __ubsan_handle_nonnull_arg(data_nonnull_arg_t *data) {
129 printf(format: "UBSAN: handle_nonnull_arg @ %s:%u:%u {arg_index: %i}\n",
130 data->location.filename, data->location.line, data->location.column,
131 data->arg_index);
132 HALT
133}
134void __ubsan_handle_nullability_arg(data_nonnull_arg_t *data) {
135 printf(format: "UBSAN: nullability_arg @ %s:%u:%u {arg_index: %i}\n",
136 data->location.filename, data->location.line, data->location.column,
137 data->arg_index);
138 HALT
139}
140void __ubsan_handle_nonnull_return_v1(data_only_location_t *data
141 [[maybe_unused]],
142 source_location_t *location) {
143 printf(format: "UBSAN: nonnull_return @ %s:%u:%u\n", location->filename,
144 location->line, location->column);
145 HALT
146}
147void __ubsan_handle_nullability_return_v1(data_only_location_t *data
148 [[maybe_unused]],
149 source_location_t *location) {
150 printf(format: "UBSAN: nullability_return @ %s:%u:%u\n", location->filename,
151 location->line, location->column);
152 HALT
153}
154void __ubsan_handle_vla_bound_not_positive(data_location_type_t *data,
155 uintptr_t bound) {
156 printf(
157 format: "UBSAN: vla_bound_not_positive @ %s:%u:%u {bound: %#lx, type: %u-bit "
158 "%s %s}\n",
159 data->location.filename, data->location.line, data->location.column,
160 bound, info_to_bits(info: data->type->info), kind_to_type(kind: data->type->kind),
161 data->type->name);
162 HALT
163}
164void __ubsan_handle_add_overflow(data_location_type_t *data, uintptr_t lhs,
165 uintptr_t rhs) {
166 printf(format: "UBSAN: add_overflow @ %s:%u:%u {lhs: %#lx, rhs: %#lx, type: %u-bit "
167 "%s %s}\n",
168 data->location.filename, data->location.line, data->location.column,
169 lhs, rhs, info_to_bits(info: data->type->info),
170 kind_to_type(kind: data->type->kind), data->type->name);
171 HALT
172}
173void __ubsan_handle_sub_overflow(data_location_type_t *data, uintptr_t lhs,
174 uintptr_t rhs) {
175 printf(format: "UBSAN: sub_overflow @ %s:%u:%u {lhs: %#lx, rhs: %#lx, type: %u-bit "
176 "%s %s}\n",
177 data->location.filename, data->location.line, data->location.column,
178 lhs, rhs, info_to_bits(info: data->type->info),
179 kind_to_type(kind: data->type->kind), data->type->name);
180 HALT
181}
182void __ubsan_handle_mul_overflow(data_location_type_t *data, uintptr_t lhs,
183 uintptr_t rhs) {
184 printf(format: "UBSAN: mul_overflow @ %s:%u:%u {lhs: %#lx, rhs: %#lx, type: %u-bit "
185 "%s %s}\n",
186 data->location.filename, data->location.line, data->location.column,
187 lhs, rhs, info_to_bits(info: data->type->info),
188 kind_to_type(kind: data->type->kind), data->type->name);
189 HALT
190}
191void __ubsan_handle_function_type_mismatch(void *data_raw, void *value_raw) {
192 struct ubsan_function_type_mismatch_data *data =
193 (struct ubsan_function_type_mismatch_data *) data_raw;
194 printf(format: "UBSAN: function type mismatch @ %s:%u:%u", data->location.filename,
195 data->location.line, data->location.column);
196 HALT
197}
198void __ubsan_handle_divrem_overflow(data_location_type_t *data, uintptr_t lhs,
199 uintptr_t rhs) {
200 printf(format: "UBSAN: divrem_overflow @ %s:%u:%u {lhs: %#lx, rhs: %#lx, type: "
201 "%u-bit %s %s}\n",
202 data->location.filename, data->location.line, data->location.column,
203 lhs, rhs, info_to_bits(info: data->type->info),
204 kind_to_type(kind: data->type->kind), data->type->name);
205 HALT
206}
207void __ubsan_handle_negate_overflow(data_location_type_t *data, uintptr_t old) {
208 printf(
209 format: "UBSAN: negate_overflow @ %s:%u:%u {old: %#lx, type: %u-bit %s %s}\n",
210 data->location.filename, data->location.line, data->location.column,
211 old, info_to_bits(info: data->type->info), kind_to_type(kind: data->type->kind),
212 data->type->name);
213 HALT
214}
215void __ubsan_handle_shift_out_of_bounds(data_shift_out_of_bounds_t *data,
216 uintptr_t lhs, uintptr_t rhs) {
217 printf(format: "UBSAN: shift_out_of_bounds @ %s:%u:%u {lhs: %#lx, rhs: %#lx, "
218 "rhs_type: %u-bit %s %s, lhs_type: %u-bit %s %s}\n",
219 data->location.filename, data->location.line, data->location.column,
220 lhs, rhs, info_to_bits(info: data->rhs_type->info),
221 kind_to_type(kind: data->rhs_type->kind), data->rhs_type->name,
222 info_to_bits(info: data->lhs_type->info),
223 kind_to_type(kind: data->lhs_type->kind), data->lhs_type->name);
224 HALT
225}
226void __ubsan_handle_out_of_bounds(data_out_of_bounds_t *data, uint64_t index) {
227 printf(
228 format: "UBSAN: out_of_bounds @ %s:%u:%u {index: %#lx, array_type: %u-bit %s "
229 "%s, index_type: %u-bit %s %s}\n",
230 data->location.filename, data->location.line, data->location.column,
231 index, info_to_bits(info: data->array_type->info),
232 kind_to_type(kind: data->array_type->kind), data->array_type->name,
233 info_to_bits(info: data->index_type->info),
234 kind_to_type(kind: data->index_type->kind), data->index_type->name);
235 HALT
236}
237
238void __ubsan_handle_type_mismatch(data_type_mismatch_t *data, void *pointer) {
239 static const char *kind_strs[] = {"load of",
240 "store to",
241 "reference binding to",
242 "member access within",
243 "member call on",
244 "constructor call on",
245 "downcast of",
246 "downcast of",
247 "upcast of",
248 "cast to virtual base of",
249 "nonnull binding to",
250 "dynamic operation on"};
251 if (pointer == NULL) {
252 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s NULL pointer of type %s)\n",
253 data->location.filename, data->location.line,
254 data->location.column, kind_strs[data->type_check_kind],
255 data->type->name);
256 } else if (data->alignment &&
257 !is_aligned((uint64_t) pointer, data->alignment)) {
258 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s misaligned address %#lx of "
259 "type %s)\n",
260 data->location.filename, data->location.line,
261 data->location.column, kind_strs[data->type_check_kind],
262 (uintptr_t) pointer, data->type->name);
263 } else {
264 printf(
265 format: "UBSAN: type_mismatch @ %s:%u:%u (%s address %#lx not long enough "
266 "for type %s)\n",
267 data->location.filename, data->location.line, data->location.column,
268 kind_strs[data->type_check_kind], (uintptr_t) pointer,
269 data->type->name);
270 }
271 HALT
272}
273void __ubsan_handle_type_mismatch_v1(data_type_mismatch_t *data,
274 void *pointer) {
275 static const char *kind_strs[] = {"load of",
276 "store to",
277 "reference binding to",
278 "member access within",
279 "member call on",
280 "constructor call on",
281 "downcast of",
282 "downcast of",
283 "upcast of",
284 "cast to virtual base of",
285 "nonnull binding to",
286 "dynamic operation on"};
287 data->alignment = 1UL << data->alignment;
288 if (pointer == NULL) {
289 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s NULL pointer of type %s)\n",
290 data->location.filename, data->location.line,
291 data->location.column, kind_strs[data->type_check_kind],
292 data->type->name);
293 } else if (data->alignment &&
294 !is_aligned((uint64_t) pointer, data->alignment)) {
295 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s misaligned address %#lx of "
296 "type %s)\n",
297 data->location.filename, data->location.line,
298 data->location.column, kind_strs[data->type_check_kind],
299 (uintptr_t) pointer, data->type->name);
300 } else {
301 printf(
302 format: "UBSAN: type_mismatch @ %s:%u:%u (%s address %#lx not long enough "
303 "for type %s)\n",
304 data->location.filename, data->location.line, data->location.column,
305 kind_strs[data->type_check_kind], (uintptr_t) pointer,
306 data->type->name);
307 }
308 HALT
309}
310void __ubsan_handle_alignment_assumption(data_alignment_assumption_t *data,
311 void *, void *, void *) {
312 printf(format: "UBSAN: alignment_assumption @ %s:%u:%u\n", data->location.filename,
313 data->location.line, data->location.column);
314 HALT
315}
316void __ubsan_handle_implicit_conversion(data_implicit_conversion_t *data,
317 void *, void *) {
318 printf(format: "UBSAN: implicit_conversion @ %s:%u:%u\n", data->location.filename,
319 data->location.line, data->location.column);
320 HALT
321}
322void __ubsan_handle_invalid_builtin(data_invalid_builtin_t *data) {
323 printf(format: "UBSAN: invalid_builtin @ %s:%u:%u\n", data->location.filename,
324 data->location.line, data->location.column);
325 HALT
326}
327void __ubsan_handle_pointer_overflow(data_only_location_t *data, void *,
328 void *) {
329 printf(format: "UBSAN: pointer_overflow @ %s:%u:%u\n", data->location.filename,
330 data->location.line, data->location.column);
331 HALT
332}
333__attribute__((noreturn)) void
334__ubsan_handle_builtin_unreachable(data_only_location_t *data) {
335 printf(format: "UBSAN: builtin_unreachable @ %s:%u:%u\n", data->location.filename,
336 data->location.line, data->location.column);
337 ubsan_panic(&data->location, "UBSAN: reached __builtin_unreachable()");
338}
339__attribute__((noreturn)) void
340__ubsan_handle_missing_return(data_only_location_t *data) {
341 printf(format: "UBSAN: missing_return @ %s:%u:%u\n", data->location.filename,
342 data->location.line, data->location.column);
343 ubsan_panic(&data->location,
344 "UBSAN: control reached end of non-void function");
345}
346