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