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