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