xref: /openbsd-src/sys/kern/subr_kubsan.c (revision 202e2461a0d9a8e3abe70503423141a09ea1c4f4)
1*202e2461Smbuhl /*	$OpenBSD: subr_kubsan.c,v 1.13 2024/09/06 13:31:59 mbuhl Exp $	*/
228673518Santon 
328673518Santon /*
428673518Santon  * Copyright (c) 2019 Anton Lindqvist <anton@openbsd.org>
528673518Santon  *
628673518Santon  * Permission to use, copy, modify, and distribute this software for any
728673518Santon  * purpose with or without fee is hereby granted, provided that the above
828673518Santon  * copyright notice and this permission notice appear in all copies.
928673518Santon  *
1028673518Santon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1128673518Santon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1228673518Santon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1328673518Santon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1428673518Santon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1528673518Santon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1628673518Santon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1728673518Santon  */
1828673518Santon 
19c01f5a04Santon #include <sys/types.h>
2028673518Santon #include <sys/param.h>
2128673518Santon #include <sys/atomic.h>
2228673518Santon #include <sys/syslimits.h>
2328673518Santon #include <sys/systm.h>
24c01f5a04Santon #include <sys/timeout.h>
25c4bd2261Santon 
26c4bd2261Santon #include <uvm/uvm_extern.h>
27c4bd2261Santon 
28c01f5a04Santon #define KUBSAN_INTERVAL	100	/* report interval in msec */
29c4bd2261Santon #define KUBSAN_NSLOTS	32
3028673518Santon 
3128673518Santon #define NUMBER_BUFSIZ		32
3228673518Santon #define LOCATION_BUFSIZ		(PATH_MAX + 32)	/* filename:line:column */
331827c4f9Santon #define LOCATION_REPORTED	(1U << 31)
3428673518Santon 
3528673518Santon #define NBITS(typ)	(1 << ((typ)->t_info >> 1))
3628673518Santon #define SIGNED(typ)	((typ)->t_info & 1)
3728673518Santon 
38c4bd2261Santon struct kubsan_report {
39c4bd2261Santon 	enum {
40da9aa09cSanton 		KUBSAN_FLOAT_CAST_OVERFLOW,
41*202e2461Smbuhl 		KUBSAN_INVALID_BUILTIN,
42c4bd2261Santon 		KUBSAN_INVALID_VALUE,
43c4bd2261Santon 		KUBSAN_NEGATE_OVERFLOW,
44c4bd2261Santon 		KUBSAN_NONNULL_ARG,
45c4bd2261Santon 		KUBSAN_OUT_OF_BOUNDS,
46c4bd2261Santon 		KUBSAN_OVERFLOW,
47c4bd2261Santon 		KUBSAN_POINTER_OVERFLOW,
48c4bd2261Santon 		KUBSAN_SHIFT_OUT_OF_BOUNDS,
49c4bd2261Santon 		KUBSAN_TYPE_MISMATCH,
50c4bd2261Santon 		KUBSAN_UNREACHABLE,
51c4bd2261Santon 	} kr_type;
52c4bd2261Santon 
53c4bd2261Santon 	struct source_location *kr_src;
54c4bd2261Santon 
55c4bd2261Santon 	union {
56c4bd2261Santon 		struct {
57da9aa09cSanton 			const struct float_cast_overflow_data *v_data;
58da9aa09cSanton 			unsigned long v_val;
59da9aa09cSanton 		} v_float_cast_overflow;
60da9aa09cSanton 
61da9aa09cSanton 		struct {
62*202e2461Smbuhl 			const struct invalid_builtin_data *v_data;
63*202e2461Smbuhl 		} v_invalid_builtin;
64*202e2461Smbuhl 
65*202e2461Smbuhl 		struct {
66c4bd2261Santon 			const struct invalid_value_data *v_data;
67c4bd2261Santon 			unsigned long v_val;
68c4bd2261Santon 		} v_invalid_value;
69c4bd2261Santon 
70c4bd2261Santon 		struct {
71c4bd2261Santon 			const struct overflow_data *v_data;
72c4bd2261Santon 			unsigned int v_val;
73c4bd2261Santon 		} v_negate_overflow;
74c4bd2261Santon 
75c4bd2261Santon 		struct {
76c4bd2261Santon 			const struct nonnull_arg_data *v_data;
77c4bd2261Santon 		} v_nonnull_arg;
78c4bd2261Santon 
79c4bd2261Santon 		struct {
80c4bd2261Santon 			const struct out_of_bounds_data *v_data;
81c4bd2261Santon 			unsigned int v_idx;
82c4bd2261Santon 		} v_out_of_bounds;
83c4bd2261Santon 
84c4bd2261Santon 		struct {
85c4bd2261Santon 			const struct overflow_data *v_data;
86c4bd2261Santon 			unsigned long v_lhs;
87c4bd2261Santon 			unsigned long v_rhs;
88c4bd2261Santon 			char v_op;
89c4bd2261Santon 		} v_overflow;
90c4bd2261Santon 
91c4bd2261Santon 		struct {
92c4bd2261Santon 			const struct pointer_overflow_data *v_data;
93c4bd2261Santon 			unsigned long v_base;
94c4bd2261Santon 			unsigned long v_res;
95c4bd2261Santon 		} v_pointer_overflow;
96c4bd2261Santon 
97c4bd2261Santon 		struct {
98c4bd2261Santon 			const struct shift_out_of_bounds_data *v_data;
99c4bd2261Santon 			unsigned long v_lhs;
100c4bd2261Santon 			unsigned long v_rhs;
101c4bd2261Santon 		} v_shift_out_of_bounds;
102c4bd2261Santon 
103c4bd2261Santon 		struct {
104c4bd2261Santon 			const struct type_mismatch_data *v_data;
105c4bd2261Santon 			unsigned long v_ptr;
106c4bd2261Santon 		} v_type_mismatch;
107c4bd2261Santon 	} kr_u;
108c4bd2261Santon };
109da9aa09cSanton #define kr_float_cast_overflow		kr_u.v_float_cast_overflow
110*202e2461Smbuhl #define kr_invalid_builtin		kr_u.v_invalid_builtin
111c4bd2261Santon #define kr_invalid_value		kr_u.v_invalid_value
112c4bd2261Santon #define kr_negate_overflow		kr_u.v_negate_overflow
113c4bd2261Santon #define kr_nonnull_arg			kr_u.v_nonnull_arg
114c4bd2261Santon #define kr_out_of_bounds		kr_u.v_out_of_bounds
115c4bd2261Santon #define kr_overflow			kr_u.v_overflow
116c4bd2261Santon #define kr_pointer_overflow		kr_u.v_pointer_overflow
117c4bd2261Santon #define kr_shift_out_of_bounds		kr_u.v_shift_out_of_bounds
118c4bd2261Santon #define kr_type_mismatch		kr_u.v_type_mismatch
119c4bd2261Santon 
12028673518Santon struct type_descriptor {
12128673518Santon 	uint16_t t_kind;
12228673518Santon 	uint16_t t_info;
12328673518Santon 	char t_name[1];	/* type name as variable length array */
12428673518Santon };
12528673518Santon 
12628673518Santon struct source_location {
12728673518Santon 	const char *sl_filename;
12828673518Santon 	uint32_t sl_line;
12928673518Santon 	uint32_t sl_column;
13028673518Santon };
13128673518Santon 
132da9aa09cSanton struct float_cast_overflow_data {
133da9aa09cSanton 	struct source_location d_src;
134da9aa09cSanton 	struct type_descriptor *d_ftype;	/* from type */
135da9aa09cSanton 	struct type_descriptor *d_ttype;	/* to type */
136da9aa09cSanton };
137da9aa09cSanton 
138*202e2461Smbuhl struct invalid_builtin_data {
139*202e2461Smbuhl 	struct source_location d_src;
140*202e2461Smbuhl 	uint8_t d_kind;
141*202e2461Smbuhl };
142*202e2461Smbuhl 
14328673518Santon struct invalid_value_data {
14428673518Santon 	struct source_location d_src;
14528673518Santon 	struct type_descriptor *d_type;
14628673518Santon };
14728673518Santon 
1483241747bSanton struct nonnull_arg_data {
1493241747bSanton 	struct source_location d_src;
1503241747bSanton 	struct source_location d_attr_src;	/* __attribute__ location */
1513241747bSanton 	int d_idx;
1523241747bSanton };
1533241747bSanton 
15428673518Santon struct out_of_bounds_data {
15528673518Santon 	struct source_location d_src;
15628673518Santon 	struct type_descriptor *d_atype;	/* array type */
15728673518Santon 	struct type_descriptor *d_itype;	/* index type */
15828673518Santon };
15928673518Santon 
16028673518Santon struct overflow_data {
16128673518Santon 	struct source_location d_src;
16228673518Santon 	struct type_descriptor *d_type;
16328673518Santon };
16428673518Santon 
16528673518Santon struct pointer_overflow_data {
16628673518Santon 	struct source_location d_src;
16728673518Santon };
16828673518Santon 
16928673518Santon struct shift_out_of_bounds_data {
17028673518Santon 	struct source_location d_src;
17128673518Santon 	struct type_descriptor *d_ltype;
17228673518Santon 	struct type_descriptor *d_rtype;
17328673518Santon };
17428673518Santon 
175270b1e82Santon struct type_mismatch_data {
17628673518Santon 	struct source_location d_src;
17728673518Santon 	struct type_descriptor *d_type;
17828673518Santon 	uint8_t d_align;	/* log2 alignment */
17928673518Santon 	uint8_t d_kind;
18028673518Santon };
18128673518Santon 
182d2e0f60bSanton struct unreachable_data {
183d2e0f60bSanton 	struct source_location d_src;
184d2e0f60bSanton };
185d2e0f60bSanton 
18628673518Santon int64_t		 kubsan_deserialize_int(struct type_descriptor *,
18728673518Santon 		    unsigned long);
18828673518Santon uint64_t	 kubsan_deserialize_uint(struct type_descriptor *,
18928673518Santon 		    unsigned long);
190c4bd2261Santon void		 kubsan_defer_report(struct kubsan_report *);
19128673518Santon void		 kubsan_format_int(struct type_descriptor *, unsigned long,
19228673518Santon 		    char *, size_t);
193c4bd2261Santon int		 kubsan_format_location(const struct source_location *, char *,
19428673518Santon 		    size_t);
19528673518Santon int		 kubsan_is_reported(struct source_location *);
19628673518Santon const char	*kubsan_kind(uint8_t);
197c4bd2261Santon void		 kubsan_report(void *);
198c4bd2261Santon void		 kubsan_unreport(struct source_location *);
19928673518Santon 
20028673518Santon static int	is_negative(struct type_descriptor *, unsigned long);
20128673518Santon static int	is_shift_exponent_too_large(struct type_descriptor *,
20228673518Santon 		    unsigned long);
20328673518Santon 
204a15e6dd3Santon static const char	*pathstrip(const char *);
205a15e6dd3Santon 
20628673518Santon #ifdef KUBSAN_WATCH
20728673518Santon int kubsan_watch = 2;
20828673518Santon #else
20928673518Santon int kubsan_watch = 1;
21028673518Santon #endif
21128673518Santon 
212c4bd2261Santon struct kubsan_report	*kubsan_reports = NULL;
213c01f5a04Santon struct timeout		 kubsan_timo = TIMEOUT_INITIALIZER(kubsan_report, NULL);
214c4bd2261Santon unsigned int		 kubsan_slot = 0;
21506389e20Santon int			 kubsan_cold = 1;
216c4bd2261Santon 
21728673518Santon /*
21828673518Santon  * Compiling the kernel with `-fsanitize=undefined' will cause the following
21928673518Santon  * functions to be called when a sanitizer detects undefined behavior.
22028673518Santon  * Some sanitizers are omitted since they are only applicable to C++.
22128673518Santon  *
22228673518Santon  * Every __ubsan_*() sanitizer function also has a corresponding
22328673518Santon  * __ubsan_*_abort() function as part of the ABI provided by Clang.
22428673518Santon  * But, since the kernel never is compiled with `fno-sanitize-recover' for
22528673518Santon  * obvious reasons, they are also omitted.
22628673518Santon  */
22728673518Santon 
22828673518Santon void
22928673518Santon __ubsan_handle_add_overflow(struct overflow_data *data,
23028673518Santon     unsigned long lhs, unsigned long rhs)
23128673518Santon {
232c4bd2261Santon 	struct kubsan_report kr = {
233c4bd2261Santon 		.kr_type		= KUBSAN_OVERFLOW,
234c4bd2261Santon 		.kr_src			= &data->d_src,
235c4bd2261Santon 		.kr_overflow		= { data, lhs, rhs, '+' },
236c4bd2261Santon 	};
237c4bd2261Santon 
238c4bd2261Santon 	kubsan_defer_report(&kr);
23928673518Santon }
24028673518Santon 
24128673518Santon void
24228673518Santon __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
24328673518Santon {
244c4bd2261Santon 	struct kubsan_report kr = {
245c4bd2261Santon 		.kr_type		= KUBSAN_UNREACHABLE,
246c4bd2261Santon 		.kr_src			= &data->d_src,
247c4bd2261Santon 	};
248c4bd2261Santon 
249c4bd2261Santon 	kubsan_defer_report(&kr);
25028673518Santon }
25128673518Santon 
25228673518Santon void
25328673518Santon __ubsan_handle_divrem_overflow(struct overflow_data *data,
25428673518Santon     unsigned long lhs, unsigned long rhs)
25528673518Santon {
256c4bd2261Santon 	struct kubsan_report kr = {
257c4bd2261Santon 		.kr_type		= KUBSAN_OVERFLOW,
258c4bd2261Santon 		.kr_src			= &data->d_src,
259c4bd2261Santon 		.kr_overflow		= { data, lhs, rhs, '/' },
260c4bd2261Santon 	};
261c4bd2261Santon 
262c4bd2261Santon 	kubsan_defer_report(&kr);
26328673518Santon }
26428673518Santon 
26528673518Santon void
266da9aa09cSanton __ubsan_handle_float_cast_overflow(struct float_cast_overflow_data *data,
267da9aa09cSanton     unsigned long val)
268da9aa09cSanton {
269da9aa09cSanton 	struct kubsan_report kr = {
270da9aa09cSanton 		.kr_type		= KUBSAN_FLOAT_CAST_OVERFLOW,
271da9aa09cSanton 		.kr_src			= &data->d_src,
272da9aa09cSanton 		.kr_float_cast_overflow	= { data, val },
273da9aa09cSanton 	};
274da9aa09cSanton 
275da9aa09cSanton 	kubsan_defer_report(&kr);
276da9aa09cSanton }
277da9aa09cSanton 
278da9aa09cSanton void
279*202e2461Smbuhl __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
280*202e2461Smbuhl {
281*202e2461Smbuhl 	struct kubsan_report kr = {
282*202e2461Smbuhl 		.kr_type		= KUBSAN_INVALID_VALUE,
283*202e2461Smbuhl 		.kr_src			= &data->d_src,
284*202e2461Smbuhl 		.kr_invalid_builtin	= { data },
285*202e2461Smbuhl 	};
286*202e2461Smbuhl 
287*202e2461Smbuhl 	kubsan_defer_report(&kr);
288*202e2461Smbuhl }
289*202e2461Smbuhl 
290*202e2461Smbuhl void
29128673518Santon __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
29228673518Santon     unsigned long val)
29328673518Santon {
294c4bd2261Santon 	struct kubsan_report kr = {
295c4bd2261Santon 		.kr_type		= KUBSAN_INVALID_VALUE,
296c4bd2261Santon 		.kr_src			= &data->d_src,
297c4bd2261Santon 		.kr_invalid_value	= { data, val },
298c4bd2261Santon 	};
299c4bd2261Santon 
300c4bd2261Santon 	kubsan_defer_report(&kr);
30128673518Santon }
30228673518Santon 
30328673518Santon void
3043241747bSanton __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
3053241747bSanton {
306c4bd2261Santon 	struct kubsan_report kr = {
307c4bd2261Santon 		.kr_type		= KUBSAN_NONNULL_ARG,
308c4bd2261Santon 		.kr_src			= &data->d_src,
309c4bd2261Santon 		.kr_nonnull_arg		= { data },
310c4bd2261Santon 	};
311c4bd2261Santon 
312c4bd2261Santon 	kubsan_defer_report(&kr);
3133241747bSanton }
3143241747bSanton 
3153241747bSanton void
31628673518Santon __ubsan_handle_mul_overflow(struct overflow_data *data,
31728673518Santon     unsigned long lhs, unsigned long rhs)
31828673518Santon {
319c4bd2261Santon 	struct kubsan_report kr = {
320c4bd2261Santon 		.kr_type		= KUBSAN_OVERFLOW,
321c4bd2261Santon 		.kr_src			= &data->d_src,
322c4bd2261Santon 		.kr_overflow		= { data, lhs, rhs, '*' },
323c4bd2261Santon 	};
324c4bd2261Santon 
325c4bd2261Santon 	kubsan_defer_report(&kr);
32628673518Santon }
32728673518Santon 
32828673518Santon void
32928673518Santon __ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long val)
33028673518Santon {
331c4bd2261Santon 	struct kubsan_report kr = {
332c4bd2261Santon 		.kr_type		= KUBSAN_NEGATE_OVERFLOW,
333c4bd2261Santon 		.kr_src			= &data->d_src,
334c4bd2261Santon 		.kr_negate_overflow	= { data, val },
335c4bd2261Santon 	};
336c4bd2261Santon 
337c4bd2261Santon 	kubsan_defer_report(&kr);
33828673518Santon }
33928673518Santon 
34028673518Santon void
34128673518Santon __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
34228673518Santon     unsigned long idx)
34328673518Santon {
344c4bd2261Santon 	struct kubsan_report kr = {
345c4bd2261Santon 		.kr_type		= KUBSAN_OUT_OF_BOUNDS,
346c4bd2261Santon 		.kr_src			= &data->d_src,
347c4bd2261Santon 		.kr_out_of_bounds	= { data, idx },
348c4bd2261Santon 	};
349c4bd2261Santon 
350c4bd2261Santon 	kubsan_defer_report(&kr);
35128673518Santon }
35228673518Santon 
35328673518Santon void
35428673518Santon __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
35528673518Santon     unsigned long base, unsigned long res)
35628673518Santon {
357c4bd2261Santon 	struct kubsan_report kr = {
358c4bd2261Santon 		.kr_type		= KUBSAN_POINTER_OVERFLOW,
359c4bd2261Santon 		.kr_src			= &data->d_src,
360c4bd2261Santon 		.kr_pointer_overflow	= { data, base, res },
361c4bd2261Santon 	};
362c4bd2261Santon 
363c4bd2261Santon 	kubsan_defer_report(&kr);
36428673518Santon }
36528673518Santon 
36628673518Santon void
36728673518Santon __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
36828673518Santon     unsigned long lhs, unsigned long rhs)
36928673518Santon {
370c4bd2261Santon 	struct kubsan_report kr = {
371c4bd2261Santon 		.kr_type		= KUBSAN_SHIFT_OUT_OF_BOUNDS,
372c4bd2261Santon 		.kr_src			= &data->d_src,
373c4bd2261Santon 		.kr_shift_out_of_bounds	= { data, lhs, rhs },
374c4bd2261Santon 	};
375c4bd2261Santon 
376c4bd2261Santon 	kubsan_defer_report(&kr);
37728673518Santon }
37828673518Santon 
37928673518Santon void
38028673518Santon __ubsan_handle_sub_overflow(struct overflow_data *data,
38128673518Santon     unsigned long lhs, unsigned long rhs)
38228673518Santon {
383c4bd2261Santon 	struct kubsan_report kr = {
384c4bd2261Santon 		.kr_type		= KUBSAN_OVERFLOW,
385c4bd2261Santon 		.kr_src			= &data->d_src,
386c4bd2261Santon 		.kr_overflow		= { data, lhs, rhs, '-' },
387c4bd2261Santon 	};
388c4bd2261Santon 
389c4bd2261Santon 	kubsan_defer_report(&kr);
39028673518Santon }
39128673518Santon 
39228673518Santon void
393270b1e82Santon __ubsan_handle_type_mismatch_v1(struct type_mismatch_data *data,
39428673518Santon     unsigned long ptr)
39528673518Santon {
396c4bd2261Santon 	struct kubsan_report kr = {
397c4bd2261Santon 		.kr_type		= KUBSAN_TYPE_MISMATCH,
398c4bd2261Santon 		.kr_src			= &data->d_src,
399c4bd2261Santon 		.kr_type_mismatch	= { data, ptr },
400c4bd2261Santon 	};
401c4bd2261Santon 
402c4bd2261Santon 	kubsan_defer_report(&kr);
40328673518Santon }
40428673518Santon 
4053241747bSanton /*
406c01f5a04Santon  * Allocate storage for reports and schedule the reporter.
407c01f5a04Santon  * Must be called as early on as possible in order to catch undefined behavior
408c01f5a04Santon  * during boot.
4093241747bSanton  */
4103241747bSanton void
411c4bd2261Santon kubsan_init(void)
41228673518Santon {
413c4bd2261Santon 	kubsan_reports = (void *)uvm_pageboot_alloc(
414c4bd2261Santon 	    sizeof(struct kubsan_report) * KUBSAN_NSLOTS);
41506389e20Santon 	kubsan_cold = 0;
41628673518Santon 
417c01f5a04Santon 	timeout_add_msec(&kubsan_timo, KUBSAN_INTERVAL);
41828673518Santon }
41928673518Santon 
42028673518Santon int64_t
42128673518Santon kubsan_deserialize_int(struct type_descriptor *typ, unsigned long val)
42228673518Santon {
42328673518Santon 	switch (NBITS(typ)) {
42428673518Santon 	case 8:
42528673518Santon 		return ((int8_t)val);
42628673518Santon 	case 16:
42728673518Santon 		return ((int16_t)val);
42828673518Santon 	case 32:
42928673518Santon 		return ((int32_t)val);
43028673518Santon 	case 64:
43128673518Santon 	default:
43228673518Santon 		return ((int64_t)val);
43328673518Santon 	}
43428673518Santon }
43528673518Santon 
43628673518Santon uint64_t
43728673518Santon kubsan_deserialize_uint(struct type_descriptor *typ, unsigned long val)
43828673518Santon {
43928673518Santon 	switch (NBITS(typ)) {
44028673518Santon 	case 8:
44128673518Santon 		return ((uint8_t)val);
44228673518Santon 	case 16:
44328673518Santon 		return ((uint16_t)val);
44428673518Santon 	case 32:
44528673518Santon 		return ((uint32_t)val);
44628673518Santon 	case 64:
44728673518Santon 	default:
44828673518Santon 		return ((uint64_t)val);
44928673518Santon 	}
45028673518Santon }
45128673518Santon 
45228673518Santon void
453c4bd2261Santon kubsan_defer_report(struct kubsan_report *kr)
454c4bd2261Santon {
455c4bd2261Santon 	unsigned int slot;
456c4bd2261Santon 
45706389e20Santon 	if (__predict_false(kubsan_cold == 1) ||
458c4bd2261Santon 	    kubsan_is_reported(kr->kr_src))
459c4bd2261Santon 		return;
460c4bd2261Santon 
461c4bd2261Santon 	slot = atomic_inc_int_nv(&kubsan_slot) - 1;
462c4bd2261Santon 	if (slot >= KUBSAN_NSLOTS) {
463c4bd2261Santon 		/*
464c4bd2261Santon 		 * No slots left, flag source location as not reported and
465c4bd2261Santon 		 * hope a slot will be available next time.
466c4bd2261Santon 		 */
467c4bd2261Santon 		kubsan_unreport(kr->kr_src);
468c4bd2261Santon 		return;
469c4bd2261Santon 	}
470c4bd2261Santon 
471c4bd2261Santon 	memcpy(&kubsan_reports[slot], kr, sizeof(*kr));
472c4bd2261Santon }
473c4bd2261Santon 
474c4bd2261Santon void
47528673518Santon kubsan_format_int(struct type_descriptor *typ, unsigned long val,
47628673518Santon     char *buf, size_t bufsiz)
47728673518Santon {
47828673518Santon 	switch (typ->t_kind) {
47928673518Santon 	case 0:	/* integer */
48028673518Santon 		if (SIGNED(typ)) {
48128673518Santon 			int64_t i = kubsan_deserialize_int(typ, val);
48228673518Santon 			snprintf(buf, bufsiz, "%lld", i);
48328673518Santon 		} else {
48428673518Santon 			uint64_t u = kubsan_deserialize_uint(typ, val);
48528673518Santon 			snprintf(buf, bufsiz, "%llu", u);
48628673518Santon 		}
48728673518Santon 		break;
48828673518Santon 	default:
48928673518Santon 		snprintf(buf, bufsiz, "%#x<NaN>", typ->t_kind);
49028673518Santon 	}
49128673518Santon }
49228673518Santon 
4933241747bSanton int
494c4bd2261Santon kubsan_format_location(const struct source_location *src, char *buf,
49528673518Santon     size_t bufsiz)
49628673518Santon {
497a15e6dd3Santon 	const char *path;
498a15e6dd3Santon 
499a15e6dd3Santon 	path = pathstrip(src->sl_filename);
500a15e6dd3Santon 
5013241747bSanton 	return snprintf(buf, bufsiz, "%s:%u:%u",
502a15e6dd3Santon 	    path, src->sl_line & ~LOCATION_REPORTED, src->sl_column);
50328673518Santon }
50428673518Santon 
50528673518Santon int
50628673518Santon kubsan_is_reported(struct source_location *src)
50728673518Santon {
50828673518Santon 	uint32_t *line = &src->sl_line;
50928673518Santon 	uint32_t prev;
51028673518Santon 
51128673518Santon 	/*
51228673518Santon 	 * Treat everything as reported when disabled.
51328673518Santon 	 * Otherwise, new violations would go by unnoticed.
51428673518Santon 	 */
51528673518Santon 	if (__predict_false(kubsan_watch == 0))
51628673518Santon 		return (1);
51728673518Santon 
51828673518Santon 	do {
51928673518Santon 		prev = *line;
52028673518Santon 		/* If already reported, avoid redundant atomic operation. */
52128673518Santon 		if (prev & LOCATION_REPORTED)
52228673518Santon 			break;
52328673518Santon 	} while (atomic_cas_uint(line, prev, prev | LOCATION_REPORTED) != prev);
52428673518Santon 
52528673518Santon 	return (prev & LOCATION_REPORTED);
52628673518Santon }
52728673518Santon 
52828673518Santon const char *
52928673518Santon kubsan_kind(uint8_t kind)
53028673518Santon {
53128673518Santon 	static const char *kinds[] = {
53228673518Santon 		"load of",
53328673518Santon 		"store to",
53428673518Santon 		"reference binding to",
53528673518Santon 		"member access within",
53628673518Santon 		"member call on",
53728673518Santon 		"constructor call on",
53828673518Santon 		"downcast of",
53928673518Santon 		"downcast of",
54028673518Santon 		"upcast of",
54128673518Santon 		"cast to virtual base of",
54228673518Santon 		"_Nonnull binding to",
54328673518Santon 		"dynamic operation on"
54428673518Santon 	};
54528673518Santon 
54628673518Santon 	if (kind >= nitems(kinds))
54728673518Santon 		return ("?");
54828673518Santon 
54928673518Santon 	return (kinds[kind]);
55028673518Santon }
55128673518Santon 
55228673518Santon void
553c4bd2261Santon kubsan_report(void *arg)
55428673518Santon {
555c4bd2261Santon 	char bloc[LOCATION_BUFSIZ];
556c4bd2261Santon 	char blhs[NUMBER_BUFSIZ];
557c4bd2261Santon 	char brhs[NUMBER_BUFSIZ];
558c4bd2261Santon 	struct kubsan_report *kr;
559c4bd2261Santon 	unsigned int nslots;
560c4bd2261Santon 	unsigned int i = 0;
56128673518Santon 
562c4bd2261Santon again:
563c4bd2261Santon 	nslots = kubsan_slot;
564c01f5a04Santon 	if (nslots == 0)
565c01f5a04Santon 		goto done;
566c4bd2261Santon 	if (nslots > KUBSAN_NSLOTS)
567c4bd2261Santon 		nslots = KUBSAN_NSLOTS;
568c4bd2261Santon 
569c4bd2261Santon 	for (; i < nslots; i++) {
570c4bd2261Santon 		kr = &kubsan_reports[i];
571c4bd2261Santon 
572c4bd2261Santon 		kubsan_format_location(kr->kr_src, bloc, sizeof(bloc));
573c4bd2261Santon 		switch (kr->kr_type) {
574da9aa09cSanton 		case KUBSAN_FLOAT_CAST_OVERFLOW: {
575da9aa09cSanton 			const struct float_cast_overflow_data *data =
576da9aa09cSanton 			    kr->kr_float_cast_overflow.v_data;
577da9aa09cSanton 
578da9aa09cSanton 			kubsan_format_int(data->d_ftype,
579da9aa09cSanton 			    kr->kr_float_cast_overflow.v_val,
580da9aa09cSanton 			    blhs, sizeof(blhs));
581da9aa09cSanton 			printf("kubsan: %s: %s of type %s is outside the range "
582da9aa09cSanton 			    "of representable values of type %s\n",
583da9aa09cSanton 			    bloc, blhs, data->d_ftype->t_name,
584da9aa09cSanton 			    data->d_ttype->t_name);
585da9aa09cSanton 			break;
586da9aa09cSanton 		}
587da9aa09cSanton 
588*202e2461Smbuhl 		case KUBSAN_INVALID_BUILTIN: {
589*202e2461Smbuhl 			const struct invalid_builtin_data *data =
590*202e2461Smbuhl 			    kr->kr_invalid_builtin.v_data;
591*202e2461Smbuhl 
592*202e2461Smbuhl 			printf("kubsan: %s: invalid builtin: passing zero to "
593*202e2461Smbuhl 			    "%s, which is not a valid argument\n",
594*202e2461Smbuhl 			    bloc, kubsan_kind(data->d_kind));
595*202e2461Smbuhl 			break;
596*202e2461Smbuhl 		}
597*202e2461Smbuhl 
598c4bd2261Santon 		case KUBSAN_INVALID_VALUE: {
599c4bd2261Santon 			const struct invalid_value_data *data =
600c4bd2261Santon 			    kr->kr_invalid_value.v_data;
601c4bd2261Santon 
602c4bd2261Santon 			kubsan_format_int(data->d_type,
603c4bd2261Santon 			    kr->kr_invalid_value.v_val, blhs, sizeof(blhs));
604c4bd2261Santon 			printf("kubsan: %s: load invalid value: load of value "
605c4bd2261Santon 			    "%s is not a valid value for type %s\n",
606c4bd2261Santon 			    bloc, blhs, data->d_type->t_name);
607c4bd2261Santon 			break;
608c4bd2261Santon 		}
609c4bd2261Santon 
610c4bd2261Santon 		case KUBSAN_NEGATE_OVERFLOW: {
611c4bd2261Santon 			const struct overflow_data *data =
612c4bd2261Santon 			    kr->kr_negate_overflow.v_data;
613c4bd2261Santon 
614c4bd2261Santon 			kubsan_format_int(data->d_type,
615c4bd2261Santon 			    kr->kr_negate_overflow.v_val, blhs, sizeof(blhs));
616c4bd2261Santon 			printf("kubsan: %s: negate overflow: negation of %s "
617c4bd2261Santon 			    "cannot be represented in type %s\n",
618c4bd2261Santon 			    bloc, blhs, data->d_type->t_name);
619c4bd2261Santon 			break;
620c4bd2261Santon 		}
621c4bd2261Santon 
622c4bd2261Santon 		case KUBSAN_NONNULL_ARG: {
623c4bd2261Santon 			const struct nonnull_arg_data *data =
624c4bd2261Santon 			    kr->kr_nonnull_arg.v_data;
625c4bd2261Santon 
626c4bd2261Santon 			if (data->d_attr_src.sl_filename)
627c4bd2261Santon 				kubsan_format_location(&data->d_attr_src,
628c4bd2261Santon 				    blhs, sizeof(blhs));
629c4bd2261Santon 			else
630c4bd2261Santon 				blhs[0] = '\0';
631c4bd2261Santon 
632c4bd2261Santon 			printf("kubsan: %s: null pointer passed as argument "
633c4bd2261Santon 			    "%d, which is declared to never be null%s%s\n",
634c4bd2261Santon 			    bloc, data->d_idx,
635c4bd2261Santon 			    blhs[0] ? "nonnull specified in " : "", blhs);
636c4bd2261Santon 			break;
637c4bd2261Santon 		}
638c4bd2261Santon 
639c4bd2261Santon 		case KUBSAN_OUT_OF_BOUNDS: {
640c4bd2261Santon 			const struct out_of_bounds_data *data =
641c4bd2261Santon 			    kr->kr_out_of_bounds.v_data;
642c4bd2261Santon 
643c4bd2261Santon 			kubsan_format_int(data->d_itype,
644c4bd2261Santon 			    kr->kr_out_of_bounds.v_idx, blhs, sizeof(blhs));
645c4bd2261Santon 			printf("kubsan: %s: out of bounds: index %s is out of "
646c4bd2261Santon 			    "range for type %s\n",
647c4bd2261Santon 			    bloc, blhs, data->d_atype->t_name);
648c4bd2261Santon 			break;
649c4bd2261Santon 		}
650c4bd2261Santon 
651c4bd2261Santon 		case KUBSAN_OVERFLOW: {
652c4bd2261Santon 			const struct overflow_data *data =
653c4bd2261Santon 			    kr->kr_overflow.v_data;
654c4bd2261Santon 
655c4bd2261Santon 			kubsan_format_int(data->d_type,
656c4bd2261Santon 			    kr->kr_overflow.v_lhs, blhs, sizeof(blhs));
657c4bd2261Santon 			kubsan_format_int(data->d_type,
658c4bd2261Santon 			    kr->kr_overflow.v_rhs, brhs, sizeof(brhs));
659c4bd2261Santon                         printf("kubsan: %s: %s integer overflow: %s %c %s "
660c4bd2261Santon                             "cannot be represented in type %s\n",
661c4bd2261Santon 			    bloc, SIGNED(data->d_type) ? "signed" : "unsigned",
662c4bd2261Santon 			    blhs, kr->kr_overflow.v_op, brhs,
663c4bd2261Santon 			    data->d_type->t_name);
664c4bd2261Santon 			break;
665c4bd2261Santon 		}
666c4bd2261Santon 
667c4bd2261Santon 		case KUBSAN_POINTER_OVERFLOW:
668c4bd2261Santon 			printf("kubsan: %s: pointer overflow: pointer "
669c4bd2261Santon 			    "expression with base %#lx overflowed to %#lx\n",
670c4bd2261Santon 			    bloc, kr->kr_pointer_overflow.v_base,
671c4bd2261Santon 			    kr->kr_pointer_overflow.v_res);
672c4bd2261Santon 			break;
673c4bd2261Santon 
674c4bd2261Santon 		case KUBSAN_SHIFT_OUT_OF_BOUNDS: {
675c4bd2261Santon 			const struct shift_out_of_bounds_data *data =
676c4bd2261Santon 				kr->kr_shift_out_of_bounds.v_data;
677c4bd2261Santon 			unsigned long lhs = kr->kr_shift_out_of_bounds.v_lhs;
678c4bd2261Santon 			unsigned long rhs = kr->kr_shift_out_of_bounds.v_rhs;
679c4bd2261Santon 
680c4bd2261Santon 			kubsan_format_int(data->d_ltype, lhs, blhs,
681c4bd2261Santon 			    sizeof(blhs));
682c4bd2261Santon 			kubsan_format_int(data->d_rtype, rhs, brhs,
683c4bd2261Santon 			    sizeof(brhs));
684c4bd2261Santon 			if (is_negative(data->d_rtype, rhs))
685c4bd2261Santon 				printf("kubsan: %s: shift: shift exponent %s "
686c4bd2261Santon 				    "is negative\n",
687c4bd2261Santon 				    bloc, brhs);
688c4bd2261Santon 			else if (is_shift_exponent_too_large(data->d_rtype, rhs))
689c4bd2261Santon 				printf("kubsan: %s: shift: shift exponent %s "
690c4bd2261Santon 				    "is too large for %u-bit type\n",
691c4bd2261Santon 				    bloc, brhs, NBITS(data->d_rtype));
692c4bd2261Santon 			else if (is_negative(data->d_ltype, lhs))
693c4bd2261Santon 				printf("kubsan: %s: shift: left shift of "
694c4bd2261Santon 				    "negative value %s\n",
695c4bd2261Santon 				    bloc, blhs);
696c4bd2261Santon 			else
697c4bd2261Santon 				printf("kubsan: %s: shift: left shift of %s by "
698c4bd2261Santon 				    "%s places cannot be represented in type "
699c4bd2261Santon 				    "%s\n",
700c4bd2261Santon 				    bloc, blhs, brhs, data->d_ltype->t_name);
701c4bd2261Santon 			break;
702c4bd2261Santon 		}
703c4bd2261Santon 
704c4bd2261Santon 		case KUBSAN_TYPE_MISMATCH: {
705c4bd2261Santon 			const struct type_mismatch_data *data =
706c4bd2261Santon 				kr->kr_type_mismatch.v_data;
707c4bd2261Santon 			unsigned long ptr = kr->kr_type_mismatch.v_ptr;
708c4bd2261Santon 			unsigned long align = 1UL << data->d_align;
709c4bd2261Santon 
710c4bd2261Santon 			if (ptr == 0UL)
711c4bd2261Santon 				printf("kubsan: %s: type mismatch: %s null "
712c4bd2261Santon 				    "pointer of type %s\n",
713c4bd2261Santon 				    bloc, kubsan_kind(data->d_kind),
714c4bd2261Santon 				    data->d_type->t_name);
715c4bd2261Santon 			else if (ptr & (align - 1))
716c4bd2261Santon 				printf("kubsan: %s: type mismatch: %s "
717c4bd2261Santon 				    "misaligned address %p for type %s which "
718c4bd2261Santon 				    "requires %lu byte alignment\n",
719c4bd2261Santon 				    bloc, kubsan_kind(data->d_kind),
720c4bd2261Santon 				    (void *)ptr, data->d_type->t_name, align);
721c4bd2261Santon 			else
722c4bd2261Santon 				printf("kubsan: %s: type mismatch: %s address "
723c4bd2261Santon 				    "%p with insufficient space for an object "
724c4bd2261Santon 				    "of type %s\n",
725c4bd2261Santon 				    bloc, kubsan_kind(data->d_kind),
726c4bd2261Santon 				    (void *)ptr, data->d_type->t_name);
727c4bd2261Santon 			break;
728c4bd2261Santon 		}
729c4bd2261Santon 
730c4bd2261Santon 		case KUBSAN_UNREACHABLE:
731c4bd2261Santon 			printf("kubsan: %s: unreachable: calling "
732c4bd2261Santon 			    "__builtin_unreachable()\n",
733c4bd2261Santon 			    bloc);
734c4bd2261Santon 			break;
735c4bd2261Santon 		}
73628673518Santon 
73728673518Santon #ifdef DDB
73828673518Santon 		if (kubsan_watch == 2)
73928673518Santon 			db_enter();
74028673518Santon #endif
74128673518Santon 	}
74228673518Santon 
743c4bd2261Santon 	/* New reports can arrive at any time. */
744aafc92f8Santon 	if (atomic_cas_uint(&kubsan_slot, nslots, 0) != nslots) {
745aafc92f8Santon 		if (nslots < KUBSAN_NSLOTS)
746c4bd2261Santon 			goto again;
747aafc92f8Santon 		atomic_swap_uint(&kubsan_slot, 0);
748aafc92f8Santon 	}
749c01f5a04Santon 
750c01f5a04Santon done:
751c01f5a04Santon 	timeout_add_msec(&kubsan_timo, KUBSAN_INTERVAL);
752c4bd2261Santon }
753c4bd2261Santon 
754c4bd2261Santon void
755c4bd2261Santon kubsan_unreport(struct source_location *src)
756c4bd2261Santon {
757c4bd2261Santon 	uint32_t *line = &src->sl_line;
758c4bd2261Santon 
759c4bd2261Santon 	atomic_clearbits_int(line, LOCATION_REPORTED);
760c4bd2261Santon }
761c4bd2261Santon 
76228673518Santon static int
76328673518Santon is_negative(struct type_descriptor *typ, unsigned long val)
76428673518Santon {
76528673518Santon 	return (SIGNED(typ) && kubsan_deserialize_int(typ, val) < 0);
76628673518Santon }
76728673518Santon 
76828673518Santon static int
76928673518Santon is_shift_exponent_too_large(struct type_descriptor *typ, unsigned long val)
77028673518Santon {
77128673518Santon 	return (kubsan_deserialize_int(typ, val) >= NBITS(typ));
77228673518Santon }
773a15e6dd3Santon 
774a15e6dd3Santon /*
775a15e6dd3Santon  * A source location is an absolute path making reports quite long.
776a15e6dd3Santon  * Instead, use everything after the first /sys/ segment as the path.
777a15e6dd3Santon  */
778a15e6dd3Santon static const char *
779a15e6dd3Santon pathstrip(const char *path)
780a15e6dd3Santon {
781a15e6dd3Santon 	const char *needle = "/sys/";
782a15e6dd3Santon 	size_t i, j;
783a15e6dd3Santon 
784a15e6dd3Santon 	for (i = j = 0; path[i] != '\0'; i++) {
785a15e6dd3Santon 		if (path[i] != needle[j]) {
786a15e6dd3Santon 			j = 0;
787a15e6dd3Santon 			continue;
788a15e6dd3Santon 		}
789a15e6dd3Santon 
790a15e6dd3Santon 		if (needle[++j] == '\0')
791a15e6dd3Santon 			return path + i + 1;
792a15e6dd3Santon 	}
793a15e6dd3Santon 
794a15e6dd3Santon 	return path;
795a15e6dd3Santon }
796