diff --git a/CMakeLists.txt b/CMakeLists.txt index ac822c1a..edc10cfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ option(ENABLE_RUSAGE "Enable rusage support" ON) option(ENABLE_MCOVERLAYFS "Enable overlay filesystem" OFF) option(ENABLE_QLMPI "Enable qlmpi programs" OFF) option(ENABLE_UTI "Enable uti support" OFF) +option(ENABLE_UBSAN "Enable undefined behaviour sanitizer on mckernel size" OFF) find_library(LIBRT rt) find_library(LIBNUMA numa) @@ -187,4 +188,5 @@ message("ENABLE_MCOVERLAYFS: ${ENABLE_MCOVERLAYFS}") message("ENABLE_QLMPI: ${ENABLE_QLMPI}") message("ENABLE_UTI: ${ENABLE_UTI}") message("ENABLE_WERROR: ${ENABLE_WERROR}") +message("ENABLE_UBSAN: ${ENABLE_UBSAN}") message("-------------------------------") diff --git a/config.h.in b/config.h.in index bedd0af0..e4571f32 100644 --- a/config.h.in +++ b/config.h.in @@ -24,6 +24,9 @@ /* whether UTI is enabled */ #cmakedefine ENABLE_UTI 1 +/* whether undefined behaviour sanitizer is enabled */ +#cmakedefine ENABLE_UBSAN 1 + /* Path of bind-mount source directory */ #cmakedefine ROOTFSDIR "${ROOTFSDIR}" diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 43835d80..42ef605f 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -45,6 +45,11 @@ set(MCKERNEL_SRCS ${IHK_FULL_SOURCE_DIR}/cokernel/smp/${ARCH}/setup.c ) +if (ENABLE_UBSAN) + add_compile_options(-fsanitize=undefined) + list(APPEND MCKERNEL_SRCS ubsan.c) +endif(ENABLE_UBSAN) + if (BUILD_TARGET STREQUAL "smp-x86") list(APPEND MCKERNEL_SRCS ${PROJECT_SOURCE_DIR}/arch/${ARCH}/kernel/context.S diff --git a/kernel/ubsan.c b/kernel/ubsan.c new file mode 100644 index 00000000..b41251ee --- /dev/null +++ b/kernel/ubsan.c @@ -0,0 +1,226 @@ +/* + * UBSAN handlers + * Types shamelessly copied over from linux + */ + +#include +#include +#include +#include + +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); +} + diff --git a/lib/include/bitops.h b/lib/include/bitops.h index 61a61cf2..957b1702 100644 --- a/lib/include/bitops.h +++ b/lib/include/bitops.h @@ -51,6 +51,7 @@ static inline unsigned long hweight_long(unsigned long w) #define __ALIGN_MASK(x, mask) __ALIGN_KERNEL_MASK((x), (mask)) #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) #endif /*__ASSEMBLY__*/