Kernel: Add UBSAN (Undefined Behaviour Sanitizer)

This commit is contained in:
apio 2022-11-05 10:47:18 +01:00
parent ffcaac0ca3
commit d0efc106b0
4 changed files with 212 additions and 3 deletions

View File

@ -14,7 +14,7 @@ CFLAGS := ${CFLAGS} -D_MOON_SUFFIX=-$(shell git rev-parse --short HEAD)
endif endif
ifeq ($(MOON_BUILD_DEBUG), 1) ifeq ($(MOON_BUILD_DEBUG), 1)
CFLAGS := -ggdb ${CFLAGS} CFLAGS := -ggdb -fsanitize=undefined ${CFLAGS}
endif endif
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d)) rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
@ -45,6 +45,10 @@ $(MOON_OBJ)/%.cpp.o: $(MOON_SRC)/%.cpp
@mkdir -p $(@D) @mkdir -p $(@D)
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^ $(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/memory/liballoc/liballoc.c.o: $(MOON_SRC)/memory/liballoc/liballoc.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -fno-sanitize=undefined -o $@ -c $^
$(MOON_OBJ)/%.c.o: $(MOON_SRC)/%.c $(MOON_OBJ)/%.c.o: $(MOON_SRC)/%.c
@mkdir -p $(@D) @mkdir -p $(@D)
$(CC) $(CFLAGS) -o $@ -c $^ $(CC) $(CFLAGS) -o $@ -c $^

View File

@ -76,7 +76,7 @@ bool CPU::has_nx()
static bool _has_feature(int feature) static bool _has_feature(int feature)
{ {
return (CPU::get_feature_bitmask() & (uint64_t)(1 << feature)) > 0; return (CPU::get_feature_bitmask() & (uint64_t)(1UL << feature)) > 0;
} }
bool CPU::has_feature(CPU::Features feature) bool CPU::has_feature(CPU::Features feature)

View File

@ -56,7 +56,7 @@ InitRD::File InitRD::get_file(TarHeader* header)
File result; File result;
result.size = 0; result.size = 0;
memcpy(result.name, header->name, 100); memcpy(result.name, header->name, 100);
int multiplier = long multiplier =
1; // why they decided to store the size as an octal-encoded string instead of an integer is beyond me 1; // why they decided to store the size as an octal-encoded string instead of an integer is beyond me
for (int i = 10; i >= 0; i--) for (int i = 10; i >= 0; i--)
{ {

205
kernel/src/misc/ubsan.cpp Normal file
View File

@ -0,0 +1,205 @@
#define MODULE "ubsan"
#include <log/Log.h>
#include <panic/Panic.h>
#include <stdint.h>
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wpedantic"
struct source_location
{
const char* file;
uint32_t line;
uint32_t column;
};
struct type_descriptor
{
uint16_t kind;
uint16_t info;
char name[];
};
struct type_mismatch_info
{
struct source_location location;
struct type_descriptor* type;
uintptr_t alignment;
uint8_t type_check_kind;
};
struct type_mismatch_info_v1
{
struct source_location location;
struct type_descriptor* type;
unsigned char log_alignment;
unsigned char type_check_kind;
};
struct overflow_info
{
struct source_location location;
struct type_descriptor* type;
};
struct unreachable_info
{
struct source_location location;
};
struct out_of_bounds_info
{
struct source_location location;
struct type_descriptor* array_type;
struct type_descriptor* index_type;
};
struct invalid_value_info
{
struct source_location location;
struct type_descriptor* type;
};
struct shift_out_of_bounds_info
{
struct source_location location;
struct type_descriptor* lhs_type;
struct type_descriptor* rhs_type;
};
struct pointer_overflow_info
{
struct source_location location;
};
#define is_aligned(value, alignment) !(value & (alignment - 1))
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",
"upcast of",
"cast to virtual base of",
};
static void log_location(source_location* location)
{
kinfoln("at %s:%d:%d", location->file, location->line, location->column);
}
extern "C" void __ubsan_handle_type_mismatch(type_mismatch_info* type_mismatch, uintptr_t pointer)
{
source_location* location = &type_mismatch->location;
if (pointer == 0) { kinfoln("Null pointer access"); }
else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment))
{
// Most useful on architectures with stricter memory alignment requirements, like ARM.
kinfoln("Unaligned memory access");
}
else
{
kinfoln("Insufficient size");
kinfoln("%s address %p with insufficient space for object of type %s\n",
Type_Check_Kinds[type_mismatch->type_check_kind], (void*)pointer, type_mismatch->type->name);
}
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_type_mismatch_v1(type_mismatch_info_v1* type_mismatch, unsigned long pointer)
{
type_mismatch_info info = {type_mismatch->location, type_mismatch->type, 1UL << type_mismatch->log_alignment,
type_mismatch->type_check_kind};
__ubsan_handle_type_mismatch(&info, pointer);
}
extern "C" void __ubsan_handle_add_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Addition overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_sub_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Substraction overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_mul_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Multiplication overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_negate_overflow(overflow_info* overflow_data, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Negation overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_divrem_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &overflow_data->location;
kinfoln("Division overflow for two values of type %s", overflow_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_builtin_unreachable(unreachable_info* unreachable_data)
{
source_location* location = &unreachable_data->location;
kinfoln("Reached the unreachable");
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_out_of_bounds(out_of_bounds_info* out_of_bounds_data, uintptr_t index)
{
source_location* location = &out_of_bounds_data->location;
kinfoln("Out of bounds access at index %ld of array type %s and index type %s", index,
out_of_bounds_data->array_type->name, out_of_bounds_data->index_type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_load_invalid_value(invalid_value_info* invalid_value_data, uintptr_t)
{
source_location* location = &invalid_value_data->location;
kinfoln("Invalid value load of type %s", invalid_value_data->type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_shift_out_of_bounds(shift_out_of_bounds_info* shift_out_of_bounds_data, uintptr_t,
uintptr_t)
{
source_location* location = &shift_out_of_bounds_data->location;
kinfoln("Shift out of bounds for type %s", shift_out_of_bounds_data->lhs_type->name);
log_location(location);
panic("Undefined behaviour detected");
}
extern "C" void __ubsan_handle_pointer_overflow(pointer_overflow_info* pointer_overflow_data, uintptr_t, uintptr_t)
{
source_location* location = &pointer_overflow_data->location;
kinfoln("Pointer overflow");
log_location(location);
panic("Undefined behaviour detected");
}
#pragma GCC pop_options