Files
mckernel/kernel/ubsan.c
Dominique Martinet 2f456b8752 cmake: Add ENABLE_UBSAN for -fsanitize=undefined
Change-Id: I73db5f904a7d86052aae62e67b01281763c83561
2019-02-14 16:44:09 +09:00

227 lines
4.9 KiB
C

/*
* UBSAN handlers
* Types shamelessly copied over from linux
*/
#include <string.h>
#include <lwk/stddef.h>
#include <kmsg.h>
#include <kmalloc.h>
enum {
type_kind_int = 0,
type_kind_float = 1,
type_unknown = 0xffff
};
struct type_descriptor {
short type_kind;
short type_info;
char type_name[1];
};
struct source_location {
const char *file_name;
union {
unsigned long reported;
struct {
int line;
int column;
};
};
};
struct type_mismatch_data_v1 {
struct source_location location;
struct type_descriptor *type;
unsigned char log_alignment;
unsigned char type_check_kind;
};
struct type_mismatch_data {
struct source_location location;
struct type_descriptor *type;
unsigned long alignment;
unsigned char type_check_kind;
};
struct overflow_data {
struct source_location location;
struct type_descriptor *type;
};
struct nonnull_arg_data {
struct source_location location;
struct source_location attr_location;
int arg_index;
};
struct vla_bound_data {
struct source_location location;
struct type_descriptor *type;
};
struct out_of_bounds_data {
struct source_location location;
struct type_descriptor *array_type;
struct type_descriptor *index_type;
};
struct shift_out_of_bounds_data {
struct source_location location;
struct type_descriptor *lhs_type;
struct type_descriptor *rhs_type;
};
struct unreachable_data {
struct source_location location;
};
struct invalid_value_data {
struct source_location location;
struct type_descriptor *type;
};
struct pointer_overflow_data {
struct source_location location;
};
const char *type_check_kinds[] = {
"load of",
"store to",
"reference binding to",
"member access within",
"member call on",
"constructor call on",
"downcast of",
"downcast of"
};
#define REPORTED_BIT 31
#define COLUMN_MASK (~(1U << REPORTED_BIT))
#define LINE_MASK (~0U)
#define VALUE_LENGTH 40
void ubsan_prologue(struct source_location *loc)
{
kprintf("UBSAN: Undefined behaviour in %s:%d:%d\n", loc->file_name,
loc->line & LINE_MASK, loc->column & COLUMN_MASK);
}
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
unsigned long ptr)
{
ubsan_prologue(&data->location);
if (!ptr) {
kprintf("%s: null pointer deref\n", __func__);
} else if (data->alignment && !IS_ALIGNED(ptr, data->alignment)) {
kprintf("%s: pointer %#16lx of type %s is not aligned at %#lx\n",
__func__, ptr, data->type->type_name, data->alignment);
} else {
kprintf("%s: %s address %#16lx with insufficient space for an object of type %s\n",
__func__, type_check_kinds[data->type_check_kind], ptr,
data->type->type_name);
}
}
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data_v1,
unsigned long ptr)
{
struct type_mismatch_data data = {
.location = data_v1->location,
.type = data_v1->type,
.alignment = 1UL << data_v1->log_alignment,
.type_check_kind = data_v1->type_check_kind,
};
__ubsan_handle_type_mismatch(&data, ptr);
}
void __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
unsigned long base, unsigned long result)
{
ubsan_prologue(&data->location);
kprintf("%s: pointer overflow from %lx to %lx\n",
__func__, base, result);
}
void __ubsan_handle_add_overflow(struct overflow_data *data,
unsigned long lhs,
unsigned long rhs)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx %lx\n", __func__, lhs, rhs);
}
void __ubsan_handle_sub_overflow(struct overflow_data *data,
unsigned long lhs,
unsigned long rhs)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx %lx\n", __func__, lhs, rhs);
}
void __ubsan_handle_mul_overflow(struct overflow_data *data,
unsigned long lhs,
unsigned long rhs)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx %lx\n", __func__, lhs, rhs);
}
void __ubsan_handle_negate_overflow(struct overflow_data *data,
unsigned long old_val)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx\n", __func__, old_val);
}
void __ubsan_handle_divrem_overflow(struct overflow_data *data,
unsigned long lhs,
unsigned long rhs)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx %lx\n", __func__, lhs, rhs);
}
void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
unsigned long bound)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx\n", __func__, bound);
}
void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
unsigned long index)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx\n", __func__, index);
}
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
unsigned long lhs, unsigned long rhs)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx %lx\n", __func__, lhs, rhs);
}
void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
{
ubsan_prologue(&data->location);
kprintf("%s\n", __func__);
panic(__func__);
}
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
unsigned long val)
{
ubsan_prologue(&data->location);
kprintf("%s: %lx\n", __func__, val);
}