1 /* $OpenBSD: subr_kubsan.c,v 1.13 2024/09/06 13:31:59 mbuhl Exp $ */
2
3 /*
4 * Copyright (c) 2019 Anton Lindqvist <anton@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/atomic.h>
22 #include <sys/syslimits.h>
23 #include <sys/systm.h>
24 #include <sys/timeout.h>
25
26 #include <uvm/uvm_extern.h>
27
28 #define KUBSAN_INTERVAL 100 /* report interval in msec */
29 #define KUBSAN_NSLOTS 32
30
31 #define NUMBER_BUFSIZ 32
32 #define LOCATION_BUFSIZ (PATH_MAX + 32) /* filename:line:column */
33 #define LOCATION_REPORTED (1U << 31)
34
35 #define NBITS(typ) (1 << ((typ)->t_info >> 1))
36 #define SIGNED(typ) ((typ)->t_info & 1)
37
38 struct kubsan_report {
39 enum {
40 KUBSAN_FLOAT_CAST_OVERFLOW,
41 KUBSAN_INVALID_BUILTIN,
42 KUBSAN_INVALID_VALUE,
43 KUBSAN_NEGATE_OVERFLOW,
44 KUBSAN_NONNULL_ARG,
45 KUBSAN_OUT_OF_BOUNDS,
46 KUBSAN_OVERFLOW,
47 KUBSAN_POINTER_OVERFLOW,
48 KUBSAN_SHIFT_OUT_OF_BOUNDS,
49 KUBSAN_TYPE_MISMATCH,
50 KUBSAN_UNREACHABLE,
51 } kr_type;
52
53 struct source_location *kr_src;
54
55 union {
56 struct {
57 const struct float_cast_overflow_data *v_data;
58 unsigned long v_val;
59 } v_float_cast_overflow;
60
61 struct {
62 const struct invalid_builtin_data *v_data;
63 } v_invalid_builtin;
64
65 struct {
66 const struct invalid_value_data *v_data;
67 unsigned long v_val;
68 } v_invalid_value;
69
70 struct {
71 const struct overflow_data *v_data;
72 unsigned int v_val;
73 } v_negate_overflow;
74
75 struct {
76 const struct nonnull_arg_data *v_data;
77 } v_nonnull_arg;
78
79 struct {
80 const struct out_of_bounds_data *v_data;
81 unsigned int v_idx;
82 } v_out_of_bounds;
83
84 struct {
85 const struct overflow_data *v_data;
86 unsigned long v_lhs;
87 unsigned long v_rhs;
88 char v_op;
89 } v_overflow;
90
91 struct {
92 const struct pointer_overflow_data *v_data;
93 unsigned long v_base;
94 unsigned long v_res;
95 } v_pointer_overflow;
96
97 struct {
98 const struct shift_out_of_bounds_data *v_data;
99 unsigned long v_lhs;
100 unsigned long v_rhs;
101 } v_shift_out_of_bounds;
102
103 struct {
104 const struct type_mismatch_data *v_data;
105 unsigned long v_ptr;
106 } v_type_mismatch;
107 } kr_u;
108 };
109 #define kr_float_cast_overflow kr_u.v_float_cast_overflow
110 #define kr_invalid_builtin kr_u.v_invalid_builtin
111 #define kr_invalid_value kr_u.v_invalid_value
112 #define kr_negate_overflow kr_u.v_negate_overflow
113 #define kr_nonnull_arg kr_u.v_nonnull_arg
114 #define kr_out_of_bounds kr_u.v_out_of_bounds
115 #define kr_overflow kr_u.v_overflow
116 #define kr_pointer_overflow kr_u.v_pointer_overflow
117 #define kr_shift_out_of_bounds kr_u.v_shift_out_of_bounds
118 #define kr_type_mismatch kr_u.v_type_mismatch
119
120 struct type_descriptor {
121 uint16_t t_kind;
122 uint16_t t_info;
123 char t_name[1]; /* type name as variable length array */
124 };
125
126 struct source_location {
127 const char *sl_filename;
128 uint32_t sl_line;
129 uint32_t sl_column;
130 };
131
132 struct float_cast_overflow_data {
133 struct source_location d_src;
134 struct type_descriptor *d_ftype; /* from type */
135 struct type_descriptor *d_ttype; /* to type */
136 };
137
138 struct invalid_builtin_data {
139 struct source_location d_src;
140 uint8_t d_kind;
141 };
142
143 struct invalid_value_data {
144 struct source_location d_src;
145 struct type_descriptor *d_type;
146 };
147
148 struct nonnull_arg_data {
149 struct source_location d_src;
150 struct source_location d_attr_src; /* __attribute__ location */
151 int d_idx;
152 };
153
154 struct out_of_bounds_data {
155 struct source_location d_src;
156 struct type_descriptor *d_atype; /* array type */
157 struct type_descriptor *d_itype; /* index type */
158 };
159
160 struct overflow_data {
161 struct source_location d_src;
162 struct type_descriptor *d_type;
163 };
164
165 struct pointer_overflow_data {
166 struct source_location d_src;
167 };
168
169 struct shift_out_of_bounds_data {
170 struct source_location d_src;
171 struct type_descriptor *d_ltype;
172 struct type_descriptor *d_rtype;
173 };
174
175 struct type_mismatch_data {
176 struct source_location d_src;
177 struct type_descriptor *d_type;
178 uint8_t d_align; /* log2 alignment */
179 uint8_t d_kind;
180 };
181
182 struct unreachable_data {
183 struct source_location d_src;
184 };
185
186 int64_t kubsan_deserialize_int(struct type_descriptor *,
187 unsigned long);
188 uint64_t kubsan_deserialize_uint(struct type_descriptor *,
189 unsigned long);
190 void kubsan_defer_report(struct kubsan_report *);
191 void kubsan_format_int(struct type_descriptor *, unsigned long,
192 char *, size_t);
193 int kubsan_format_location(const struct source_location *, char *,
194 size_t);
195 int kubsan_is_reported(struct source_location *);
196 const char *kubsan_kind(uint8_t);
197 void kubsan_report(void *);
198 void kubsan_unreport(struct source_location *);
199
200 static int is_negative(struct type_descriptor *, unsigned long);
201 static int is_shift_exponent_too_large(struct type_descriptor *,
202 unsigned long);
203
204 static const char *pathstrip(const char *);
205
206 #ifdef KUBSAN_WATCH
207 int kubsan_watch = 2;
208 #else
209 int kubsan_watch = 1;
210 #endif
211
212 struct kubsan_report *kubsan_reports = NULL;
213 struct timeout kubsan_timo = TIMEOUT_INITIALIZER(kubsan_report, NULL);
214 unsigned int kubsan_slot = 0;
215 int kubsan_cold = 1;
216
217 /*
218 * Compiling the kernel with `-fsanitize=undefined' will cause the following
219 * functions to be called when a sanitizer detects undefined behavior.
220 * Some sanitizers are omitted since they are only applicable to C++.
221 *
222 * Every __ubsan_*() sanitizer function also has a corresponding
223 * __ubsan_*_abort() function as part of the ABI provided by Clang.
224 * But, since the kernel never is compiled with `fno-sanitize-recover' for
225 * obvious reasons, they are also omitted.
226 */
227
228 void
__ubsan_handle_add_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)229 __ubsan_handle_add_overflow(struct overflow_data *data,
230 unsigned long lhs, unsigned long rhs)
231 {
232 struct kubsan_report kr = {
233 .kr_type = KUBSAN_OVERFLOW,
234 .kr_src = &data->d_src,
235 .kr_overflow = { data, lhs, rhs, '+' },
236 };
237
238 kubsan_defer_report(&kr);
239 }
240
241 void
__ubsan_handle_builtin_unreachable(struct unreachable_data * data)242 __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
243 {
244 struct kubsan_report kr = {
245 .kr_type = KUBSAN_UNREACHABLE,
246 .kr_src = &data->d_src,
247 };
248
249 kubsan_defer_report(&kr);
250 }
251
252 void
__ubsan_handle_divrem_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)253 __ubsan_handle_divrem_overflow(struct overflow_data *data,
254 unsigned long lhs, unsigned long rhs)
255 {
256 struct kubsan_report kr = {
257 .kr_type = KUBSAN_OVERFLOW,
258 .kr_src = &data->d_src,
259 .kr_overflow = { data, lhs, rhs, '/' },
260 };
261
262 kubsan_defer_report(&kr);
263 }
264
265 void
__ubsan_handle_float_cast_overflow(struct float_cast_overflow_data * data,unsigned long val)266 __ubsan_handle_float_cast_overflow(struct float_cast_overflow_data *data,
267 unsigned long val)
268 {
269 struct kubsan_report kr = {
270 .kr_type = KUBSAN_FLOAT_CAST_OVERFLOW,
271 .kr_src = &data->d_src,
272 .kr_float_cast_overflow = { data, val },
273 };
274
275 kubsan_defer_report(&kr);
276 }
277
278 void
__ubsan_handle_invalid_builtin(struct invalid_builtin_data * data)279 __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
280 {
281 struct kubsan_report kr = {
282 .kr_type = KUBSAN_INVALID_VALUE,
283 .kr_src = &data->d_src,
284 .kr_invalid_builtin = { data },
285 };
286
287 kubsan_defer_report(&kr);
288 }
289
290 void
__ubsan_handle_load_invalid_value(struct invalid_value_data * data,unsigned long val)291 __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
292 unsigned long val)
293 {
294 struct kubsan_report kr = {
295 .kr_type = KUBSAN_INVALID_VALUE,
296 .kr_src = &data->d_src,
297 .kr_invalid_value = { data, val },
298 };
299
300 kubsan_defer_report(&kr);
301 }
302
303 void
__ubsan_handle_nonnull_arg(struct nonnull_arg_data * data)304 __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
305 {
306 struct kubsan_report kr = {
307 .kr_type = KUBSAN_NONNULL_ARG,
308 .kr_src = &data->d_src,
309 .kr_nonnull_arg = { data },
310 };
311
312 kubsan_defer_report(&kr);
313 }
314
315 void
__ubsan_handle_mul_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)316 __ubsan_handle_mul_overflow(struct overflow_data *data,
317 unsigned long lhs, unsigned long rhs)
318 {
319 struct kubsan_report kr = {
320 .kr_type = KUBSAN_OVERFLOW,
321 .kr_src = &data->d_src,
322 .kr_overflow = { data, lhs, rhs, '*' },
323 };
324
325 kubsan_defer_report(&kr);
326 }
327
328 void
__ubsan_handle_negate_overflow(struct overflow_data * data,unsigned long val)329 __ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long val)
330 {
331 struct kubsan_report kr = {
332 .kr_type = KUBSAN_NEGATE_OVERFLOW,
333 .kr_src = &data->d_src,
334 .kr_negate_overflow = { data, val },
335 };
336
337 kubsan_defer_report(&kr);
338 }
339
340 void
__ubsan_handle_out_of_bounds(struct out_of_bounds_data * data,unsigned long idx)341 __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
342 unsigned long idx)
343 {
344 struct kubsan_report kr = {
345 .kr_type = KUBSAN_OUT_OF_BOUNDS,
346 .kr_src = &data->d_src,
347 .kr_out_of_bounds = { data, idx },
348 };
349
350 kubsan_defer_report(&kr);
351 }
352
353 void
__ubsan_handle_pointer_overflow(struct pointer_overflow_data * data,unsigned long base,unsigned long res)354 __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
355 unsigned long base, unsigned long res)
356 {
357 struct kubsan_report kr = {
358 .kr_type = KUBSAN_POINTER_OVERFLOW,
359 .kr_src = &data->d_src,
360 .kr_pointer_overflow = { data, base, res },
361 };
362
363 kubsan_defer_report(&kr);
364 }
365
366 void
__ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data * data,unsigned long lhs,unsigned long rhs)367 __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
368 unsigned long lhs, unsigned long rhs)
369 {
370 struct kubsan_report kr = {
371 .kr_type = KUBSAN_SHIFT_OUT_OF_BOUNDS,
372 .kr_src = &data->d_src,
373 .kr_shift_out_of_bounds = { data, lhs, rhs },
374 };
375
376 kubsan_defer_report(&kr);
377 }
378
379 void
__ubsan_handle_sub_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)380 __ubsan_handle_sub_overflow(struct overflow_data *data,
381 unsigned long lhs, unsigned long rhs)
382 {
383 struct kubsan_report kr = {
384 .kr_type = KUBSAN_OVERFLOW,
385 .kr_src = &data->d_src,
386 .kr_overflow = { data, lhs, rhs, '-' },
387 };
388
389 kubsan_defer_report(&kr);
390 }
391
392 void
__ubsan_handle_type_mismatch_v1(struct type_mismatch_data * data,unsigned long ptr)393 __ubsan_handle_type_mismatch_v1(struct type_mismatch_data *data,
394 unsigned long ptr)
395 {
396 struct kubsan_report kr = {
397 .kr_type = KUBSAN_TYPE_MISMATCH,
398 .kr_src = &data->d_src,
399 .kr_type_mismatch = { data, ptr },
400 };
401
402 kubsan_defer_report(&kr);
403 }
404
405 /*
406 * Allocate storage for reports and schedule the reporter.
407 * Must be called as early on as possible in order to catch undefined behavior
408 * during boot.
409 */
410 void
kubsan_init(void)411 kubsan_init(void)
412 {
413 kubsan_reports = (void *)uvm_pageboot_alloc(
414 sizeof(struct kubsan_report) * KUBSAN_NSLOTS);
415 kubsan_cold = 0;
416
417 timeout_add_msec(&kubsan_timo, KUBSAN_INTERVAL);
418 }
419
420 int64_t
kubsan_deserialize_int(struct type_descriptor * typ,unsigned long val)421 kubsan_deserialize_int(struct type_descriptor *typ, unsigned long val)
422 {
423 switch (NBITS(typ)) {
424 case 8:
425 return ((int8_t)val);
426 case 16:
427 return ((int16_t)val);
428 case 32:
429 return ((int32_t)val);
430 case 64:
431 default:
432 return ((int64_t)val);
433 }
434 }
435
436 uint64_t
kubsan_deserialize_uint(struct type_descriptor * typ,unsigned long val)437 kubsan_deserialize_uint(struct type_descriptor *typ, unsigned long val)
438 {
439 switch (NBITS(typ)) {
440 case 8:
441 return ((uint8_t)val);
442 case 16:
443 return ((uint16_t)val);
444 case 32:
445 return ((uint32_t)val);
446 case 64:
447 default:
448 return ((uint64_t)val);
449 }
450 }
451
452 void
kubsan_defer_report(struct kubsan_report * kr)453 kubsan_defer_report(struct kubsan_report *kr)
454 {
455 unsigned int slot;
456
457 if (__predict_false(kubsan_cold == 1) ||
458 kubsan_is_reported(kr->kr_src))
459 return;
460
461 slot = atomic_inc_int_nv(&kubsan_slot) - 1;
462 if (slot >= KUBSAN_NSLOTS) {
463 /*
464 * No slots left, flag source location as not reported and
465 * hope a slot will be available next time.
466 */
467 kubsan_unreport(kr->kr_src);
468 return;
469 }
470
471 memcpy(&kubsan_reports[slot], kr, sizeof(*kr));
472 }
473
474 void
kubsan_format_int(struct type_descriptor * typ,unsigned long val,char * buf,size_t bufsiz)475 kubsan_format_int(struct type_descriptor *typ, unsigned long val,
476 char *buf, size_t bufsiz)
477 {
478 switch (typ->t_kind) {
479 case 0: /* integer */
480 if (SIGNED(typ)) {
481 int64_t i = kubsan_deserialize_int(typ, val);
482 snprintf(buf, bufsiz, "%lld", i);
483 } else {
484 uint64_t u = kubsan_deserialize_uint(typ, val);
485 snprintf(buf, bufsiz, "%llu", u);
486 }
487 break;
488 default:
489 snprintf(buf, bufsiz, "%#x<NaN>", typ->t_kind);
490 }
491 }
492
493 int
kubsan_format_location(const struct source_location * src,char * buf,size_t bufsiz)494 kubsan_format_location(const struct source_location *src, char *buf,
495 size_t bufsiz)
496 {
497 const char *path;
498
499 path = pathstrip(src->sl_filename);
500
501 return snprintf(buf, bufsiz, "%s:%u:%u",
502 path, src->sl_line & ~LOCATION_REPORTED, src->sl_column);
503 }
504
505 int
kubsan_is_reported(struct source_location * src)506 kubsan_is_reported(struct source_location *src)
507 {
508 uint32_t *line = &src->sl_line;
509 uint32_t prev;
510
511 /*
512 * Treat everything as reported when disabled.
513 * Otherwise, new violations would go by unnoticed.
514 */
515 if (__predict_false(kubsan_watch == 0))
516 return (1);
517
518 do {
519 prev = *line;
520 /* If already reported, avoid redundant atomic operation. */
521 if (prev & LOCATION_REPORTED)
522 break;
523 } while (atomic_cas_uint(line, prev, prev | LOCATION_REPORTED) != prev);
524
525 return (prev & LOCATION_REPORTED);
526 }
527
528 const char *
kubsan_kind(uint8_t kind)529 kubsan_kind(uint8_t kind)
530 {
531 static const char *kinds[] = {
532 "load of",
533 "store to",
534 "reference binding to",
535 "member access within",
536 "member call on",
537 "constructor call on",
538 "downcast of",
539 "downcast of",
540 "upcast of",
541 "cast to virtual base of",
542 "_Nonnull binding to",
543 "dynamic operation on"
544 };
545
546 if (kind >= nitems(kinds))
547 return ("?");
548
549 return (kinds[kind]);
550 }
551
552 void
kubsan_report(void * arg)553 kubsan_report(void *arg)
554 {
555 char bloc[LOCATION_BUFSIZ];
556 char blhs[NUMBER_BUFSIZ];
557 char brhs[NUMBER_BUFSIZ];
558 struct kubsan_report *kr;
559 unsigned int nslots;
560 unsigned int i = 0;
561
562 again:
563 nslots = kubsan_slot;
564 if (nslots == 0)
565 goto done;
566 if (nslots > KUBSAN_NSLOTS)
567 nslots = KUBSAN_NSLOTS;
568
569 for (; i < nslots; i++) {
570 kr = &kubsan_reports[i];
571
572 kubsan_format_location(kr->kr_src, bloc, sizeof(bloc));
573 switch (kr->kr_type) {
574 case KUBSAN_FLOAT_CAST_OVERFLOW: {
575 const struct float_cast_overflow_data *data =
576 kr->kr_float_cast_overflow.v_data;
577
578 kubsan_format_int(data->d_ftype,
579 kr->kr_float_cast_overflow.v_val,
580 blhs, sizeof(blhs));
581 printf("kubsan: %s: %s of type %s is outside the range "
582 "of representable values of type %s\n",
583 bloc, blhs, data->d_ftype->t_name,
584 data->d_ttype->t_name);
585 break;
586 }
587
588 case KUBSAN_INVALID_BUILTIN: {
589 const struct invalid_builtin_data *data =
590 kr->kr_invalid_builtin.v_data;
591
592 printf("kubsan: %s: invalid builtin: passing zero to "
593 "%s, which is not a valid argument\n",
594 bloc, kubsan_kind(data->d_kind));
595 break;
596 }
597
598 case KUBSAN_INVALID_VALUE: {
599 const struct invalid_value_data *data =
600 kr->kr_invalid_value.v_data;
601
602 kubsan_format_int(data->d_type,
603 kr->kr_invalid_value.v_val, blhs, sizeof(blhs));
604 printf("kubsan: %s: load invalid value: load of value "
605 "%s is not a valid value for type %s\n",
606 bloc, blhs, data->d_type->t_name);
607 break;
608 }
609
610 case KUBSAN_NEGATE_OVERFLOW: {
611 const struct overflow_data *data =
612 kr->kr_negate_overflow.v_data;
613
614 kubsan_format_int(data->d_type,
615 kr->kr_negate_overflow.v_val, blhs, sizeof(blhs));
616 printf("kubsan: %s: negate overflow: negation of %s "
617 "cannot be represented in type %s\n",
618 bloc, blhs, data->d_type->t_name);
619 break;
620 }
621
622 case KUBSAN_NONNULL_ARG: {
623 const struct nonnull_arg_data *data =
624 kr->kr_nonnull_arg.v_data;
625
626 if (data->d_attr_src.sl_filename)
627 kubsan_format_location(&data->d_attr_src,
628 blhs, sizeof(blhs));
629 else
630 blhs[0] = '\0';
631
632 printf("kubsan: %s: null pointer passed as argument "
633 "%d, which is declared to never be null%s%s\n",
634 bloc, data->d_idx,
635 blhs[0] ? "nonnull specified in " : "", blhs);
636 break;
637 }
638
639 case KUBSAN_OUT_OF_BOUNDS: {
640 const struct out_of_bounds_data *data =
641 kr->kr_out_of_bounds.v_data;
642
643 kubsan_format_int(data->d_itype,
644 kr->kr_out_of_bounds.v_idx, blhs, sizeof(blhs));
645 printf("kubsan: %s: out of bounds: index %s is out of "
646 "range for type %s\n",
647 bloc, blhs, data->d_atype->t_name);
648 break;
649 }
650
651 case KUBSAN_OVERFLOW: {
652 const struct overflow_data *data =
653 kr->kr_overflow.v_data;
654
655 kubsan_format_int(data->d_type,
656 kr->kr_overflow.v_lhs, blhs, sizeof(blhs));
657 kubsan_format_int(data->d_type,
658 kr->kr_overflow.v_rhs, brhs, sizeof(brhs));
659 printf("kubsan: %s: %s integer overflow: %s %c %s "
660 "cannot be represented in type %s\n",
661 bloc, SIGNED(data->d_type) ? "signed" : "unsigned",
662 blhs, kr->kr_overflow.v_op, brhs,
663 data->d_type->t_name);
664 break;
665 }
666
667 case KUBSAN_POINTER_OVERFLOW:
668 printf("kubsan: %s: pointer overflow: pointer "
669 "expression with base %#lx overflowed to %#lx\n",
670 bloc, kr->kr_pointer_overflow.v_base,
671 kr->kr_pointer_overflow.v_res);
672 break;
673
674 case KUBSAN_SHIFT_OUT_OF_BOUNDS: {
675 const struct shift_out_of_bounds_data *data =
676 kr->kr_shift_out_of_bounds.v_data;
677 unsigned long lhs = kr->kr_shift_out_of_bounds.v_lhs;
678 unsigned long rhs = kr->kr_shift_out_of_bounds.v_rhs;
679
680 kubsan_format_int(data->d_ltype, lhs, blhs,
681 sizeof(blhs));
682 kubsan_format_int(data->d_rtype, rhs, brhs,
683 sizeof(brhs));
684 if (is_negative(data->d_rtype, rhs))
685 printf("kubsan: %s: shift: shift exponent %s "
686 "is negative\n",
687 bloc, brhs);
688 else if (is_shift_exponent_too_large(data->d_rtype, rhs))
689 printf("kubsan: %s: shift: shift exponent %s "
690 "is too large for %u-bit type\n",
691 bloc, brhs, NBITS(data->d_rtype));
692 else if (is_negative(data->d_ltype, lhs))
693 printf("kubsan: %s: shift: left shift of "
694 "negative value %s\n",
695 bloc, blhs);
696 else
697 printf("kubsan: %s: shift: left shift of %s by "
698 "%s places cannot be represented in type "
699 "%s\n",
700 bloc, blhs, brhs, data->d_ltype->t_name);
701 break;
702 }
703
704 case KUBSAN_TYPE_MISMATCH: {
705 const struct type_mismatch_data *data =
706 kr->kr_type_mismatch.v_data;
707 unsigned long ptr = kr->kr_type_mismatch.v_ptr;
708 unsigned long align = 1UL << data->d_align;
709
710 if (ptr == 0UL)
711 printf("kubsan: %s: type mismatch: %s null "
712 "pointer of type %s\n",
713 bloc, kubsan_kind(data->d_kind),
714 data->d_type->t_name);
715 else if (ptr & (align - 1))
716 printf("kubsan: %s: type mismatch: %s "
717 "misaligned address %p for type %s which "
718 "requires %lu byte alignment\n",
719 bloc, kubsan_kind(data->d_kind),
720 (void *)ptr, data->d_type->t_name, align);
721 else
722 printf("kubsan: %s: type mismatch: %s address "
723 "%p with insufficient space for an object "
724 "of type %s\n",
725 bloc, kubsan_kind(data->d_kind),
726 (void *)ptr, data->d_type->t_name);
727 break;
728 }
729
730 case KUBSAN_UNREACHABLE:
731 printf("kubsan: %s: unreachable: calling "
732 "__builtin_unreachable()\n",
733 bloc);
734 break;
735 }
736
737 #ifdef DDB
738 if (kubsan_watch == 2)
739 db_enter();
740 #endif
741 }
742
743 /* New reports can arrive at any time. */
744 if (atomic_cas_uint(&kubsan_slot, nslots, 0) != nslots) {
745 if (nslots < KUBSAN_NSLOTS)
746 goto again;
747 atomic_swap_uint(&kubsan_slot, 0);
748 }
749
750 done:
751 timeout_add_msec(&kubsan_timo, KUBSAN_INTERVAL);
752 }
753
754 void
kubsan_unreport(struct source_location * src)755 kubsan_unreport(struct source_location *src)
756 {
757 uint32_t *line = &src->sl_line;
758
759 atomic_clearbits_int(line, LOCATION_REPORTED);
760 }
761
762 static int
is_negative(struct type_descriptor * typ,unsigned long val)763 is_negative(struct type_descriptor *typ, unsigned long val)
764 {
765 return (SIGNED(typ) && kubsan_deserialize_int(typ, val) < 0);
766 }
767
768 static int
is_shift_exponent_too_large(struct type_descriptor * typ,unsigned long val)769 is_shift_exponent_too_large(struct type_descriptor *typ, unsigned long val)
770 {
771 return (kubsan_deserialize_int(typ, val) >= NBITS(typ));
772 }
773
774 /*
775 * A source location is an absolute path making reports quite long.
776 * Instead, use everything after the first /sys/ segment as the path.
777 */
778 static const char *
pathstrip(const char * path)779 pathstrip(const char *path)
780 {
781 const char *needle = "/sys/";
782 size_t i, j;
783
784 for (i = j = 0; path[i] != '\0'; i++) {
785 if (path[i] != needle[j]) {
786 j = 0;
787 continue;
788 }
789
790 if (needle[++j] == '\0')
791 return path + i + 1;
792 }
793
794 return path;
795 }
796