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