xref: /openbsd-src/sys/kern/subr_kubsan.c (revision 4b70baf6e17fc8b27fc1f7fa7929335753fa94c3)
1 /*	$OpenBSD: subr_kubsan.c,v 1.2 2019/03/19 20:13:54 anton 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/param.h>
20 #include <sys/atomic.h>
21 #include <sys/syslimits.h>
22 #include <sys/systm.h>
23 
24 #define NUMBER_BUFSIZ		32
25 #define LOCATION_BUFSIZ		(PATH_MAX + 32)	/* filename:line:column */
26 #define LOCATION_REPORTED	(1U << 31)
27 
28 #define NBITS(typ)	(1 << ((typ)->t_info >> 1))
29 #define SIGNED(typ)	((typ)->t_info & 1)
30 
31 struct type_descriptor {
32 	uint16_t t_kind;
33 	uint16_t t_info;
34 	char t_name[1];	/* type name as variable length array */
35 };
36 
37 struct source_location {
38 	const char *sl_filename;
39 	uint32_t sl_line;
40 	uint32_t sl_column;
41 };
42 
43 struct invalid_value_data {
44 	struct source_location d_src;
45 	struct type_descriptor *d_type;
46 };
47 
48 struct out_of_bounds_data {
49 	struct source_location d_src;
50 	struct type_descriptor *d_atype;	/* array type */
51 	struct type_descriptor *d_itype;	/* index type */
52 };
53 
54 struct overflow_data {
55 	struct source_location d_src;
56 	struct type_descriptor *d_type;
57 };
58 
59 struct pointer_overflow_data {
60 	struct source_location d_src;
61 };
62 
63 struct shift_out_of_bounds_data {
64 	struct source_location d_src;
65 	struct type_descriptor *d_ltype;
66 	struct type_descriptor *d_rtype;
67 };
68 
69 struct unreachable_data {
70 	struct source_location d_src;
71 };
72 
73 struct type_mismatch {
74 	struct source_location d_src;
75 	struct type_descriptor *d_type;
76 	uint8_t d_align;	/* log2 alignment */
77 	uint8_t d_kind;
78 };
79 
80 void	kubsan_handle_load_invalid_value(struct invalid_value_data *,
81 	    unsigned long);
82 void	kubsan_handle_negate_overflow(struct overflow_data *, unsigned long);
83 void	kubsan_handle_out_of_bounds(struct out_of_bounds_data *, unsigned long);
84 void	kubsan_handle_overflow(struct overflow_data *, unsigned long,
85 	    unsigned long, char);
86 void	kubsan_handle_pointer_overflow(struct pointer_overflow_data *,
87 	    unsigned long, unsigned long);
88 void	kubsan_handle_type_mismatch(struct type_mismatch *, unsigned long);
89 void    kubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *,
90 	    unsigned long, unsigned long);
91 void	kubsan_handle_ureachable(struct unreachable_data *);
92 
93 int64_t		 kubsan_deserialize_int(struct type_descriptor *,
94 		    unsigned long);
95 uint64_t	 kubsan_deserialize_uint(struct type_descriptor *,
96 		    unsigned long);
97 void		 kubsan_format_int(struct type_descriptor *, unsigned long,
98 		    char *, size_t);
99 void		 kubsan_format_location(struct source_location *, char *,
100 		    size_t);
101 int		 kubsan_is_reported(struct source_location *);
102 const char	*kubsan_kind(uint8_t);
103 void		 kubsan_report(const char *, ...)
104 		    __attribute__((__format__(__kprintf__, 1, 2)));
105 
106 static int	is_negative(struct type_descriptor *, unsigned long);
107 static int	is_shift_exponent_too_large(struct type_descriptor *,
108 		    unsigned long);
109 
110 #ifdef KUBSAN_WATCH
111 int kubsan_watch = 2;
112 #else
113 int kubsan_watch = 1;
114 #endif
115 
116 /*
117  * Compiling the kernel with `-fsanitize=undefined' will cause the following
118  * functions to be called when a sanitizer detects undefined behavior.
119  * Some sanitizers are omitted since they are only applicable to C++.
120  *
121  * Every __ubsan_*() sanitizer function also has a corresponding
122  * __ubsan_*_abort() function as part of the ABI provided by Clang.
123  * But, since the kernel never is compiled with `fno-sanitize-recover' for
124  * obvious reasons, they are also omitted.
125  */
126 
127 void
128 __ubsan_handle_add_overflow(struct overflow_data *data,
129     unsigned long lhs, unsigned long rhs)
130 {
131 	kubsan_handle_overflow(data, lhs, rhs, '+');
132 }
133 
134 void
135 __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
136 {
137 	kubsan_handle_ureachable(data);
138 }
139 
140 void
141 __ubsan_handle_divrem_overflow(struct overflow_data *data,
142     unsigned long lhs, unsigned long rhs)
143 {
144 	kubsan_handle_overflow(data, lhs, rhs, '/');
145 }
146 
147 void
148 __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
149     unsigned long val)
150 {
151 	kubsan_handle_load_invalid_value(data, val);
152 }
153 
154 void
155 __ubsan_handle_mul_overflow(struct overflow_data *data,
156     unsigned long lhs, unsigned long rhs)
157 {
158 	kubsan_handle_overflow(data, lhs, rhs, '*');
159 }
160 
161 void
162 __ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long val)
163 {
164 	kubsan_handle_negate_overflow(data, val);
165 }
166 
167 void
168 __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
169     unsigned long idx)
170 {
171 	kubsan_handle_out_of_bounds(data, idx);
172 }
173 
174 void
175 __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
176     unsigned long base, unsigned long res)
177 {
178 	kubsan_handle_pointer_overflow(data, base, res);
179 }
180 
181 void
182 __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
183     unsigned long lhs, unsigned long rhs)
184 {
185 	kubsan_handle_shift_out_of_bounds(data, lhs, rhs);
186 }
187 
188 void
189 __ubsan_handle_sub_overflow(struct overflow_data *data,
190     unsigned long lhs, unsigned long rhs)
191 {
192 	kubsan_handle_overflow(data, lhs, rhs, '-');
193 }
194 
195 void
196 __ubsan_handle_type_mismatch_v1(struct type_mismatch *data,
197     unsigned long ptr)
198 {
199 	kubsan_handle_type_mismatch(data, ptr);
200 }
201 
202 void
203 kubsan_handle_load_invalid_value(struct invalid_value_data *data,
204     unsigned long val)
205 {
206 	char bloc[LOCATION_BUFSIZ];
207 	char bval[NUMBER_BUFSIZ];
208 
209 	if (kubsan_is_reported(&data->d_src))
210 		return;
211 
212 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
213 	kubsan_format_int(data->d_type, val, bval, sizeof(bval));
214 	kubsan_report("kubsan: %s: load invalid value: load of value %s is "
215 	    "not a valid value for type %s\n",
216 	    bloc, bval, data->d_type->t_name);
217 }
218 
219 void
220 kubsan_handle_negate_overflow(struct overflow_data *data, unsigned long val)
221 {
222 	char bloc[LOCATION_BUFSIZ];
223 	char bval[NUMBER_BUFSIZ];
224 
225 	if (kubsan_is_reported(&data->d_src))
226 		return;
227 
228 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
229 	kubsan_format_int(data->d_type, val, bval, sizeof(bval));
230 	kubsan_report("kubsan: %s: negate overflow: negation of %s cannot be "
231 	    "represented in type %s\n",
232 	    bloc, bval, data->d_type->t_name);
233 }
234 
235 void
236 kubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
237     unsigned long idx)
238 {
239 	char bloc[LOCATION_BUFSIZ];
240 	char bidx[NUMBER_BUFSIZ];
241 
242 	if (kubsan_is_reported(&data->d_src))
243 		return;
244 
245 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
246 	kubsan_format_int(data->d_itype, idx, bidx, sizeof(bidx));
247 	kubsan_report("kubsan: %s: out of bounds: index %s is out of range "
248 	    "for type %s\n",
249 	    bloc, bidx, data->d_atype->t_name);
250 }
251 
252 void
253 kubsan_handle_overflow(struct overflow_data *data, unsigned long rhs,
254     unsigned long lhs, char op)
255 {
256 	char bloc[LOCATION_BUFSIZ];
257 	char blhs[NUMBER_BUFSIZ];
258 	char brhs[NUMBER_BUFSIZ];
259 
260 	if (kubsan_is_reported(&data->d_src))
261 		return;
262 
263 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
264 	kubsan_format_int(data->d_type, lhs, blhs, sizeof(blhs));
265 	kubsan_format_int(data->d_type, rhs, brhs, sizeof(brhs));
266 	kubsan_report("kubsan: %s: %s integer overflow: %s %c %s cannot "
267 	    "be represented in type %s\n",
268 	    bloc, SIGNED(data->d_type) ? "signed" : "unsigned",
269 	    blhs, op, brhs, data->d_type->t_name);
270 }
271 
272 void
273 kubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
274     unsigned long base, unsigned long res)
275 {
276 	char bloc[LOCATION_BUFSIZ];
277 
278 	if (kubsan_is_reported(&data->d_src))
279 		return;
280 
281 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
282 	kubsan_report("kubsan: %s: pointer overflow: pointer expression with"
283 	    " base %#lx overflowed to %#lx\n",
284 	    bloc, base, res);
285 }
286 
287 void
288 kubsan_handle_type_mismatch(struct type_mismatch *data, unsigned long ptr)
289 {
290 	char bloc[LOCATION_BUFSIZ];
291 	unsigned long align = 1UL << data->d_align;
292 
293 	if (kubsan_is_reported(&data->d_src))
294 		return;
295 
296 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
297 	if (ptr == 0UL)
298 		kubsan_report("kubsan: %s: type mismatch: %s null pointer of "
299 		    "type %s\n",
300 		    bloc, kubsan_kind(data->d_kind), data->d_type->t_name);
301 	else if (ptr & (align - 1))
302 		kubsan_report("kubsan: %s: type mismatch: %s misaligned address "
303 		    "%p for type %s which requires %lu byte alignment\n",
304 		    bloc, kubsan_kind(data->d_kind), (void *)ptr,
305 		    data->d_type->t_name, align);
306 	else
307 		kubsan_report("kubsan: %s: type mismatch: %s address %p with "
308 		    "insufficient space for an object of type %s\n",
309 		    bloc, kubsan_kind(data->d_kind), (void *)ptr,
310 		    data->d_type->t_name);
311 }
312 
313 void
314 kubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
315     unsigned long lhs, unsigned long rhs)
316 {
317 	char bloc[LOCATION_BUFSIZ];
318 	char blhs[NUMBER_BUFSIZ];
319 	char brhs[NUMBER_BUFSIZ];
320 
321 	if (kubsan_is_reported(&data->d_src))
322 		return;
323 
324 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
325 	kubsan_format_int(data->d_ltype, lhs, blhs, sizeof(blhs));
326 	kubsan_format_int(data->d_rtype, rhs, brhs, sizeof(brhs));
327 	if (is_negative(data->d_rtype, rhs))
328 		kubsan_report("kubsan: %s: shift: shift exponent %s is "
329 		    "negative\n",
330 		    bloc, brhs);
331 	else if (is_shift_exponent_too_large(data->d_rtype, rhs))
332 		kubsan_report("kubsan: %s: shift: shift exponent %s is too "
333 		    "large for %u-bit type\n",
334 		    bloc, brhs, NBITS(data->d_rtype));
335 	else if (is_negative(data->d_ltype, lhs))
336 		kubsan_report("kubsan: %s: shift: left shift of negative "
337 		    "value %s\n",
338 		    bloc, blhs);
339 	else
340 		kubsan_report("kubsan: %s: shift: left shift of %s by %s "
341 		    "places cannot be represented in type %s\n",
342 		    bloc, blhs, brhs, data->d_ltype->t_name);
343 }
344 
345 void
346 kubsan_handle_ureachable(struct unreachable_data *data)
347 {
348 	char bloc[LOCATION_BUFSIZ];
349 
350 	if (kubsan_is_reported(&data->d_src))
351 		return;
352 
353 	kubsan_format_location(&data->d_src, bloc, sizeof(bloc));
354 	kubsan_report("kubsan: %s: unreachable: calling "
355 	    "__builtin_unreachable()\n",
356 	    bloc);
357 }
358 
359 int64_t
360 kubsan_deserialize_int(struct type_descriptor *typ, unsigned long val)
361 {
362 	switch (NBITS(typ)) {
363 	case 8:
364 		return ((int8_t)val);
365 	case 16:
366 		return ((int16_t)val);
367 	case 32:
368 		return ((int32_t)val);
369 	case 64:
370 	default:
371 		return ((int64_t)val);
372 	}
373 }
374 
375 uint64_t
376 kubsan_deserialize_uint(struct type_descriptor *typ, unsigned long val)
377 {
378 	switch (NBITS(typ)) {
379 	case 8:
380 		return ((uint8_t)val);
381 	case 16:
382 		return ((uint16_t)val);
383 	case 32:
384 		return ((uint32_t)val);
385 	case 64:
386 	default:
387 		return ((uint64_t)val);
388 	}
389 }
390 
391 void
392 kubsan_format_int(struct type_descriptor *typ, unsigned long val,
393     char *buf, size_t bufsiz)
394 {
395 	switch (typ->t_kind) {
396 	case 0:	/* integer */
397 		if (SIGNED(typ)) {
398 			int64_t i = kubsan_deserialize_int(typ, val);
399 			snprintf(buf, bufsiz, "%lld", i);
400 		} else {
401 			uint64_t u = kubsan_deserialize_uint(typ, val);
402 			snprintf(buf, bufsiz, "%llu", u);
403 		}
404 		break;
405 	default:
406 		snprintf(buf, bufsiz, "%#x<NaN>", typ->t_kind);
407 	}
408 }
409 
410 void
411 kubsan_format_location(struct source_location *src, char *buf,
412     size_t bufsiz)
413 {
414 	snprintf(buf, bufsiz, "%s:%u:%u",
415 	    src->sl_filename, src->sl_line & ~LOCATION_REPORTED,
416 	    src->sl_column);
417 }
418 
419 int
420 kubsan_is_reported(struct source_location *src)
421 {
422 	uint32_t *line = &src->sl_line;
423 	uint32_t prev;
424 
425 	/*
426 	 * Treat everything as reported when disabled.
427 	 * Otherwise, new violations would go by unnoticed.
428 	 */
429 	if (__predict_false(kubsan_watch == 0))
430 		return (1);
431 
432 	do {
433 		prev = *line;
434 		/* If already reported, avoid redundant atomic operation. */
435 		if (prev & LOCATION_REPORTED)
436 			break;
437 	} while (atomic_cas_uint(line, prev, prev | LOCATION_REPORTED) != prev);
438 
439 	return (prev & LOCATION_REPORTED);
440 }
441 
442 const char *
443 kubsan_kind(uint8_t kind)
444 {
445 	static const char *kinds[] = {
446 		"load of",
447 		"store to",
448 		"reference binding to",
449 		"member access within",
450 		"member call on",
451 		"constructor call on",
452 		"downcast of",
453 		"downcast of",
454 		"upcast of",
455 		"cast to virtual base of",
456 		"_Nonnull binding to",
457 		"dynamic operation on"
458 	};
459 
460 	if (kind >= nitems(kinds))
461 		return ("?");
462 
463 	return (kinds[kind]);
464 }
465 
466 void
467 kubsan_report(const char *fmt, ...)
468 {
469 	va_list ap;
470 
471 	va_start(ap, fmt);
472 	vprintf(fmt, ap);
473 	va_end(ap);
474 
475 #ifdef DDB
476 	if (kubsan_watch == 2)
477 		db_enter();
478 #endif
479 }
480 
481 static int
482 is_negative(struct type_descriptor *typ, unsigned long val)
483 {
484 	return (SIGNED(typ) && kubsan_deserialize_int(typ, val) < 0);
485 }
486 
487 static int
488 is_shift_exponent_too_large(struct type_descriptor *typ, unsigned long val)
489 {
490 	return (kubsan_deserialize_int(typ, val) >= NBITS(typ));
491 }
492