xref: /xnu-10063.121.3/san/memory/ubsan.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
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