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