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