1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016, Linaro Limited 4 */ 5 6 #include <atomic.h> 7 #include <compiler.h> 8 #include <string.h> 9 #include <trace.h> 10 #include <types_ext.h> 11 #include <util.h> 12 13 #if defined(__KERNEL__) 14 # include <kernel/panic.h> 15 #elif defined(__LDELF__) 16 # include <ldelf_syscalls.h> 17 #else 18 # include <utee_syscalls.h> 19 #endif 20 21 #define UBSAN_LOC_REPORTED BIT32(31) 22 23 struct source_location { 24 const char *file_name; 25 uint32_t line; 26 uint32_t column; 27 }; 28 29 static void __noreturn ubsan_panic(void) 30 { 31 #if defined(__KERNEL__) 32 panic(); 33 #elif defined(__LDELF__) 34 _ldelf_panic(2); 35 #else 36 _utee_panic(TEE_ERROR_GENERIC); 37 #endif 38 /* 39 * _ldelf_panic and _utee_panic are not marked as noreturn, 40 * however they should be. To prevent "‘noreturn’ function 41 * does return" warning the while loop is used. 42 */ 43 while (1) 44 ; 45 } 46 47 static bool was_already_reported(struct source_location *loc) 48 { 49 uint32_t column = loc->column; 50 51 if (column & UBSAN_LOC_REPORTED) 52 return true; 53 54 return !atomic_cas_u32(&loc->column, &column, 55 column | UBSAN_LOC_REPORTED); 56 } 57 58 struct type_descriptor { 59 uint16_t type_kind; 60 uint16_t type_info; 61 char type_name[1]; 62 }; 63 64 struct type_mismatch_data { 65 struct source_location loc; 66 struct type_descriptor *type; 67 unsigned long alignment; 68 unsigned char type_check_kind; 69 }; 70 71 struct overflow_data { 72 struct source_location loc; 73 struct type_descriptor *type; 74 }; 75 76 struct shift_out_of_bounds_data { 77 struct source_location loc; 78 struct type_descriptor *lhs_type; 79 struct type_descriptor *rhs_type; 80 }; 81 82 struct out_of_bounds_data { 83 struct source_location loc; 84 struct type_descriptor *array_type; 85 struct type_descriptor *index_type; 86 }; 87 88 struct unreachable_data { 89 struct source_location loc; 90 }; 91 92 struct vla_bound_data { 93 struct source_location loc; 94 struct type_descriptor *type; 95 }; 96 97 struct invalid_value_data { 98 struct source_location loc; 99 struct type_descriptor *type; 100 }; 101 102 struct nonnull_arg_data { 103 struct source_location loc; 104 }; 105 106 struct invalid_builtin_data { 107 struct source_location loc; 108 unsigned char kind; 109 }; 110 111 /* 112 * When compiling with -fsanitize=undefined the compiler expects functions 113 * with the following signatures. The functions are never called directly, 114 * only when undefined behavior is detected in instrumented code. 115 */ 116 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, 117 unsigned long ptr); 118 void __ubsan_handle_type_mismatch_v1(void *data_, void *ptr); 119 void __ubsan_handle_add_overflow(void *data_, void *lhs, void *rhs); 120 void __ubsan_handle_sub_overflow(void *data_, void *lhs, void *rhs); 121 void __ubsan_handle_mul_overflow(void *data_, void *lhs, void *rhs); 122 void __ubsan_handle_negate_overflow(void *data_, void *old_val); 123 void __ubsan_handle_divrem_overflow(void *data_, void *lhs, void *rhs); 124 void __ubsan_handle_pointer_overflow(void *data_, void *lhs, void *rhs); 125 void __ubsan_handle_shift_out_of_bounds(void *data_, void *lhs, void *rhs); 126 void __ubsan_handle_out_of_bounds(void *data_, void *idx); 127 void __ubsan_handle_builtin_unreachable(void *data_); 128 void __ubsan_handle_missing_return(void *data_); 129 void __ubsan_handle_vla_bound_not_positive(void *data_, void *bound); 130 void __ubsan_handle_load_invalid_value(void *data_, void *val); 131 void __ubsan_handle_nonnull_arg(void *data_ 132 #if __GCC_VERSION < 60000 133 , size_t arg_no 134 #endif 135 ); 136 void __ubsan_handle_invalid_builtin(void *data_); 137 138 static bool should_panic = true; 139 140 static void ubsan_handle_error(const char *func, struct source_location *loc, 141 bool panic_flag) 142 { 143 const char *f = func; 144 const char func_prefix[] = "__ubsan_handle"; 145 146 if (was_already_reported(loc)) 147 return; 148 149 if (!memcmp(f, func_prefix, sizeof(func_prefix) - 1)) 150 f += sizeof(func_prefix); 151 152 EMSG_RAW("Undefined behavior %s at %s:%" PRIu32 " col %" PRIu32, 153 f, loc->file_name, loc->line, loc->column & ~UBSAN_LOC_REPORTED); 154 155 if (panic_flag) 156 ubsan_panic(); 157 } 158 159 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, 160 unsigned long ptr __unused) 161 { 162 ubsan_handle_error(__func__, &data->loc, should_panic); 163 } 164 165 void __ubsan_handle_type_mismatch_v1(void *data_, void *ptr __unused) 166 { 167 struct type_mismatch_data *data = data_; 168 169 ubsan_handle_error(__func__, &data->loc, should_panic); 170 } 171 172 void __ubsan_handle_add_overflow(void *data_, void *lhs __unused, 173 void *rhs __unused) 174 { 175 struct overflow_data *data = data_; 176 177 ubsan_handle_error(__func__, &data->loc, should_panic); 178 } 179 180 void __ubsan_handle_sub_overflow(void *data_, void *lhs __unused, 181 void *rhs __unused) 182 { 183 struct overflow_data *data = data_; 184 185 ubsan_handle_error(__func__, &data->loc, should_panic); 186 } 187 188 void __ubsan_handle_mul_overflow(void *data_, void *lhs __unused, 189 void *rhs __unused) 190 { 191 struct overflow_data *data = data_; 192 193 ubsan_handle_error(__func__, &data->loc, should_panic); 194 } 195 196 void __ubsan_handle_negate_overflow(void *data_, void *old_val __unused) 197 { 198 struct overflow_data *data = data_; 199 200 ubsan_handle_error(__func__, &data->loc, should_panic); 201 } 202 203 void __ubsan_handle_divrem_overflow(void *data_, void *lhs __unused, 204 void *rhs __unused) 205 { 206 struct overflow_data *data = data_; 207 208 ubsan_handle_error(__func__, &data->loc, should_panic); 209 } 210 211 void __ubsan_handle_pointer_overflow(void *data_, void *lhs __unused, 212 void *rhs __unused) 213 { 214 struct overflow_data *data = data_; 215 216 ubsan_handle_error(__func__, &data->loc, should_panic); 217 } 218 219 void __ubsan_handle_shift_out_of_bounds(void *data_, void *lhs __unused, 220 void *rhs __unused) 221 { 222 struct shift_out_of_bounds_data *data = data_; 223 224 ubsan_handle_error(__func__, &data->loc, should_panic); 225 } 226 227 void __ubsan_handle_out_of_bounds(void *data_, void *idx __unused) 228 { 229 struct out_of_bounds_data *data = data_; 230 231 ubsan_handle_error(__func__, &data->loc, should_panic); 232 } 233 234 void __noreturn __ubsan_handle_builtin_unreachable(void *data_) 235 { 236 struct unreachable_data *data = data_; 237 238 ubsan_handle_error(__func__, &data->loc, false); 239 ubsan_panic(); 240 } 241 242 void __noreturn __ubsan_handle_missing_return(void *data_) 243 { 244 struct unreachable_data *data = data_; 245 246 ubsan_handle_error(__func__, &data->loc, false); 247 ubsan_panic(); 248 } 249 250 void __ubsan_handle_vla_bound_not_positive(void *data_, void *bound __unused) 251 { 252 struct vla_bound_data *data = data_; 253 254 ubsan_handle_error(__func__, &data->loc, should_panic); 255 } 256 257 void __ubsan_handle_load_invalid_value(void *data_, void *val __unused) 258 { 259 struct invalid_value_data *data = data_; 260 261 ubsan_handle_error(__func__, &data->loc, should_panic); 262 } 263 264 void __ubsan_handle_nonnull_arg(void *data_ 265 #if __GCC_VERSION < 60000 266 , size_t arg_no __unused 267 #endif 268 ) 269 { 270 struct nonnull_arg_data *data = data_; 271 272 ubsan_handle_error(__func__, &data->loc, should_panic); 273 } 274 275 void __ubsan_handle_invalid_builtin(void *data_) 276 { 277 struct invalid_builtin_data *data = data_; 278 279 ubsan_handle_error(__func__, &data->loc, should_panic); 280 } 281