1#include "sanitizer_common/sanitizer_atomic.h"
2
3#include <stdint.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7
8#ifdef KERNEL_USE
9extern "C" void ubsan_message(const char *msg);
10static void message(const char *msg) { ubsan_message(msg); }
11#else
12static void message(const char *msg) { (void)write(fd: 2, buf: msg, n: strlen(s: msg)); }
13#endif
14
15// If for some reason we cannot build the runtime with preserve_all, don't
16// emit any symbol. Programs that need them will fail to link, but that is
17// better than randomly corrupted registers.
18// Some architectures don't support preserve_all (but clang still has the)
19// attribute. For now, only support x86-64 and aarch64.
20#if defined(__clang__) && defined(__has_cpp_attribute) && \
21 (defined(__x86_64__) || defined(__aarch64__))
22#if __has_cpp_attribute(clang::preserve_all)
23#define PRESERVE_HANDLERS true
24#else
25#define PRESERVE_HANDLERS false
26#endif
27#else
28#define PRESERVE_HANDLERS false
29#endif
30
31static const int kMaxCallerPcs = 20;
32static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
33// Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
34// that "too many errors" has already been reported.
35static __sanitizer::atomic_uint32_t caller_pcs_sz;
36
37static char *append_str(const char *s, char *buf, const char *end) {
38 for (const char *p = s; (buf < end) && (*p != '\0'); ++p, ++buf)
39 *buf = *p;
40 return buf;
41}
42
43static char *append_hex(uintptr_t d, char *buf, const char *end) {
44 // Print the address by nibbles.
45 for (unsigned shift = sizeof(uintptr_t) * 8; shift && buf < end;) {
46 shift -= 4;
47 unsigned nibble = (d >> shift) & 0xf;
48 *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a';
49 }
50 return buf;
51}
52
53static void format_msg(const char *kind, uintptr_t caller, char *buf,
54 const char *end) {
55 buf = append_str(s: "ubsan: ", buf, end);
56 buf = append_str(s: kind, buf, end);
57 buf = append_str(s: " by 0x", buf, end);
58 buf = append_hex(d: caller, buf, end);
59 buf = append_str(s: "\n", buf, end);
60 if (buf == end)
61 --buf; // Make sure we don't cause a buffer overflow.
62 *buf = '\0';
63}
64
65SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
66 uintptr_t caller) {
67 if (caller == 0)
68 return;
69 while (true) {
70 unsigned sz = __sanitizer::atomic_load_relaxed(a: &caller_pcs_sz);
71 if (sz > kMaxCallerPcs)
72 return; // early exit
73 // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg
74 // succeeds in order to not print it multiple times.
75 if (sz > 0 && sz < kMaxCallerPcs) {
76 uintptr_t p;
77 for (unsigned i = 0; i < sz; ++i) {
78 p = __sanitizer::atomic_load_relaxed(a: &caller_pcs[i]);
79 if (p == 0)
80 break; // Concurrent update.
81 if (p == caller)
82 return;
83 }
84 if (p == 0)
85 continue; // FIXME: yield?
86 }
87
88 if (!__sanitizer::atomic_compare_exchange_strong(
89 a: &caller_pcs_sz, cmp: &sz, xchg: sz + 1, mo: __sanitizer::memory_order_seq_cst))
90 continue; // Concurrent update! Try again from the start.
91
92 if (sz == kMaxCallerPcs) {
93 message(msg: "ubsan: too many errors\n");
94 return;
95 }
96 __sanitizer::atomic_store_relaxed(a: &caller_pcs[sz], v: caller);
97
98 char msg_buf[128];
99 format_msg(kind, caller, buf: msg_buf, end: msg_buf + sizeof(msg_buf));
100 message(msg: msg_buf);
101 }
102}
103
104#if PRESERVE_HANDLERS
105SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_preserve,
106 const char *kind, uintptr_t caller)
107[[clang::preserve_all]] {
108 // Additional indirecton so the user can override this with their own
109 // preserve_all function. This would allow, e.g., a function that reports the
110 // first error only, so for all subsequent calls we can skip the register save
111 // / restore.
112 __ubsan_report_error(kind, caller);
113}
114#endif
115
116SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char *kind,
117 uintptr_t caller) {
118 // Use another handlers, in case it's already overriden.
119 __ubsan_report_error(kind, caller);
120}
121
122#if defined(__ANDROID__)
123extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
124static void abort_with_message(const char *kind, uintptr_t caller) {
125 char msg_buf[128];
126 format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
127 if (&android_set_abort_message)
128 android_set_abort_message(msg_buf);
129 abort();
130}
131#else
132static void abort_with_message(const char *kind, uintptr_t caller) { abort(); }
133#endif
134
135#if SANITIZER_DEBUG
136namespace __sanitizer {
137// The DCHECK macro needs this symbol to be defined.
138void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
139 message("Sanitizer CHECK failed: ");
140 message(file);
141 message(":?? : "); // FIXME: Show line number.
142 message(cond);
143 abort();
144}
145} // namespace __sanitizer
146#endif
147
148#define INTERFACE extern "C" __attribute__((visibility("default")))
149
150#if PRESERVE_HANDLERS
151#define HANDLER_PRESERVE(name, kind) \
152 INTERFACE void __ubsan_handle_##name##_minimal_preserve() \
153 [[clang::preserve_all]] { \
154 __ubsan_report_error_preserve(kind, GET_CALLER_PC()); \
155 }
156#else
157#define HANDLER_PRESERVE(name, kind)
158#endif
159
160#define HANDLER_RECOVER(name, kind) \
161 INTERFACE void __ubsan_handle_##name##_minimal() { \
162 __ubsan_report_error(kind, GET_CALLER_PC()); \
163 } \
164 HANDLER_PRESERVE(name, kind)
165
166#define HANDLER_NORECOVER(name, kind) \
167 INTERFACE void __ubsan_handle_##name##_minimal_abort() { \
168 uintptr_t caller = GET_CALLER_PC(); \
169 __ubsan_report_error_fatal(kind, caller); \
170 abort_with_message(kind, caller); \
171 }
172
173#define HANDLER(name, kind) \
174 HANDLER_RECOVER(name, kind) \
175 HANDLER_NORECOVER(name, kind)
176
177HANDLER(type_mismatch, "type-mismatch")
178HANDLER(alignment_assumption, "alignment-assumption")
179HANDLER(add_overflow, "add-overflow")
180HANDLER(sub_overflow, "sub-overflow")
181HANDLER(mul_overflow, "mul-overflow")
182HANDLER(negate_overflow, "negate-overflow")
183HANDLER(divrem_overflow, "divrem-overflow")
184HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
185HANDLER(out_of_bounds, "out-of-bounds")
186HANDLER(local_out_of_bounds, "local-out-of-bounds")
187HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
188HANDLER_RECOVER(missing_return, "missing-return")
189HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
190HANDLER(float_cast_overflow, "float-cast-overflow")
191HANDLER(load_invalid_value, "load-invalid-value")
192HANDLER(invalid_builtin, "invalid-builtin")
193HANDLER(invalid_objc_cast, "invalid-objc-cast")
194HANDLER(function_type_mismatch, "function-type-mismatch")
195HANDLER(implicit_conversion, "implicit-conversion")
196HANDLER(nonnull_arg, "nonnull-arg")
197HANDLER(nonnull_return, "nonnull-return")
198HANDLER(nullability_arg, "nullability-arg")
199HANDLER(nullability_return, "nullability-return")
200HANDLER(pointer_overflow, "pointer-overflow")
201HANDLER(cfi_check_fail, "cfi-check-fail")
202