1a9aa8137SNico Weber #include "sanitizer_common/sanitizer_atomic.h" 2a9aa8137SNico Weber 3a9aa8137SNico Weber #include <stdlib.h> 4a9aa8137SNico Weber #include <stdint.h> 5a9aa8137SNico Weber #include <string.h> 6a9aa8137SNico Weber #include <unistd.h> 7a9aa8137SNico Weber 8a9aa8137SNico Weber #ifdef KERNEL_USE 9a9aa8137SNico Weber extern "C" void ubsan_message(const char *msg); 10a9aa8137SNico Weber static void message(const char *msg) { ubsan_message(msg); } 11a9aa8137SNico Weber #else 12a9aa8137SNico Weber static void message(const char *msg) { 131ef0e94dSFangrui Song (void)write(2, msg, strlen(msg)); 14a9aa8137SNico Weber } 15a9aa8137SNico Weber #endif 16a9aa8137SNico Weber 17a9aa8137SNico Weber static const int kMaxCallerPcs = 20; 18a9aa8137SNico Weber static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs]; 19a9aa8137SNico Weber // Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means 20a9aa8137SNico Weber // that "too many errors" has already been reported. 21a9aa8137SNico Weber static __sanitizer::atomic_uint32_t caller_pcs_sz; 22a9aa8137SNico Weber 23e5e0f23aSKirill Stoimenov static char *append_str(const char *s, char *buf, const char *end) { 24e5e0f23aSKirill Stoimenov for (const char *p = s; (buf < end) && (*p != '\0'); ++p, ++buf) 25e5e0f23aSKirill Stoimenov *buf = *p; 26e5e0f23aSKirill Stoimenov return buf; 27e5e0f23aSKirill Stoimenov } 28e5e0f23aSKirill Stoimenov 29e5e0f23aSKirill Stoimenov static char *append_hex(uintptr_t d, char *buf, const char *end) { 30e5e0f23aSKirill Stoimenov // Print the address by nibbles. 31e5e0f23aSKirill Stoimenov for (unsigned shift = sizeof(uintptr_t) * 8; shift && buf < end;) { 32e5e0f23aSKirill Stoimenov shift -= 4; 33e5e0f23aSKirill Stoimenov unsigned nibble = (d >> shift) & 0xf; 34e5e0f23aSKirill Stoimenov *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a'; 35e5e0f23aSKirill Stoimenov } 36e5e0f23aSKirill Stoimenov return buf; 37e5e0f23aSKirill Stoimenov } 38e5e0f23aSKirill Stoimenov 39e5e0f23aSKirill Stoimenov static void format_msg(const char *kind, uintptr_t caller, char *buf, 40e5e0f23aSKirill Stoimenov const char *end) { 41e5e0f23aSKirill Stoimenov buf = append_str("ubsan: ", buf, end); 42e5e0f23aSKirill Stoimenov buf = append_str(kind, buf, end); 43e5e0f23aSKirill Stoimenov buf = append_str(" by 0x", buf, end); 44e5e0f23aSKirill Stoimenov buf = append_hex(caller, buf, end); 45e5e0f23aSKirill Stoimenov buf = append_str("\n", buf, end); 46e5e0f23aSKirill Stoimenov if (buf == end) 47e5e0f23aSKirill Stoimenov --buf; // Make sure we don't cause a buffer overflow. 48e5e0f23aSKirill Stoimenov *buf = '\0'; 49e5e0f23aSKirill Stoimenov } 50e5e0f23aSKirill Stoimenov 5171d2fa79SKirill Stoimenov SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind, 5271d2fa79SKirill Stoimenov uintptr_t caller) { 531959a555SIgor Kudrin if (caller == 0) 54e5e0f23aSKirill Stoimenov return; 55a9aa8137SNico Weber while (true) { 56a9aa8137SNico Weber unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz); 57e5e0f23aSKirill Stoimenov if (sz > kMaxCallerPcs) 58e5e0f23aSKirill Stoimenov return; // early exit 59a9aa8137SNico Weber // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg 60a9aa8137SNico Weber // succeeds in order to not print it multiple times. 61a9aa8137SNico Weber if (sz > 0 && sz < kMaxCallerPcs) { 62a9aa8137SNico Weber uintptr_t p; 63a9aa8137SNico Weber for (unsigned i = 0; i < sz; ++i) { 64a9aa8137SNico Weber p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]); 65a9aa8137SNico Weber if (p == 0) break; // Concurrent update. 66e5e0f23aSKirill Stoimenov if (p == caller) 67e5e0f23aSKirill Stoimenov return; 68a9aa8137SNico Weber } 69a9aa8137SNico Weber if (p == 0) continue; // FIXME: yield? 70a9aa8137SNico Weber } 71a9aa8137SNico Weber 72a9aa8137SNico Weber if (!__sanitizer::atomic_compare_exchange_strong( 73a9aa8137SNico Weber &caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst)) 74a9aa8137SNico Weber continue; // Concurrent update! Try again from the start. 75a9aa8137SNico Weber 76a9aa8137SNico Weber if (sz == kMaxCallerPcs) { 77a9aa8137SNico Weber message("ubsan: too many errors\n"); 78e5e0f23aSKirill Stoimenov return; 79a9aa8137SNico Weber } 80a9aa8137SNico Weber __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller); 81a9aa8137SNico Weber 82e5e0f23aSKirill Stoimenov char msg_buf[128]; 83e5e0f23aSKirill Stoimenov format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf)); 84e5e0f23aSKirill Stoimenov message(msg_buf); 8584c4efbcSIgor Kudrin } 8684c4efbcSIgor Kudrin } 8784c4efbcSIgor Kudrin 88a9aa8137SNico Weber #if defined(__ANDROID__) 89a9aa8137SNico Weber extern "C" __attribute__((weak)) void android_set_abort_message(const char *); 90e5e0f23aSKirill Stoimenov static void abort_with_message(const char *kind, uintptr_t caller) { 91e5e0f23aSKirill Stoimenov char msg_buf[128]; 92e5e0f23aSKirill Stoimenov format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf)); 93e5e0f23aSKirill Stoimenov if (&android_set_abort_message) 94e5e0f23aSKirill Stoimenov android_set_abort_message(msg_buf); 95a9aa8137SNico Weber abort(); 96a9aa8137SNico Weber } 97a9aa8137SNico Weber #else 98e5e0f23aSKirill Stoimenov static void abort_with_message(const char *kind, uintptr_t caller) { abort(); } 99a9aa8137SNico Weber #endif 100a9aa8137SNico Weber 101a9aa8137SNico Weber #if SANITIZER_DEBUG 102a9aa8137SNico Weber namespace __sanitizer { 103a9aa8137SNico Weber // The DCHECK macro needs this symbol to be defined. 104a9aa8137SNico Weber void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { 105a9aa8137SNico Weber message("Sanitizer CHECK failed: "); 106a9aa8137SNico Weber message(file); 107a9aa8137SNico Weber message(":?? : "); // FIXME: Show line number. 108a9aa8137SNico Weber message(cond); 109a9aa8137SNico Weber abort(); 110a9aa8137SNico Weber } 111a9aa8137SNico Weber } // namespace __sanitizer 112a9aa8137SNico Weber #endif 113a9aa8137SNico Weber 114a9aa8137SNico Weber #define INTERFACE extern "C" __attribute__((visibility("default"))) 115a9aa8137SNico Weber 116e5e0f23aSKirill Stoimenov #define HANDLER_RECOVER(name, kind) \ 117a9aa8137SNico Weber INTERFACE void __ubsan_handle_##name##_minimal() { \ 11871d2fa79SKirill Stoimenov __ubsan_report_error(kind, GET_CALLER_PC()); \ 119a9aa8137SNico Weber } 120a9aa8137SNico Weber 121e5e0f23aSKirill Stoimenov #define HANDLER_NORECOVER(name, kind) \ 122a9aa8137SNico Weber INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ 123e5e0f23aSKirill Stoimenov uintptr_t caller = GET_CALLER_PC(); \ 12471d2fa79SKirill Stoimenov __ubsan_report_error(kind, caller); \ 125e5e0f23aSKirill Stoimenov abort_with_message(kind, caller); \ 126a9aa8137SNico Weber } 127a9aa8137SNico Weber 128e5e0f23aSKirill Stoimenov #define HANDLER(name, kind) \ 129e5e0f23aSKirill Stoimenov HANDLER_RECOVER(name, kind) \ 130e5e0f23aSKirill Stoimenov HANDLER_NORECOVER(name, kind) 131a9aa8137SNico Weber 132a9aa8137SNico Weber HANDLER(type_mismatch, "type-mismatch") 133a9aa8137SNico Weber HANDLER(alignment_assumption, "alignment-assumption") 134a9aa8137SNico Weber HANDLER(add_overflow, "add-overflow") 135a9aa8137SNico Weber HANDLER(sub_overflow, "sub-overflow") 136a9aa8137SNico Weber HANDLER(mul_overflow, "mul-overflow") 137a9aa8137SNico Weber HANDLER(negate_overflow, "negate-overflow") 138a9aa8137SNico Weber HANDLER(divrem_overflow, "divrem-overflow") 139a9aa8137SNico Weber HANDLER(shift_out_of_bounds, "shift-out-of-bounds") 140a9aa8137SNico Weber HANDLER(out_of_bounds, "out-of-bounds") 141*c2aee506SVitaly Buka HANDLER(local_out_of_bounds, "local-out-of-bounds") 142a9aa8137SNico Weber HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable") 143a9aa8137SNico Weber HANDLER_RECOVER(missing_return, "missing-return") 144a9aa8137SNico Weber HANDLER(vla_bound_not_positive, "vla-bound-not-positive") 145a9aa8137SNico Weber HANDLER(float_cast_overflow, "float-cast-overflow") 146a9aa8137SNico Weber HANDLER(load_invalid_value, "load-invalid-value") 147a9aa8137SNico Weber HANDLER(invalid_builtin, "invalid-builtin") 1488c4a65b9SVedant Kumar HANDLER(invalid_objc_cast, "invalid-objc-cast") 149a9aa8137SNico Weber HANDLER(function_type_mismatch, "function-type-mismatch") 150a9aa8137SNico Weber HANDLER(implicit_conversion, "implicit-conversion") 151a9aa8137SNico Weber HANDLER(nonnull_arg, "nonnull-arg") 152a9aa8137SNico Weber HANDLER(nonnull_return, "nonnull-return") 153a9aa8137SNico Weber HANDLER(nullability_arg, "nullability-arg") 154a9aa8137SNico Weber HANDLER(nullability_return, "nullability-return") 155a9aa8137SNico Weber HANDLER(pointer_overflow, "pointer-overflow") 156a9aa8137SNico Weber HANDLER(cfi_check_fail, "cfi-check-fail") 157