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#pragma GCC diagnostic ignored "-Wmissing-prototypes"
18
19#define is_aligned(value, align) (((value) & ((align) - 1)) == 0)
20
21typedef struct {
22 const char *filename;
23 uint32_t line;
24 uint32_t column;
25} source_location_t;
26
27#define ubsan_panic(loc, fmt, ...) \
28 do { \
29 char _ubsan_msg[CRASH_MSG_MAX]; \
30 snprintf(_ubsan_msg, sizeof(_ubsan_msg), fmt, ##__VA_ARGS__); \
31 const source_location_t *_sloc = (const source_location_t *) (loc); \
32 crash_full(&(struct crash_context){ \
33 .source = CRASH_SOURCE_UBSAN, \
34 .formats = CRASH_FMT_DEFAULT, \
35 .file = (_sloc && _sloc->filename) ? _sloc->filename : __FILE__, \
36 .line = _sloc ? (int) _sloc->line : __LINE__, \
37 .func = __func__, \
38 .msg = _ubsan_msg, \
39 }); \
40 } while (0)
41
42#define HALT ubsan_panic(NULL, "UBSAN violation asserted");
43
44typedef struct {
45 uint16_t kind;
46 uint16_t info;
47 char name[];
48} type_descriptor_t;
49
50typedef struct {
51 source_location_t location;
52} data_only_location_t;
53
54typedef struct {
55 source_location_t location;
56 type_descriptor_t *type;
57} data_location_type_t;
58
59typedef struct {
60 source_location_t location;
61 type_descriptor_t *type;
62} data_load_invalid_value_t;
63
64typedef struct {
65 source_location_t location;
66 source_location_t attr_location;
67 int arg_index;
68} data_nonnull_arg_t;
69
70typedef struct {
71 source_location_t location;
72 type_descriptor_t *lhs_type;
73 type_descriptor_t *rhs_type;
74} data_shift_out_of_bounds_t;
75
76typedef struct {
77 source_location_t location;
78 type_descriptor_t *array_type;
79 type_descriptor_t *index_type;
80} data_out_of_bounds_t;
81
82typedef struct {
83 source_location_t location;
84 type_descriptor_t *type;
85 uint8_t alignment;
86 uint8_t type_check_kind;
87} data_type_mismatch_t;
88
89typedef struct {
90 source_location_t location;
91 source_location_t assumption_location;
92 type_descriptor_t *type;
93} data_alignment_assumption_t;
94
95typedef struct {
96 source_location_t location;
97 type_descriptor_t *from_type;
98 type_descriptor_t *to_type;
99 uint8_t kind;
100} data_implicit_conversion_t;
101
102typedef struct {
103 source_location_t location;
104 uint8_t kind;
105} data_invalid_builtin_t;
106struct ubsan_function_type_mismatch_data {
107 source_location_t location;
108 struct type_descriptor_t *type;
109};
110static const char *kind_to_type(uint16_t kind) {
111 const char *type;
112 switch (kind) {
113 case 0: type = "integer"; break;
114 case 1: type = "float"; break;
115 default: type = "unknown"; break;
116 }
117 return type;
118}
119
120static unsigned int info_to_bits(uint16_t info) {
121 return 1 << (info >> 1);
122}
123void __ubsan_handle_load_invalid_value(data_load_invalid_value_t *data,
124 uintptr_t value) {
125 printf(format: "UBSAN: load_invalid_value @ %s:%u:%u {value: %#lx}\n",
126 data->location.filename, data->location.line, data->location.column,
127 value);
128 HALT
129}
130void __ubsan_handle_nonnull_arg(data_nonnull_arg_t *data) {
131 printf(format: "UBSAN: handle_nonnull_arg @ %s:%u:%u {arg_index: %i}\n",
132 data->location.filename, data->location.line, data->location.column,
133 data->arg_index);
134 HALT
135}
136void __ubsan_handle_nullability_arg(data_nonnull_arg_t *data) {
137 printf(format: "UBSAN: nullability_arg @ %s:%u:%u {arg_index: %i}\n",
138 data->location.filename, data->location.line, data->location.column,
139 data->arg_index);
140 HALT
141}
142void __ubsan_handle_nonnull_return_v1(data_only_location_t *data cc_unused,
143 source_location_t *location) {
144 printf(format: "UBSAN: nonnull_return @ %s:%u:%u\n", location->filename,
145 location->line, location->column);
146 HALT
147}
148void __ubsan_handle_nullability_return_v1(data_only_location_t *data cc_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 (callee: %p)\n",
195 data->location.filename, data->location.line, data->location.column,
196 value_raw);
197 HALT
198}
199void __ubsan_handle_divrem_overflow(data_location_type_t *data, uintptr_t lhs,
200 uintptr_t rhs) {
201 printf(format: "UBSAN: divrem_overflow @ %s:%u:%u {lhs: %#lx, rhs: %#lx, type: "
202 "%u-bit %s %s}\n",
203 data->location.filename, data->location.line, data->location.column,
204 lhs, rhs, info_to_bits(info: data->type->info),
205 kind_to_type(kind: data->type->kind), data->type->name);
206 HALT
207}
208void __ubsan_handle_negate_overflow(data_location_type_t *data, uintptr_t old) {
209 printf(
210 format: "UBSAN: negate_overflow @ %s:%u:%u {old: %#lx, type: %u-bit %s %s}\n",
211 data->location.filename, data->location.line, data->location.column,
212 old, info_to_bits(info: data->type->info), kind_to_type(kind: data->type->kind),
213 data->type->name);
214 HALT
215}
216void __ubsan_handle_shift_out_of_bounds(data_shift_out_of_bounds_t *data,
217 uintptr_t lhs, uintptr_t rhs) {
218 printf(format: "UBSAN: shift_out_of_bounds @ %s:%u:%u {lhs: %#lx, rhs: %#lx, "
219 "rhs_type: %u-bit %s %s, lhs_type: %u-bit %s %s}\n",
220 data->location.filename, data->location.line, data->location.column,
221 lhs, rhs, info_to_bits(info: data->rhs_type->info),
222 kind_to_type(kind: data->rhs_type->kind), data->rhs_type->name,
223 info_to_bits(info: data->lhs_type->info),
224 kind_to_type(kind: data->lhs_type->kind), data->lhs_type->name);
225 HALT
226}
227void __ubsan_handle_out_of_bounds(data_out_of_bounds_t *data, uint64_t index) {
228 printf(
229 format: "UBSAN: out_of_bounds @ %s:%u:%u {index: %#lx, array_type: %u-bit %s "
230 "%s, index_type: %u-bit %s %s}\n",
231 data->location.filename, data->location.line, data->location.column,
232 index, info_to_bits(info: data->array_type->info),
233 kind_to_type(kind: data->array_type->kind), data->array_type->name,
234 info_to_bits(info: data->index_type->info),
235 kind_to_type(kind: data->index_type->kind), data->index_type->name);
236 HALT
237}
238
239void __ubsan_handle_type_mismatch(data_type_mismatch_t *data, void *pointer) {
240 static const char *kind_strs[] = {"load of",
241 "store to",
242 "reference binding to",
243 "member access within",
244 "member call on",
245 "constructor call on",
246 "downcast of",
247 "downcast of",
248 "upcast of",
249 "cast to virtual base of",
250 "nonnull binding to",
251 "dynamic operation on"};
252 if (pointer == NULL) {
253 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s NULL pointer of type %s)\n",
254 data->location.filename, data->location.line,
255 data->location.column, kind_strs[data->type_check_kind],
256 data->type->name);
257 } else if (data->alignment &&
258 !is_aligned((uint64_t) pointer, data->alignment)) {
259 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s misaligned address %#lx of "
260 "type %s)\n",
261 data->location.filename, data->location.line,
262 data->location.column, kind_strs[data->type_check_kind],
263 (uintptr_t) pointer, data->type->name);
264 } else {
265 printf(
266 format: "UBSAN: type_mismatch @ %s:%u:%u (%s address %#lx not long enough "
267 "for type %s)\n",
268 data->location.filename, data->location.line, data->location.column,
269 kind_strs[data->type_check_kind], (uintptr_t) pointer,
270 data->type->name);
271 }
272 HALT
273}
274void __ubsan_handle_type_mismatch_v1(data_type_mismatch_t *data,
275 void *pointer) {
276 static const char *kind_strs[] = {"load of",
277 "store to",
278 "reference binding to",
279 "member access within",
280 "member call on",
281 "constructor call on",
282 "downcast of",
283 "downcast of",
284 "upcast of",
285 "cast to virtual base of",
286 "nonnull binding to",
287 "dynamic operation on"};
288 data->alignment = 1UL << data->alignment;
289 if (pointer == NULL) {
290 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s NULL pointer of type %s)\n",
291 data->location.filename, data->location.line,
292 data->location.column, kind_strs[data->type_check_kind],
293 data->type->name);
294 } else if (data->alignment &&
295 !is_aligned((uint64_t) pointer, data->alignment)) {
296 printf(format: "UBSAN: type_mismatch @ %s:%u:%u (%s misaligned address %#lx of "
297 "type %s)\n",
298 data->location.filename, data->location.line,
299 data->location.column, kind_strs[data->type_check_kind],
300 (uintptr_t) pointer, data->type->name);
301 } else {
302 printf(
303 format: "UBSAN: type_mismatch @ %s:%u:%u (%s address %#lx not long enough "
304 "for type %s)\n",
305 data->location.filename, data->location.line, data->location.column,
306 kind_strs[data->type_check_kind], (uintptr_t) pointer,
307 data->type->name);
308 }
309 HALT
310}
311void __ubsan_handle_alignment_assumption(data_alignment_assumption_t *data,
312 void *ptr, void *align, void *offset) {
313 cc_ignore(ptr, align, offset);
314 printf(format: "UBSAN: alignment_assumption @ %s:%u:%u\n", data->location.filename,
315 data->location.line, data->location.column);
316 HALT
317}
318void __ubsan_handle_implicit_conversion(data_implicit_conversion_t *data,
319 void *src, void *dst) {
320 cc_ignore(src, dst);
321 printf(format: "UBSAN: implicit_conversion @ %s:%u:%u\n", data->location.filename,
322 data->location.line, data->location.column);
323 HALT
324}
325void __ubsan_handle_invalid_builtin(data_invalid_builtin_t *data) {
326 printf(format: "UBSAN: invalid_builtin @ %s:%u:%u\n", data->location.filename,
327 data->location.line, data->location.column);
328 HALT
329}
330void __ubsan_handle_pointer_overflow(data_only_location_t *data, void *base,
331 void *result) {
332 cc_ignore(base, result);
333 printf(format: "UBSAN: pointer_overflow @ %s:%u:%u\n", data->location.filename,
334 data->location.line, data->location.column);
335 HALT
336}
337cc_noreturn void
338__ubsan_handle_builtin_unreachable(data_only_location_t *data) {
339 printf(format: "UBSAN: builtin_unreachable @ %s:%u:%u\n", data->location.filename,
340 data->location.line, data->location.column);
341 ubsan_panic(&data->location, "UBSAN: reached __builtin_unreachable()");
342}
343cc_noreturn void __ubsan_handle_missing_return(data_only_location_t *data) {
344 printf(format: "UBSAN: missing_return @ %s:%u:%u\n", data->location.filename,
345 data->location.line, data->location.column);
346 ubsan_panic(&data->location,
347 "UBSAN: control reached end of non-void function");
348}
349