1 /*
2 * Copyright (c) 2018-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <stdatomic.h>
30 #include <kern/debug.h>
31 #include <kern/assert.h>
32 #include <libkern/libkern.h>
33 #include "ubsan.h"
34
35 static const uint32_t line_acquired = 0x80000000UL;
36 static const char *get_mismatch_kind(uint8_t kind);
37
38 /*
39 * A simple JSON serializer. Character quoting is not supported.
40 */
41
42 static size_t
ubsan_buf_available(const ubsan_buf_t * ub)43 ubsan_buf_available(const ubsan_buf_t *ub)
44 {
45 assert(ub->ub_buf_size >= ub->ub_written);
46 return ub->ub_buf_size - ub->ub_written;
47 }
48
49 static void
ubsan_buf_rewind(ubsan_buf_t * ub,size_t mark)50 ubsan_buf_rewind(ubsan_buf_t *ub, size_t mark)
51 {
52 assert(mark < ub->ub_buf_size);
53 ub->ub_written = mark;
54 ub->ub_buf[ub->ub_written] = '\0';
55 }
56
57 __printflike(2, 0)
58 static void
ubsan_json_log_ap(ubsan_buf_t * ub,const char * fmt,va_list ap)59 ubsan_json_log_ap(ubsan_buf_t *ub, const char *fmt, va_list ap)
60 {
61 const size_t available = ubsan_buf_available(ub);
62
63 if (available == 0) {
64 return;
65 }
66
67 int n = vsnprintf(&ub->ub_buf[ub->ub_written], available, fmt, ap);
68 assert(n >= 0);
69
70 if (n <= available) {
71 ub->ub_written += n;
72 } else {
73 ub->ub_err = true;
74 ub->ub_written = ub->ub_buf_size;
75 }
76 }
77
78 __printflike(2, 3)
79 static void
ubsan_json_log(ubsan_buf_t * ub,const char * fmt,...)80 ubsan_json_log(ubsan_buf_t *ub, const char *fmt, ...)
81 {
82 va_list ap;
83
84 va_start(ap, fmt);
85 ubsan_json_log_ap(ub, fmt, ap);
86 va_end(ap);
87 }
88
89 static bool
ubsan_json_struct_is_empty(const ubsan_buf_t * ub)90 ubsan_json_struct_is_empty(const ubsan_buf_t *ub)
91 {
92 if (ub->ub_written == 0) {
93 return true;
94 }
95 char prev_c = ub->ub_buf[ub->ub_written - 1];
96 return prev_c == '{' || prev_c == '[';
97 }
98
99 static int64_t
signed_num(size_t bit_width,uint64_t value)100 signed_num(size_t bit_width, uint64_t value)
101 {
102 switch (bit_width / 8) {
103 case sizeof(int8_t):
104 return (int8_t)value;
105 case sizeof(int16_t):
106 return (int16_t)value;
107 case sizeof(int32_t):
108 return (int32_t)value;
109 case sizeof(int64_t):
110 return (int64_t)value;
111 default:
112 panic("Invalid bit width %lu", bit_width);
113 }
114 }
115
116 static void
ubsan_json_struct_begin(ubsan_buf_t * ub,const char * section_name,bool is_array)117 ubsan_json_struct_begin(ubsan_buf_t *ub, const char *section_name, bool is_array)
118 {
119 if (!ubsan_json_struct_is_empty(ub)) {
120 ubsan_json_log(ub, ",");
121 }
122
123 if (section_name) {
124 assert(section_name[0] != '\0');
125 ubsan_json_log(ub, "\"%s\":", section_name);
126 }
127
128 ubsan_json_log(ub, is_array ? "[" : "{");
129
130 if (ubsan_buf_available(ub) == 0 || ub->ub_err) {
131 ub->ub_err = true;
132 return;
133 }
134 ub->ub_buf_size--; // Reserve for ] or }
135 }
136
137 static void
ubsan_json_struct_end(ubsan_buf_t * ub,bool is_array)138 ubsan_json_struct_end(ubsan_buf_t *ub, bool is_array)
139 {
140 ub->ub_buf_size++; // Reserved for ] or }
141 assert(ub->ub_buf[ub->ub_written - 1] != ',');
142 ubsan_json_log(ub, is_array ? "]" : "}");
143 }
144
145 static void
ubsan_json_obj_begin(ubsan_buf_t * ub,const char * section_name)146 ubsan_json_obj_begin(ubsan_buf_t *ub, const char *section_name)
147 {
148 ubsan_json_struct_begin(ub, section_name, false);
149 }
150
151 static void
ubsan_json_obj_end(ubsan_buf_t * ub)152 ubsan_json_obj_end(ubsan_buf_t *ub)
153 {
154 ubsan_json_struct_end(ub, false);
155 }
156
157 static void
ubsan_json_array_begin(ubsan_buf_t * ub,const char * section_name)158 ubsan_json_array_begin(ubsan_buf_t *ub, const char *section_name)
159 {
160 ubsan_json_struct_begin(ub, section_name, true);
161 }
162
163 static void
ubsan_json_array_end(ubsan_buf_t * ub)164 ubsan_json_array_end(ubsan_buf_t *ub)
165 {
166 ubsan_json_struct_end(ub, true);
167 }
168
169 __printflike(4, 0)
170 static void
ubsan_json_kv_ap(ubsan_buf_t * ub,bool quote,const char * key,const char * fmt,va_list ap)171 ubsan_json_kv_ap(ubsan_buf_t *ub, bool quote, const char *key, const char *fmt, va_list ap)
172 {
173 assert(key && key[0] != '\0');
174 assert(fmt && fmt[0] != '\0');
175
176 if (!ubsan_json_struct_is_empty(ub)) {
177 ubsan_json_log(ub, ",");
178 }
179
180 ubsan_json_log(ub, "\"%s\":", key);
181
182 if (quote) {
183 ubsan_json_log(ub, "\"");
184 ubsan_json_log_ap(ub, fmt, ap);
185 ubsan_json_log(ub, "\"");
186 } else {
187 ubsan_json_log_ap(ub, fmt, ap);
188 }
189 }
190
191 __printflike(4, 5)
192 static void
ubsan_json_kv(ubsan_buf_t * ub,int quote,const char * key,const char * fmt,...)193 ubsan_json_kv(ubsan_buf_t *ub, int quote, const char *key, const char *fmt, ...)
194 {
195 va_list ap;
196
197 va_start(ap, fmt);
198 ubsan_json_kv_ap(ub, quote, key, fmt, ap);
199 va_end(ap);
200 }
201
202 __printflike(3, 4)
203 static void
ubsan_json_fmt(ubsan_buf_t * ub,const char * key,const char * fmt,...)204 ubsan_json_fmt(ubsan_buf_t *ub, const char *key, const char *fmt, ...)
205 {
206 va_list ap;
207
208 va_start(ap, fmt);
209 ubsan_json_kv_ap(ub, true, key, fmt, ap);
210 va_end(ap);
211 }
212
213 static void
ubsan_json_unum(ubsan_buf_t * ub,const char * key,uint64_t number)214 ubsan_json_unum(ubsan_buf_t *ub, const char *key, uint64_t number)
215 {
216 ubsan_json_kv(ub, false, key, "%llu", number);
217 }
218
219 static void
ubsan_json_snum(ubsan_buf_t * ub,const char * key,int64_t number)220 ubsan_json_snum(ubsan_buf_t *ub, const char *key, int64_t number)
221 {
222 ubsan_json_kv(ub, false, key, "%lld", number);
223 }
224
225 static void
ubsan_json_num(ubsan_buf_t * ub,const char * key,struct san_type_desc * std,uint64_t value)226 ubsan_json_num(ubsan_buf_t *ub, const char *key, struct san_type_desc *std, uint64_t value)
227 {
228 if (std->issigned) {
229 ubsan_json_snum(ub, key, signed_num(1 << std->width, value));
230 } else {
231 ubsan_json_unum(ub, key, value);
232 }
233 }
234
235 static void
ubsan_json_bool(ubsan_buf_t * ub,const char * key,bool value)236 ubsan_json_bool(ubsan_buf_t *ub, const char *key, bool value)
237 {
238 ubsan_json_kv(ub, false, key, "%s", value ? "true" : "false");
239 }
240
241 static void
ubsan_json_str(ubsan_buf_t * ub,const char * key,const char * string)242 ubsan_json_str(ubsan_buf_t *ub, const char *key, const char *string)
243 {
244 const char *str_value = string;
245 bool quote = true;
246
247 if (!str_value) {
248 str_value = "null";
249 quote = false;
250 }
251
252 ubsan_json_kv(ub, quote, key, "%s", str_value);
253 }
254
255 static void
ubsan_json_loc(ubsan_buf_t * ub,const char * desc,struct san_src_loc * loc)256 ubsan_json_loc(ubsan_buf_t *ub, const char *desc, struct san_src_loc *loc)
257 {
258 ubsan_json_obj_begin(ub, desc);
259
260 ubsan_json_str(ub, "file", loc->filename);
261 ubsan_json_unum(ub, "line", loc->line & ~line_acquired);
262 ubsan_json_unum(ub, "column", loc->col);
263
264 ubsan_json_obj_end(ub);
265 }
266
267 static void
ubsan_json_type(ubsan_buf_t * ub,const char * section,uint64_t * value,struct san_type_desc * std)268 ubsan_json_type(ubsan_buf_t *ub, const char *section, uint64_t *value, struct san_type_desc *std)
269 {
270 if (section) {
271 ubsan_json_obj_begin(ub, section);
272 }
273
274 if (value) {
275 ubsan_json_num(ub, "value", std, *value);
276 }
277 ubsan_json_str(ub, "type", std->name);
278 ubsan_json_bool(ub, "signed", std->issigned);
279 ubsan_json_unum(ub, "width", 1 << std->width);
280
281 if (section) {
282 ubsan_json_obj_end(ub);
283 }
284 }
285
286 /*
287 * return true for the first visit to this loc, false every subsequent time
288 */
289 static bool
ubsan_loc_acquire(struct san_src_loc * loc)290 ubsan_loc_acquire(struct san_src_loc *loc)
291 {
292 uint32_t line = loc->line;
293 if (line & line_acquired) {
294 return false;
295 }
296 uint32_t acq = line | line_acquired;
297 return atomic_compare_exchange_strong((_Atomic uint32_t *)&loc->line, &line, acq);
298 }
299
300 static void
format_overflow(ubsan_violation_t * v,ubsan_buf_t * ub)301 format_overflow(ubsan_violation_t *v, ubsan_buf_t *ub)
302 {
303 static const char *const overflow_str[] = {
304 NULL,
305 "add",
306 "sub",
307 "mul",
308 "divrem",
309 "negate",
310 NULL
311 };
312 struct san_type_desc *ty = v->overflow->ty;
313
314 ubsan_json_fmt(ub, "problem", "type overflow");
315 ubsan_json_str(ub, "op", overflow_str[v->ubsan_type]);
316 ubsan_json_type(ub, "lhs", &v->lhs, ty);
317 ubsan_json_unum(ub, "rhs", v->rhs);
318 }
319
320 static void
format_shift(ubsan_violation_t * v,ubsan_buf_t * ub)321 format_shift(ubsan_violation_t *v, ubsan_buf_t *ub)
322 {
323 ubsan_json_str(ub, "problem", "bad shift");
324 ubsan_json_type(ub, "lhs", &v->lhs, v->shift->lhs_t);
325 ubsan_json_type(ub, "rhs", &v->rhs, v->shift->rhs_t);
326 }
327
328 static const char *
get_mismatch_kind(uint8_t kind)329 get_mismatch_kind(uint8_t kind)
330 {
331 static const char *const mismatch_kinds[] = {
332 "load of",
333 "store to",
334 "reference binding to",
335 "member access within",
336 "member call on",
337 "constructor call on",
338 "downcast of",
339 "downcast of",
340 "upcast of",
341 "cast to virtual base of",
342 "_Nonnull binding to"
343 };
344
345 return (kind < (sizeof(mismatch_kinds) / sizeof(mismatch_kinds[0])))
346 ? mismatch_kinds[kind]
347 : "some";
348 }
349
350 static void
format_type_mismatch(ubsan_violation_t * v,ubsan_buf_t * ub)351 format_type_mismatch(ubsan_violation_t *v, ubsan_buf_t *ub)
352 {
353 const char *kind = get_mismatch_kind(v->align->kind);
354 const size_t alignment = 1 << v->align->align;
355 uintptr_t addr = (uintptr_t)v->lhs;
356
357 ubsan_json_str(ub, "problem", "type mismatch");
358
359 if (!addr) {
360 ubsan_json_fmt(ub, "kind", "%s NULL pointer", kind);
361 ubsan_json_str(ub, "type", v->align->ty->name);
362 return;
363 }
364
365 if (alignment && (addr & (alignment - 1))) {
366 ubsan_json_fmt(ub, "kind", "%s misaligned", kind);
367 ubsan_json_unum(ub, "required", alignment);
368 } else {
369 ubsan_json_fmt(ub, "kind", "%s insufficient size", kind);
370 }
371 ubsan_json_type(ub, NULL, (uint64_t *)&addr, v->align->ty);
372 }
373
374 static void
format_oob(ubsan_violation_t * v,ubsan_buf_t * ub)375 format_oob(ubsan_violation_t *v, ubsan_buf_t *ub)
376 {
377 ubsan_json_str(ub, "problem", "OOB array indexing");
378 ubsan_json_type(ub, "array", NULL, v->oob->array_ty);
379 ubsan_json_type(ub, "idx", &v->lhs, v->oob->index_ty);
380 }
381
382 static void
format_nullability_arg(ubsan_violation_t * v,ubsan_buf_t * ub)383 format_nullability_arg(ubsan_violation_t *v, ubsan_buf_t *ub)
384 {
385 struct ubsan_nullability_arg_desc *data = v->nonnull_arg;
386
387 ubsan_json_str(ub, "problem", "nullability");
388 ubsan_json_snum(ub, "arg", data->arg_index);
389 ubsan_json_str(ub, "attr", v->lhs ? "nonnull" : "_Nonnull");
390 ubsan_json_loc(ub, "declared", &data->attr_loc);
391 }
392
393 static void
format_nonnull_return(ubsan_violation_t * v,ubsan_buf_t * ub)394 format_nonnull_return(ubsan_violation_t *v, ubsan_buf_t *ub)
395 {
396 ubsan_json_str(ub, "problem", "nonnull return");
397 ubsan_json_str(ub, "attr", v->lhs ? "returns_nonnull" : "_Nonnull");
398 ubsan_json_loc(ub, "declared", (struct san_src_loc *)v->rhs);
399 }
400
401 static void
format_load_invalid_value(ubsan_violation_t * v,ubsan_buf_t * ub)402 format_load_invalid_value(ubsan_violation_t *v, ubsan_buf_t *ub)
403 {
404 ubsan_json_str(ub, "problem", "invalid load");
405 ubsan_json_type(ub, NULL, &v->lhs, v->invalid->type);
406 }
407
408 static void
format_missing_return(ubsan_violation_t * v __unused,ubsan_buf_t * ub)409 format_missing_return(ubsan_violation_t *v __unused, ubsan_buf_t *ub)
410 {
411 ubsan_json_str(ub, "problem", "missing return");
412 }
413
414 static void
format_float_cast_overflow(ubsan_violation_t * v,ubsan_buf_t * ub)415 format_float_cast_overflow(ubsan_violation_t *v, ubsan_buf_t *ub)
416 {
417 struct ubsan_float_desc *data = v->flt;
418 /*
419 * Cannot print out offending value (e.g. using %A, %f and so on) as kernel logging
420 * does not support float types (yet).
421 */
422 ubsan_json_str(ub, "problem", "cast overflow");
423 ubsan_json_str(ub, "src", data->type_from->name);
424 ubsan_json_str(ub, "to", data->type_to->name);
425 }
426
427 static const char *
get_implicit_conv_type(unsigned char kind)428 get_implicit_conv_type(unsigned char kind)
429 {
430 static const char * const conv_types[] = {
431 "integer truncation",
432 "unsigned integer truncation",
433 "signed integer truncation",
434 "integer sign change",
435 "signed integer truncation or sign change"
436 };
437 static const size_t conv_types_cnt = sizeof(conv_types) / sizeof(conv_types[0]);
438
439 return kind < conv_types_cnt ? conv_types[kind] : "unknown implicit integer conversion";
440 }
441
442 static void
format_implicit_conversion(ubsan_violation_t * v,ubsan_buf_t * ub)443 format_implicit_conversion(ubsan_violation_t *v, ubsan_buf_t *ub)
444 {
445 struct ubsan_implicit_conv_desc *data = v->implicit;
446
447 ubsan_json_str(ub, "problem", get_implicit_conv_type(data->kind));
448 ubsan_json_type(ub, "lhs", &v->lhs, data->type_to);
449 ubsan_json_type(ub, "rhs", &v->rhs, data->type_from);
450 }
451
452 static void
format_function_type_mismatch(ubsan_violation_t * v,ubsan_buf_t * ub)453 format_function_type_mismatch(ubsan_violation_t *v, ubsan_buf_t *ub)
454 {
455 ubsan_json_str(ub, "problem", "bad indirect call");
456 ubsan_json_type(ub, NULL, &v->lhs, v->func_mismatch->type);
457 }
458
459 static void
format_vla_bound_not_positive(ubsan_violation_t * v,ubsan_buf_t * ub)460 format_vla_bound_not_positive(ubsan_violation_t *v, ubsan_buf_t *ub)
461 {
462 ubsan_json_str(ub, "problem", "non-positive VLA bound");
463 ubsan_json_type(ub, NULL, &v->lhs, v->vla_bound->type);
464 }
465
466 static void
format_invalid_builtin(ubsan_violation_t * v,ubsan_buf_t * ub)467 format_invalid_builtin(ubsan_violation_t *v, ubsan_buf_t *ub)
468 {
469 ubsan_json_str(ub, "problem", "invalid builtin");
470 ubsan_json_str(ub, "op", v->invalid_builtin->kind == 0 ? "ctz()" : "clz()");
471 }
472
473 static void
format_ptr_overflow(ubsan_violation_t * v,ubsan_buf_t * ub)474 format_ptr_overflow(ubsan_violation_t *v, ubsan_buf_t *ub)
475 {
476 ubsan_json_str(ub, "problem", "pointer overflow");
477 ubsan_json_unum(ub, "lhs", v->lhs);
478 ubsan_json_unum(ub, "rhs", v->rhs);
479 }
480
481 static void
format_unreachable(ubsan_buf_t * ub)482 format_unreachable(ubsan_buf_t *ub)
483 {
484 ubsan_json_str(ub, "problem", "unreachable");
485 }
486
487 void
ubsan_json_init(ubsan_buf_t * ub,char * buf,size_t bufsize)488 ubsan_json_init(ubsan_buf_t *ub, char *buf, size_t bufsize)
489 {
490 assert(bufsize > sizeof("{\"count\":9999,\"violations\":[]}"));
491 assert(buf);
492
493 ub->ub_buf = buf;
494 ub->ub_buf_size = bufsize;
495 ub->ub_written = 0;
496 ub->ub_err = false;
497 }
498
499 void
ubsan_json_begin(ubsan_buf_t * ub,size_t nentries)500 ubsan_json_begin(ubsan_buf_t *ub, size_t nentries)
501 {
502 ub->ub_buf_size--; // for '\0'
503
504 ubsan_json_obj_begin(ub, NULL);
505 ubsan_json_unum(ub, "count", nentries);
506 ubsan_json_array_begin(ub, "violations");
507
508 assert(!ub->ub_err);
509 }
510
511 size_t
ubsan_json_finish(ubsan_buf_t * ub)512 ubsan_json_finish(ubsan_buf_t *ub)
513 {
514 ub->ub_buf_size++; // for '\0'
515 ub->ub_err = false;
516
517 ubsan_json_array_end(ub);
518 ubsan_json_obj_end(ub);
519
520 assert(!ub->ub_err);
521 return ub->ub_written;
522 }
523
524 bool
ubsan_json_format(ubsan_violation_t * v,ubsan_buf_t * ub)525 ubsan_json_format(ubsan_violation_t *v, ubsan_buf_t *ub)
526 {
527 const size_t mark = ub->ub_written;
528
529 ubsan_json_obj_begin(ub, NULL);
530
531 switch (v->ubsan_type) {
532 case UBSAN_OVERFLOW_add ... UBSAN_OVERFLOW_negate:
533 format_overflow(v, ub);
534 break;
535 case UBSAN_UNREACHABLE:
536 format_unreachable(ub);
537 break;
538 case UBSAN_SHIFT:
539 format_shift(v, ub);
540 break;
541 case UBSAN_TYPE_MISMATCH:
542 format_type_mismatch(v, ub);
543 break;
544 case UBSAN_POINTER_OVERFLOW:
545 format_ptr_overflow(v, ub);
546 break;
547 case UBSAN_OOB:
548 format_oob(v, ub);
549 break;
550 case UBSAN_NULLABILITY_ARG:
551 format_nullability_arg(v, ub);
552 break;
553 case UBSAN_NULLABILITY_RETURN:
554 format_nonnull_return(v, ub);
555 break;
556 case UBSAN_MISSING_RETURN:
557 format_missing_return(v, ub);
558 break;
559 case UBSAN_FLOAT_CAST_OVERFLOW:
560 format_float_cast_overflow(v, ub);
561 break;
562 case UBSAN_IMPLICIT_CONVERSION:
563 format_implicit_conversion(v, ub);
564 break;
565 case UBSAN_FUNCTION_TYPE_MISMATCH:
566 format_function_type_mismatch(v, ub);
567 break;
568 case UBSAN_VLA_BOUND_NOT_POSITIVE:
569 format_vla_bound_not_positive(v, ub);
570 break;
571 case UBSAN_INVALID_BUILTIN:
572 format_invalid_builtin(v, ub);
573 break;
574 case UBSAN_LOAD_INVALID_VALUE:
575 format_load_invalid_value(v, ub);
576 break;
577 default:
578 panic("unknown violation");
579 }
580
581 ubsan_json_loc(ub, "source", v->loc);
582 ubsan_json_obj_end(ub);
583
584 if (ub->ub_err) {
585 ubsan_buf_rewind(ub, mark);
586 }
587 assert(ub->ub_buf[ub->ub_written] == '\0');
588
589 return !ub->ub_err;
590 }
591
592 enum UBFatality { Fatal, FleshWound };
593
594 static void
ubsan_handle(ubsan_violation_t * v,enum UBFatality fatality)595 ubsan_handle(ubsan_violation_t *v, enum UBFatality fatality)
596 {
597 if (!ubsan_loc_acquire(v->loc)) {
598 /* violation site already reported */
599 return;
600 }
601 ubsan_log_append(v);
602
603 if (fatality != Fatal) {
604 return;
605 }
606
607 static char buf[512] = { 0 };
608 ubsan_buf_t ubsan_buf;
609
610 ubsan_json_init(&ubsan_buf, buf, sizeof(buf));
611
612 if (ubsan_json_format(v, &ubsan_buf)) {
613 printf("UBSan: %s", buf);
614 }
615 }
616
617 void
__ubsan_handle_builtin_unreachable(struct ubsan_unreachable_desc * desc)618 __ubsan_handle_builtin_unreachable(struct ubsan_unreachable_desc *desc)
619 {
620 ubsan_violation_t v = { UBSAN_UNREACHABLE, 0, 0, .unreachable = desc, &desc->loc };
621 ubsan_handle(&v, Fatal);
622 }
623
624 void
__ubsan_handle_shift_out_of_bounds(struct ubsan_shift_desc * desc,uint64_t lhs,uint64_t rhs)625 __ubsan_handle_shift_out_of_bounds(struct ubsan_shift_desc *desc, uint64_t lhs, uint64_t rhs)
626 {
627 ubsan_violation_t v = { UBSAN_SHIFT, lhs, rhs, .shift = desc, &desc->loc };
628 ubsan_handle(&v, FleshWound);
629 }
630
631 void
__ubsan_handle_shift_out_of_bounds_abort(struct ubsan_shift_desc * desc,uint64_t lhs,uint64_t rhs)632 __ubsan_handle_shift_out_of_bounds_abort(struct ubsan_shift_desc *desc, uint64_t lhs, uint64_t rhs)
633 {
634 ubsan_violation_t v = { UBSAN_SHIFT, lhs, rhs, .shift = desc, &desc->loc };
635 ubsan_handle(&v, Fatal);
636 }
637
638 #define DEFINE_OVERFLOW(op) \
639 void __ubsan_handle_##op##_overflow(struct ubsan_overflow_desc *desc, uint64_t lhs, uint64_t rhs) { \
640 ubsan_violation_t v = { UBSAN_OVERFLOW_##op, lhs, rhs, .overflow = desc, &desc->loc }; \
641 ubsan_handle(&v, FleshWound); \
642 } \
643 void __ubsan_handle_##op##_overflow_abort(struct ubsan_overflow_desc *desc, uint64_t lhs, uint64_t rhs) { \
644 ubsan_violation_t v = { UBSAN_OVERFLOW_##op, lhs, rhs, .overflow = desc, &desc->loc }; \
645 ubsan_handle(&v, Fatal); \
646 }
647
648 DEFINE_OVERFLOW(add)
DEFINE_OVERFLOW(sub)649 DEFINE_OVERFLOW(sub)
650 DEFINE_OVERFLOW(mul)
651 DEFINE_OVERFLOW(divrem)
652 DEFINE_OVERFLOW(negate)
653
654 void
655 __ubsan_handle_type_mismatch_v1(struct ubsan_align_desc *desc, uint64_t val)
656 {
657 ubsan_violation_t v = { UBSAN_TYPE_MISMATCH, val, 0, .align = desc, &desc->loc };
658 ubsan_handle(&v, FleshWound);
659 }
660
661 void
__ubsan_handle_type_mismatch_v1_abort(struct ubsan_align_desc * desc,uint64_t val)662 __ubsan_handle_type_mismatch_v1_abort(struct ubsan_align_desc *desc, uint64_t val)
663 {
664 ubsan_violation_t v = { UBSAN_TYPE_MISMATCH, val, 0, .align = desc, &desc->loc };
665 ubsan_handle(&v, Fatal);
666 }
667
668 void
__ubsan_handle_pointer_overflow(struct ubsan_ptroverflow_desc * desc,uint64_t before,uint64_t after)669 __ubsan_handle_pointer_overflow(struct ubsan_ptroverflow_desc *desc, uint64_t before, uint64_t after)
670 {
671 ubsan_violation_t v = { UBSAN_POINTER_OVERFLOW, before, after, .ptroverflow = desc, &desc->loc };
672 ubsan_handle(&v, FleshWound);
673 }
674
675 void
__ubsan_handle_pointer_overflow_abort(struct ubsan_ptroverflow_desc * desc,uint64_t before,uint64_t after)676 __ubsan_handle_pointer_overflow_abort(struct ubsan_ptroverflow_desc *desc, uint64_t before, uint64_t after)
677 {
678 ubsan_violation_t v = { UBSAN_POINTER_OVERFLOW, before, after, .ptroverflow = desc, &desc->loc };
679 ubsan_handle(&v, Fatal);
680 }
681
682 void
__ubsan_handle_out_of_bounds(struct ubsan_oob_desc * desc,uint64_t idx)683 __ubsan_handle_out_of_bounds(struct ubsan_oob_desc *desc, uint64_t idx)
684 {
685 ubsan_violation_t v = { UBSAN_OOB, idx, 0, .oob = desc, &desc->loc };
686 ubsan_handle(&v, FleshWound);
687 }
688
689 void
__ubsan_handle_out_of_bounds_abort(struct ubsan_oob_desc * desc,uint64_t idx)690 __ubsan_handle_out_of_bounds_abort(struct ubsan_oob_desc *desc, uint64_t idx)
691 {
692 ubsan_violation_t v = { UBSAN_OOB, idx, 0, .oob = desc, &desc->loc };
693 ubsan_handle(&v, Fatal);
694 }
695
696 void
__ubsan_handle_nullability_arg(struct ubsan_nullability_arg_desc * desc)697 __ubsan_handle_nullability_arg(struct ubsan_nullability_arg_desc *desc)
698 {
699 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 0, 0, .nonnull_arg = desc, &desc->loc };
700 ubsan_handle(&v, FleshWound);
701 }
702
703 void
__ubsan_handle_nullability_arg_abort(struct ubsan_nullability_arg_desc * desc)704 __ubsan_handle_nullability_arg_abort(struct ubsan_nullability_arg_desc *desc)
705 {
706 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 0, 0, .nonnull_arg = desc, &desc->loc };
707 ubsan_handle(&v, Fatal);
708 }
709
710 void
__ubsan_handle_nonnull_arg(struct ubsan_nullability_arg_desc * desc)711 __ubsan_handle_nonnull_arg(struct ubsan_nullability_arg_desc *desc)
712 {
713 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 1, 0, .nonnull_arg = desc, &desc->loc };
714 ubsan_handle(&v, FleshWound);
715 }
716
717 void
__ubsan_handle_nonnull_arg_abort(struct ubsan_nullability_arg_desc * desc)718 __ubsan_handle_nonnull_arg_abort(struct ubsan_nullability_arg_desc *desc)
719 {
720 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 1, 0, .nonnull_arg = desc, &desc->loc };
721 ubsan_handle(&v, Fatal);
722 }
723
724 void
__ubsan_handle_nullability_return_v1(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)725 __ubsan_handle_nullability_return_v1(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
726 {
727 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 0, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
728 ubsan_handle(&v, FleshWound);
729 }
730
731 void
__ubsan_handle_nullability_return_v1_abort(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)732 __ubsan_handle_nullability_return_v1_abort(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
733 {
734 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 0, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
735 ubsan_handle(&v, Fatal);
736 }
737
738 void
__ubsan_handle_nonnull_return_v1(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)739 __ubsan_handle_nonnull_return_v1(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
740 {
741 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 1, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
742 ubsan_handle(&v, FleshWound);
743 }
744
745 void
__ubsan_handle_nonnull_return_v1_abort(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)746 __ubsan_handle_nonnull_return_v1_abort(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
747 {
748 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 1, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
749 ubsan_handle(&v, Fatal);
750 }
751
752 void
__ubsan_handle_missing_return(struct ubsan_missing_ret_desc * desc)753 __ubsan_handle_missing_return(struct ubsan_missing_ret_desc *desc)
754 {
755 ubsan_violation_t v = { UBSAN_MISSING_RETURN, 0, 0, .missing_ret = desc, &desc->loc };
756 ubsan_handle(&v, Fatal);
757 }
758
759 void
__ubsan_handle_missing_return_abort(struct ubsan_missing_ret_desc * desc)760 __ubsan_handle_missing_return_abort(struct ubsan_missing_ret_desc *desc)
761 {
762 ubsan_violation_t v = { UBSAN_MISSING_RETURN, 0, 0, .missing_ret = desc, &desc->loc };
763 ubsan_handle(&v, Fatal);
764 }
765
766 void
__ubsan_handle_float_cast_overflow(struct ubsan_float_desc * desc,uint64_t value)767 __ubsan_handle_float_cast_overflow(struct ubsan_float_desc *desc, uint64_t value)
768 {
769 ubsan_violation_t v = { UBSAN_FLOAT_CAST_OVERFLOW, value, 0, .flt = desc, &desc->loc };
770 ubsan_handle(&v, Fatal);
771 }
772
773 void
__ubsan_handle_float_cast_overflow_abort(struct ubsan_float_desc * desc,uint64_t value)774 __ubsan_handle_float_cast_overflow_abort(struct ubsan_float_desc *desc, uint64_t value)
775 {
776 ubsan_violation_t v = { UBSAN_FLOAT_CAST_OVERFLOW, value, 0, .flt = desc, &desc->loc };
777 ubsan_handle(&v, Fatal);
778 }
779
780 void
__ubsan_handle_implicit_conversion(struct ubsan_implicit_conv_desc * desc,uint64_t from,uint64_t to)781 __ubsan_handle_implicit_conversion(struct ubsan_implicit_conv_desc *desc, uint64_t from, uint64_t to)
782 {
783 ubsan_violation_t v = { UBSAN_IMPLICIT_CONVERSION, from, to, .implicit = desc, &desc->loc };
784 ubsan_handle(&v, Fatal);
785 }
786
787 void
__ubsan_handle_implicit_conversion_abort(struct ubsan_implicit_conv_desc * desc,uint64_t from,uint64_t to)788 __ubsan_handle_implicit_conversion_abort(struct ubsan_implicit_conv_desc *desc, uint64_t from, uint64_t to)
789 {
790 ubsan_violation_t v = { UBSAN_IMPLICIT_CONVERSION, from, to, .implicit = desc, &desc->loc };
791 ubsan_handle(&v, Fatal);
792 }
793
794 void
__ubsan_handle_function_type_mismatch(struct ubsan_func_type_mismatch_desc * desc,uint64_t func)795 __ubsan_handle_function_type_mismatch(struct ubsan_func_type_mismatch_desc *desc, uint64_t func)
796 {
797 ubsan_violation_t v = { UBSAN_FUNCTION_TYPE_MISMATCH, func, 0, .func_mismatch = desc, &desc->loc };
798 ubsan_handle(&v, Fatal);
799 }
800
801 void
__ubsan_handle_function_type_mismatch_abort(struct ubsan_func_type_mismatch_desc * desc,uint64_t func)802 __ubsan_handle_function_type_mismatch_abort(struct ubsan_func_type_mismatch_desc *desc, uint64_t func)
803 {
804 ubsan_violation_t v = { UBSAN_FUNCTION_TYPE_MISMATCH, func, 0, .func_mismatch = desc, &desc->loc };
805 ubsan_handle(&v, Fatal);
806 }
807
808 void
__ubsan_handle_vla_bound_not_positive(struct ubsan_vla_bound_desc * desc,uint64_t length)809 __ubsan_handle_vla_bound_not_positive(struct ubsan_vla_bound_desc *desc, uint64_t length)
810 {
811 ubsan_violation_t v = { UBSAN_VLA_BOUND_NOT_POSITIVE, length, 0, .vla_bound = desc, &desc->loc };
812 ubsan_handle(&v, Fatal);
813 }
814
815 void
__ubsan_handle_vla_bound_not_positive_abort(struct ubsan_vla_bound_desc * desc,uint64_t length)816 __ubsan_handle_vla_bound_not_positive_abort(struct ubsan_vla_bound_desc *desc, uint64_t length)
817 {
818 ubsan_violation_t v = { UBSAN_VLA_BOUND_NOT_POSITIVE, length, 0, .vla_bound = desc, &desc->loc };
819 ubsan_handle(&v, Fatal);
820 }
821
822 void
__ubsan_handle_invalid_builtin(struct ubsan_invalid_builtin * desc)823 __ubsan_handle_invalid_builtin(struct ubsan_invalid_builtin *desc)
824 {
825 ubsan_violation_t v = { UBSAN_INVALID_BUILTIN, 0, 0, .invalid_builtin = desc, &desc->loc };
826 ubsan_handle(&v, Fatal);
827 }
828
829 void
__ubsan_handle_invalid_builtin_abort(struct ubsan_invalid_builtin * desc)830 __ubsan_handle_invalid_builtin_abort(struct ubsan_invalid_builtin *desc)
831 {
832 ubsan_violation_t v = { UBSAN_INVALID_BUILTIN, 0, 0, .invalid_builtin = desc, &desc->loc };
833 ubsan_handle(&v, Fatal);
834 }
835
836 void
__ubsan_handle_load_invalid_value(struct ubsan_load_invalid_desc * desc,uint64_t invalid_value)837 __ubsan_handle_load_invalid_value(struct ubsan_load_invalid_desc *desc, uint64_t invalid_value)
838 {
839 ubsan_violation_t v = { UBSAN_LOAD_INVALID_VALUE, invalid_value, 0, .invalid = desc, &desc->loc };
840 ubsan_handle(&v, Fatal);
841 }
842
843 void
__ubsan_handle_load_invalid_value_abort(struct ubsan_load_invalid_desc * desc,uint64_t invalid_value)844 __ubsan_handle_load_invalid_value_abort(struct ubsan_load_invalid_desc *desc, uint64_t invalid_value)
845 {
846 ubsan_violation_t v = { UBSAN_LOAD_INVALID_VALUE, invalid_value, 0, .invalid = desc, &desc->loc };
847 ubsan_handle(&v, Fatal);
848 }
849