From 4d5496b2b2afb5be6bbf606c97a18b76327f152b Mon Sep 17 00:00:00 2001 From: Hendiadyoin1 <37629766+Hendiadyoin1@users.noreply.github.com> Date: Thu, 11 Feb 2021 20:58:01 +0100 Subject: [PATCH] KUBSAN: Add nearly all missing -fsanitize handlers (#5254) --- Kernel/CMakeLists.txt | 31 +++++++++- Kernel/UBSanitizer.cpp | 130 ++++++++++++++++++++++++++++++++++------- Kernel/UBSanitizer.h | 28 +++++++++ 3 files changed, 167 insertions(+), 22 deletions(-) diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index ddee7aaa67f..8f9d6ec94f4 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -269,8 +269,37 @@ set(SOURCES ${CRYPTO_SOURCES} ${C_SOURCES} ) +set(KERNEL_FSANITIZE_FLAGS + "shift" + "shift-exponent" + "shift-base" + "integer-divide-by-zero" + "unreachable" + "vla-bound" + "return" + "signed-integer-overflow" + "bounds" + "bounds-strict" + "object-size" + "float-divide-by-zero" + "float-cast-overflow" + "nonnull-attribute" + "returns-nonnull-attribute" + "bool" + "enum" + "vptr" + "builtin" + # following flags will cause triple faults: + # "alignment" + # "null" + # "pointer-overflow" + ) + +foreach(flag IN LISTS KERNEL_FSANITIZE_FLAGS) + message("\tkernel fsanitize flag:${flag}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${flag}") +endforeach() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=nonnull-attribute,returns-nonnull-attribute,bool,vla-bound,signed-integer-overflow,shift,shift-exponent,shift-base,integer-divide-by-zero,return,bounds,bounds-strict,object-size,enum,vptr") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option -DKERNEL") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pie -fPIE -fno-rtti -ffreestanding -fbuiltin") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mno-80387 -mno-mmx -mno-sse -mno-sse2") diff --git a/Kernel/UBSanitizer.cpp b/Kernel/UBSanitizer.cpp index f3f159c3710..da53961dac1 100644 --- a/Kernel/UBSanitizer.cpp +++ b/Kernel/UBSanitizer.cpp @@ -35,12 +35,17 @@ extern "C" { static void print_location(const SourceLocation& location) { - dbgln("KUBSAN: at {}, line {}, column: {}", location.filename(), location.line(), location.column()); + if (!location.filename()) { + dbgln("KUBSAN: in unknown file"); + + } else { + dbgln("KUBSAN: at {}, line {}, column: {}", location.filename(), location.line(), location.column()); + } dump_backtrace(); } -void __ubsan_handle_load_invalid_value(const InvalidValueData&, void*); -void __ubsan_handle_load_invalid_value(const InvalidValueData& data, void*) +void __ubsan_handle_load_invalid_value(const InvalidValueData&, ValueHandle); +void __ubsan_handle_load_invalid_value(const InvalidValueData& data, ValueHandle) { dbgln("KUBSAN: load-invalid-value: {} ({}-bit)", data.type.name(), data.type.bit_width()); print_location(data.location); @@ -53,6 +58,13 @@ void __ubsan_handle_nonnull_arg(const NonnullArgData& data) print_location(data.location); } +void __ubsan_handle_nullability_arg(const NonnullArgData&); +void __ubsan_handle_nullability_arg(const NonnullArgData& data) +{ + dbgln("KUBSAN: null pointer passed as argument {}, which is declared to never be null", data.argument_index); + print_location(data.location); +} + void __ubsan_handle_nonnull_return_v1(const NonnullReturnData&, const SourceLocation&); void __ubsan_handle_nonnull_return_v1(const NonnullReturnData&, const SourceLocation& location) { @@ -60,66 +72,142 @@ void __ubsan_handle_nonnull_return_v1(const NonnullReturnData&, const SourceLoca print_location(location); } -void __ubsan_handle_vla_bound_not_positive(const VLABoundData&, void*); -void __ubsan_handle_vla_bound_not_positive(const VLABoundData& data, void*) +void __ubsan_handle_nullability_return_v1(const NonnullReturnData& data, const SourceLocation& location); +void __ubsan_handle_nullability_return_v1(const NonnullReturnData&, const SourceLocation& location) +{ + dbgln("KUBSAN: null pointer return from function declared to never return null"); + print_location(location); +} + +void __ubsan_handle_vla_bound_not_positive(const VLABoundData&, ValueHandle); +void __ubsan_handle_vla_bound_not_positive(const VLABoundData& data, ValueHandle) { dbgln("KUBSAN: VLA bound not positive {} ({}-bit)", data.type.name(), data.type.bit_width()); print_location(data.location); } -void __ubsan_handle_add_overflow(const OverflowData&, void* lhs, void* rhs); -void __ubsan_handle_add_overflow(const OverflowData& data, void*, void*) +void __ubsan_handle_add_overflow(const OverflowData&, ValueHandle lhs, ValueHandle rhs); +void __ubsan_handle_add_overflow(const OverflowData& data, ValueHandle, ValueHandle) { dbgln("KUBSAN: addition overflow, {} ({}-bit)", data.type.name(), data.type.bit_width()); + print_location(data.location); } -void __ubsan_handle_sub_overflow(const OverflowData&, void* lhs, void* rhs); -void __ubsan_handle_sub_overflow(const OverflowData& data, void*, void*) +void __ubsan_handle_sub_overflow(const OverflowData&, ValueHandle lhs, ValueHandle rhs); +void __ubsan_handle_sub_overflow(const OverflowData& data, ValueHandle, ValueHandle) { dbgln("KUBSAN: subtraction overflow, {} ({}-bit)", data.type.name(), data.type.bit_width()); + print_location(data.location); } -void __ubsan_handle_negate_overflow(const OverflowData&, void*); -void __ubsan_handle_negate_overflow(const OverflowData& data, void*) +void __ubsan_handle_negate_overflow(const OverflowData&, ValueHandle); +void __ubsan_handle_negate_overflow(const OverflowData& data, ValueHandle) { + dbgln("KUBSAN: negation overflow, {} ({}-bit)", data.type.name(), data.type.bit_width()); + print_location(data.location); } -void __ubsan_handle_mul_overflow(const OverflowData&, void* lhs, void* rhs); -void __ubsan_handle_mul_overflow(const OverflowData& data, void*, void*) +void __ubsan_handle_mul_overflow(const OverflowData&, ValueHandle lhs, ValueHandle rhs); +void __ubsan_handle_mul_overflow(const OverflowData& data, ValueHandle, ValueHandle) { dbgln("KUBSAN: multiplication overflow, {} ({}-bit)", data.type.name(), data.type.bit_width()); print_location(data.location); } -void __ubsan_handle_shift_out_of_bounds(const ShiftOutOfBoundsData&, void* lhs, void* rhs); -void __ubsan_handle_shift_out_of_bounds(const ShiftOutOfBoundsData& data, void*, void*) +void __ubsan_handle_shift_out_of_bounds(const ShiftOutOfBoundsData&, ValueHandle lhs, ValueHandle rhs); +void __ubsan_handle_shift_out_of_bounds(const ShiftOutOfBoundsData& data, ValueHandle, ValueHandle) { dbgln("KUBSAN: shift out of bounds, {} ({}-bit) shifted by {} ({}-bit)", data.lhs_type.name(), data.lhs_type.bit_width(), data.rhs_type.name(), data.rhs_type.bit_width()); print_location(data.location); } -void __ubsan_handle_divrem_overflow(const OverflowData&, void* lhs, void* rhs); -void __ubsan_handle_divrem_overflow(const OverflowData& data, void*, void*) +void __ubsan_handle_divrem_overflow(const OverflowData&, ValueHandle lhs, ValueHandle rhs); +void __ubsan_handle_divrem_overflow(const OverflowData& data, ValueHandle, ValueHandle) { dbgln("KUBSAN: divrem overlow, {} ({}-bit)", data.type.name(), data.type.bit_width()); print_location(data.location); } -void __ubsan_handle_out_of_bounds(const OutOfBoundsData&, void*); -void __ubsan_handle_out_of_bounds(const OutOfBoundsData& data, void*) +void __ubsan_handle_out_of_bounds(const OutOfBoundsData&, ValueHandle); +void __ubsan_handle_out_of_bounds(const OutOfBoundsData& data, ValueHandle) { dbgln("KUBSAN: out of bounds access into array of {} ({}-bit), index type {} ({}-bit)", data.array_type.name(), data.array_type.bit_width(), data.index_type.name(), data.index_type.bit_width()); print_location(data.location); } -void __ubsan_handle_type_mismatch_v1(const TypeMismatchData&, void*); -void __ubsan_handle_type_mismatch_v1(const TypeMismatchData& data, void*) +void __ubsan_handle_type_mismatch_v1(const TypeMismatchData&, ValueHandle); +void __ubsan_handle_type_mismatch_v1(const TypeMismatchData& data, ValueHandle) { dbgln("KUBSAN: type mismatch, {} ({}-bit)", data.type.name(), data.type.bit_width()); print_location(data.location); } + +// FIXME: Causes a triple fault on boot +void __ubsan_handle_alignment_assumption(const AlignmentAssumptionData&, ValueHandle, ValueHandle, ValueHandle); +void __ubsan_handle_alignment_assumption(const AlignmentAssumptionData& data, ValueHandle pointer, ValueHandle alignment, ValueHandle offset) +{ + if (offset) { + dbgln( + "KUBSAN: assumption of {:p} byte alignment (with offset of {:p} byte) for pointer {:p}" + "of type {} failed", + alignment, offset, pointer, data.type.name()); + } else { + dbgln("KUBSAN: assumption of {:p} byte alignment for pointer {:p}" + "of type {} failed", + alignment, pointer, data.type.name()); + } + // dbgln("KUBSAN: Assumption of pointer allignment failed"); + print_location(data.location); +} + +void __ubsan_handle_builtin_unreachable(const UnreachableData&); +void __ubsan_handle_builtin_unreachable(const UnreachableData& data) +{ + dbgln("KUBSAN: execution reached an unreachable program point"); + print_location(data.location); +} + +void __ubsan_handle_missing_return(const UnreachableData&); +void __ubsan_handle_missing_return(const UnreachableData& data) +{ + dbgln("KUBSAN: execution reached the end of a value-returning function without returning a value"); + print_location(data.location); +} + +void __ubsan_handle_implicit_conversion(const ImplicitConversionData&, ValueHandle, ValueHandle); +void __ubsan_handle_implicit_conversion(const ImplicitConversionData& data, ValueHandle, ValueHandle) +{ + const char* src_signed = data.from_type.is_signed() ? "" : "un"; + const char* dst_signed = data.to_type.is_signed() ? "" : "un"; + dbgln("KUBSAN: implicit conversion from type {} ({}-bit, {}signed) to type {} ({}-bit, {}signed)", + data.from_type.name(), data.from_type.bit_width(), src_signed, data.to_type.name(), data.to_type.bit_width(), dst_signed); + print_location(data.location); +} + +void __ubsan_handle_invalid_builtin(const InvalidBuiltinData); +void __ubsan_handle_invalid_builtin(const InvalidBuiltinData data) +{ + dbgln("KUBSAN: passing invalid argument"); + print_location(data.location); +} + +// FIXME: Causes a triple fault on boot +void __ubsan_handle_pointer_overflow(const PointerOverflowData&, ValueHandle, ValueHandle); +void __ubsan_handle_pointer_overflow(const PointerOverflowData& data, ValueHandle base, ValueHandle result) +{ + if (base == 0 && result == 0) { + dbgln("KUBSAN: applied zero offset to nullptr"); + } else if (base == 0 && result != 0) { + dbgln("KUBSAN: applied non-zero offset {:p} to nullptr", result); + } else if (base != 0 && result == 0) { + dbgln("KUBSAN: applying non-zero offset to non-null pointer {:p} produced null pointer", base); + } else { + dbgln("KUBSAN: addition of unsigned offset to {:p} overflowed to {:p}", base, result); + } + print_location(data.location); +} } diff --git a/Kernel/UBSanitizer.h b/Kernel/UBSanitizer.h index 6553503b94d..4031139b63c 100644 --- a/Kernel/UBSanitizer.h +++ b/Kernel/UBSanitizer.h @@ -30,6 +30,8 @@ namespace Kernel::UBSanitizer { +typedef void* ValueHandle; + class SourceLocation { public: const char* filename() const { return m_filename; } @@ -107,4 +109,30 @@ struct TypeMismatchData { u8 type_check_kind; }; +struct AlignmentAssumptionData { + SourceLocation location; + SourceLocation assumption_location; + const TypeDescriptor& type; +}; + +struct UnreachableData { + SourceLocation location; +}; + +struct ImplicitConversionData { + SourceLocation location; + const TypeDescriptor& from_type; + const TypeDescriptor& to_type; + /* ImplicitConversionCheckKind */ unsigned char kind; +}; + +struct InvalidBuiltinData { + SourceLocation location; + unsigned char kind; +}; + +struct PointerOverflowData { + SourceLocation location; +}; + }