luna: Add UB sanitizer, for both kernel-space and userspace

This commit is contained in:
apio 2023-02-25 17:37:38 +01:00
parent 96a213ec5c
commit d82b3f809b
Signed by: apio
GPG Key ID: B8A7D06E42258954
3 changed files with 196 additions and 0 deletions

View File

@ -17,6 +17,7 @@ set(FREESTANDING_SOURCES
src/DebugLog.cpp src/DebugLog.cpp
src/Heap.cpp src/Heap.cpp
src/Spinlock.cpp src/Spinlock.cpp
src/UBSAN.cpp
) )
set(SOURCES set(SOURCES

74
luna/include/luna/UBSAN.h Normal file
View File

@ -0,0 +1,74 @@
#pragma once
#include <luna/Types.h>
namespace UBSAN
{
struct SourceLocation
{
const char* file;
u32 line;
u32 column;
};
struct TypeDescriptor
{
u16 kind;
u16 info;
char name[];
};
namespace UBInfo
{
struct TypeMismatchInfo
{
SourceLocation location;
TypeDescriptor* type;
usize alignment;
u8 type_check_kind;
};
struct TypeMismatchInfo_v1
{
SourceLocation location;
TypeDescriptor* type;
u8 log_alignment;
u8 type_check_kind;
};
struct OverflowInfo
{
SourceLocation location;
TypeDescriptor* type;
};
struct UnreachableInfo
{
SourceLocation location;
};
struct OutOfBoundsInfo
{
SourceLocation location;
TypeDescriptor* array_type;
TypeDescriptor* index_type;
};
struct InvalidValueInfo
{
SourceLocation location;
TypeDescriptor* type;
};
struct ShiftOutOfBoundsInfo
{
SourceLocation location;
TypeDescriptor* lhs_type;
TypeDescriptor* rhs_type;
};
struct PointerOverflowInfo
{
SourceLocation location;
};
}
}

121
luna/src/UBSAN.cpp Normal file
View File

@ -0,0 +1,121 @@
#include <luna/Check.h>
#include <luna/DebugLog.h>
#include <luna/SourceLocation.h>
#include <luna/UBSAN.h>
using namespace UBSAN::UBInfo;
[[noreturn]] void ub_panic(SourceLocation caller = SourceLocation::current())
{
expect_at(false, caller, "Undefined behavior");
}
#define DISPLAY(loc) loc.file, loc.line, loc.column
extern "C"
{
void __ubsan_handle_builtin_unreachable(UnreachableInfo* info)
{
const auto& location = info->location;
dbgln("ubsan: __builtin_unreachable reached at %s:%d:%d", DISPLAY(location));
ub_panic();
}
void __ubsan_handle_pointer_overflow(PointerOverflowInfo* info)
{
const auto& location = info->location;
dbgln("ubsan: pointer overflow occurred at %s:%d:%d", DISPLAY(location));
ub_panic();
}
void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsInfo* info)
{
const auto& location = info->location;
dbgln("ubsan: shift out of bounds for type %s at %s:%d:%d", info->lhs_type->name, DISPLAY(location));
ub_panic();
}
void __ubsan_handle_load_invalid_value(InvalidValueInfo* info)
{
const auto& location = info->location;
dbgln("ubsan: load invalid value for type %s at %s:%d:%d", info->type->name, DISPLAY(location));
ub_panic();
}
void __ubsan_handle_out_of_bounds(OutOfBoundsInfo* info, usize index)
{
const auto& location = info->location;
dbgln("ubsan: out of bounds array (of type %s) access (index %zu of type %s) at %s:%d:%d",
info->array_type->name, index, info->index_type->name, DISPLAY(location));
ub_panic();
}
void ubsan_handle_generic_overflow(OverflowInfo* info, const char* overflow_type)
{
const auto& location = info->location;
dbgln("ubsan: %s overflow (value cannot fit into type %s) at %s:%d:%d", overflow_type, info->type->name,
DISPLAY(location));
ub_panic();
}
#define UBSAN_OVERFLOW_BINARY(operation) \
void __ubsan_handle_##operation##_overflow(OverflowInfo* info, usize, usize) \
{ \
ubsan_handle_generic_overflow(info, #operation); \
}
#define UBSAN_OVERFLOW_UNARY(operation) \
void __ubsan_handle_##operation##_overflow(OverflowInfo* info, usize) \
{ \
ubsan_handle_generic_overflow(info, #operation); \
}
UBSAN_OVERFLOW_BINARY(add);
UBSAN_OVERFLOW_BINARY(sub);
UBSAN_OVERFLOW_BINARY(mul);
UBSAN_OVERFLOW_UNARY(negate);
UBSAN_OVERFLOW_BINARY(divrem);
#define is_aligned(value, alignment) !(value & (alignment - 1))
const char* g_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",
};
void __ubsan_handle_type_mismatch(TypeMismatchInfo* info, usize pointer)
{
const auto& location = info->location;
if (pointer == 0) { dbgln("ubsan: null pointer access at %s:%d:%d", DISPLAY(location)); }
else if (info->alignment != 0 && is_aligned(pointer, info->alignment))
{
dbgln("ubsan: unaligned pointer access (address %p) at %s:%d:%d", (void*)pointer, DISPLAY(location));
}
else
{
dbgln("ubsan: %s address %p with insufficient space for object of type %s at %s:%d:%d",
g_type_check_kinds[info->type_check_kind], (void*)pointer, info->type->name, DISPLAY(location));
}
ub_panic();
}
void __ubsan_handle_type_mismatch_v1(TypeMismatchInfo_v1* v1_info, usize pointer)
{
TypeMismatchInfo info = {
.location = v1_info->location,
.type = v1_info->type,
.alignment = 1UL << v1_info->log_alignment,
.type_check_kind = v1_info->type_check_kind,
};
__ubsan_handle_type_mismatch(&info, pointer);
}
}