summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksa Vuckovic <aleksav013@gmail.com>2022-11-25 23:44:40 +0100
committerAleksa Vuckovic <aleksav013@gmail.com>2022-11-25 23:44:40 +0100
commit5d56d1a5b4d52702eb4e4ea6f05e4b6eebf41ca8 (patch)
tree1ddc17cf4524254edf322da50e5c12261715b648
parent3ec35b5abeb9765c419cf896338de7d95143bc9b (diff)
UBSAN - FINALLY FIXING UNDEFINED BEHAVIOUR
-rw-r--r--Makefile5
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/include/libk/serial_stdio.h12
-rw-r--r--kernel/include/ubsan.h5
-rw-r--r--kernel/src/boot/multiboot2.c2
-rw-r--r--kernel/src/cpu/gdt.c2
-rw-r--r--kernel/src/libk/serial_stdio.c61
-rw-r--r--kernel/src/ubsan/ubsan.c387
8 files changed, 472 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index dbce783..1eb51c9 100644
--- a/Makefile
+++ b/Makefile
@@ -7,8 +7,8 @@ LD = $(ARCH)ld
OBJDUMP = $(ARCH)objcopy
OBJCOPY = $(ARCH)objdump
-W := -Wall -Werror -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align
-W += -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations
+W := -Wall -Werror -Wextra -Wshadow -Wpointer-arith -Wcast-align
+W += -Wwrite-strings
W += -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wconversion
W += -Wstrict-prototypes
WNO := -Wno-error=unused-parameter -Wno-error=unused-variable
@@ -19,6 +19,7 @@ CFLAGS += -mgeneral-regs-only # disables SIMD instructions
CFLAGS += -MD -O3 -ffreestanding -nostdlib
CFLAGS += -fno-common -fno-stack-protector
CFLAGS += -fno-pie -no-pie -fno-pic
+CFLAGS += -g -fsanitize=undefined
LDFLAGS = -z max-page-size=4096
MAKE:=$(MAKE) -s
diff --git a/kernel/Makefile b/kernel/Makefile
index 981af74..a8fd434 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -19,6 +19,7 @@ OBJS = \
src/fs/ext2.o \
src/libk/list.o \
src/libk/math.o \
+ src/libk/serial_stdio.o \
src/libk/stdio.o \
src/libk/string.o \
src/main.o \
@@ -31,6 +32,7 @@ OBJS = \
src/sys/syscall.o \
src/sys/userspace_asm.o \
src/sys/userspace.o \
+ src/ubsan/ubsan.o \
all: kernel.bin
diff --git a/kernel/include/libk/serial_stdio.h b/kernel/include/libk/serial_stdio.h
new file mode 100644
index 0000000..17317d0
--- /dev/null
+++ b/kernel/include/libk/serial_stdio.h
@@ -0,0 +1,12 @@
+#ifndef SERIAL_STDIO_H
+#define SERIAL_STDIO_H
+
+#include <types.h>
+
+void serial_print_char(char c);
+void serial_print_string(const char* s);
+void serial_print_int(uint64_t num);
+void serial_print_hex(uint64_t num);
+void serial_printf(const char *s, ...);
+
+#endif
diff --git a/kernel/include/ubsan.h b/kernel/include/ubsan.h
new file mode 100644
index 0000000..733cca0
--- /dev/null
+++ b/kernel/include/ubsan.h
@@ -0,0 +1,5 @@
+#ifndef UBSAN_H
+#define UBSAN_H
+
+
+#endif
diff --git a/kernel/src/boot/multiboot2.c b/kernel/src/boot/multiboot2.c
index cdc0ae4..9410273 100644
--- a/kernel/src/boot/multiboot2.c
+++ b/kernel/src/boot/multiboot2.c
@@ -77,7 +77,7 @@ void read_mb2(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic)
static mb2_tag_mmap* tag_mmap;
// skip first 8 bytes (total_size + reserved)
- mb2_tag_header* tag_header = (mb2_tag_header*)((char*)multiboot_bootinfo + 8 + KERNEL_VMA);
+ mb2_tag_header* tag_header = (mb2_tag_header*)((uint64_t)multiboot_bootinfo + 8 + KERNEL_VMA);
while (tag_header->type != MB2_TAG_END) {
// process tag_type
diff --git a/kernel/src/cpu/gdt.c b/kernel/src/cpu/gdt.c
index 743b629..fe7e080 100644
--- a/kernel/src/cpu/gdt.c
+++ b/kernel/src/cpu/gdt.c
@@ -12,7 +12,7 @@ void add_gdt_entry(uint32_t num, uint32_t offset, uint32_t limit, uint8_t access
gdt[num].limit = limit & 0xffff;
gdt[num].limitflags = (limit >> 16) & 0xf;
gdt[num].access = access;
- gdt[num].limitflags = flags << 4;
+ gdt[num].limitflags = (uint8_t)(flags << 4);
}
void add_gdt_tss(uint32_t num, uint64_t offset, uint32_t limit, uint8_t access, uint8_t flags)
diff --git a/kernel/src/libk/serial_stdio.c b/kernel/src/libk/serial_stdio.c
new file mode 100644
index 0000000..a56750b
--- /dev/null
+++ b/kernel/src/libk/serial_stdio.c
@@ -0,0 +1,61 @@
+#include <types.h>
+#include <libk/serial_stdio.h>
+#include <stdarg.h>
+#include <libk/string.h>
+#include <graphics.h>
+#include <serial.h>
+
+void serial_print_char(char c)
+{
+ write_serial(c);
+}
+
+void serial_print_string(const char* s)
+{
+ for (size_t i = 0; i < strlen(s); i++) {
+ serial_print_char(s[i]);
+ }
+}
+
+void serial_print_int(uint64_t num)
+{
+ char a[100];
+ itos(num, a);
+ serial_print_string(a);
+}
+
+void serial_print_hex(uint64_t num)
+{
+ char a[100];
+ itoh(num, a);
+ serial_print_string(a);
+}
+
+void serial_printf(const char *s, ...)
+{
+ size_t count = 0;
+ for(size_t i = 0; i < strlen(s); i++) if(s[i] == '%') count++;
+
+ va_list list;
+ va_start(list, s);
+
+ for(size_t i = 0; i < strlen(s); i++)
+ {
+ if(s[i] == '%')
+ {
+ i++;
+ if(s[i] == 'c') serial_print_char((char)va_arg(list, uint32_t));
+ else if(s[i] == 's') serial_print_string(va_arg(list, char*));
+ else if(s[i] == 'd') serial_print_int((uint64_t)va_arg(list, uint64_t));
+ else if(s[i] == 'x') serial_print_hex((uint64_t)va_arg(list, uint64_t));
+ else
+ {
+ serial_print_string("Wrong format using printf\n");
+ return;
+ }
+ }
+ else serial_print_char(s[i]);
+ }
+
+ va_end(list);
+}
diff --git a/kernel/src/ubsan/ubsan.c b/kernel/src/ubsan/ubsan.c
new file mode 100644
index 0000000..84283f7
--- /dev/null
+++ b/kernel/src/ubsan/ubsan.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * ubsan/ubsan.c
+ * Undefined behavior sanitizer runtime support.
+ */
+
+#include <stdint.h>
+#include <libk/stdio.h>
+#include <libk/serial_stdio.h>
+#include <ubsan.h>
+
+struct ubsan_source_location
+{
+ const char* filename;
+ uint32_t line;
+ uint32_t column;
+};
+
+struct ubsan_type_descriptor
+{
+ uint16_t type_kind;
+ uint16_t type_info;
+ char type_name[];
+};
+
+typedef uintptr_t ubsan_value_handle_t;
+
+static const struct ubsan_source_location unknown_location =
+{
+ "<unknown file>",
+ 0,
+ 0,
+};
+
+__attribute__((noreturn))
+static void ubsan_abort(const struct ubsan_source_location* location,
+ const char* violation)
+{
+ if ( !location || !location->filename )
+ location = &unknown_location;
+
+ serial_printf(
+ "filename = %s; line = %d; column = %d; violation = %s;\n",
+ location->filename, location->line, location->column, violation);
+ while (true) {
+
+ }
+}
+
+#define ABORT_VARIANT(name, params, call) \
+__attribute__((noreturn)) \
+void __ubsan_handle_##name##_abort params \
+{ \
+ __ubsan_handle_##name call; \
+ __builtin_unreachable(); \
+}
+
+#define ABORT_VARIANT_VP(name) \
+ABORT_VARIANT(name, (void* a), (a))
+#define ABORT_VARIANT_VP_VP(name) \
+ABORT_VARIANT(name, (void* a, void* b), (a, b))
+#define ABORT_VARIANT_VP_IP(name) \
+ABORT_VARIANT(name, (void* a, intptr_t b), (a, b))
+#define ABORT_VARIANT_VP_VP_VP(name) \
+ABORT_VARIANT(name, (void* a, void* b, void* c), (a, b, c))
+
+struct ubsan_type_mismatch_v1_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* type;
+ uintptr_t alignment;
+ unsigned char type_check_kind;
+};
+
+void __ubsan_handle_type_mismatch_v1(void* data_raw,
+ void* pointer_raw)
+{
+ struct ubsan_type_mismatch_v1_data* data =
+ (struct ubsan_type_mismatch_v1_data*) data_raw;
+ ubsan_value_handle_t pointer = (ubsan_value_handle_t) pointer_raw;
+ const char* violation = "type mismatch";
+ if ( !pointer )
+ violation = "null pointer access";
+ else if ( data->alignment && (pointer & (data->alignment - 1)) )
+ violation = "unaligned access";
+ ubsan_abort(&data->location, violation);
+}
+
+ABORT_VARIANT_VP_VP(type_mismatch_v1);
+
+struct ubsan_overflow_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* type;
+};
+
+void __ubsan_handle_pointer_overflow(void* data_raw,
+ void* lhs_raw,
+ void* rhs_raw)
+{
+ struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
+ ubsan_value_handle_t lhs = (ubsan_value_handle_t) lhs_raw;
+ ubsan_value_handle_t rhs = (ubsan_value_handle_t) rhs_raw;
+ (void) lhs;
+ (void) rhs;
+ ubsan_abort(&data->location, "pointer overflow");
+}
+
+ABORT_VARIANT_VP_VP_VP(pointer_overflow);
+
+void __ubsan_handle_add_overflow(void* data_raw,
+ void* lhs_raw,
+ void* rhs_raw)
+{
+ struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
+ ubsan_value_handle_t lhs = (ubsan_value_handle_t) lhs_raw;
+ ubsan_value_handle_t rhs = (ubsan_value_handle_t) rhs_raw;
+ (void) lhs;
+ (void) rhs;
+ ubsan_abort(&data->location, "addition overflow");
+}
+
+ABORT_VARIANT_VP_VP_VP(add_overflow);
+
+void __ubsan_handle_sub_overflow(void* data_raw,
+ void* lhs_raw,
+ void* rhs_raw)
+{
+ struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
+ ubsan_value_handle_t lhs = (ubsan_value_handle_t) lhs_raw;
+ ubsan_value_handle_t rhs = (ubsan_value_handle_t) rhs_raw;
+ (void) lhs;
+ (void) rhs;
+ ubsan_abort(&data->location, "subtraction overflow");
+}
+
+ABORT_VARIANT_VP_VP_VP(sub_overflow);
+
+void __ubsan_handle_mul_overflow(void* data_raw,
+ void* lhs_raw,
+ void* rhs_raw)
+{
+ struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
+ ubsan_value_handle_t lhs = (ubsan_value_handle_t) lhs_raw;
+ ubsan_value_handle_t rhs = (ubsan_value_handle_t) rhs_raw;
+ (void) lhs;
+ (void) rhs;
+ ubsan_abort(&data->location, "multiplication overflow");
+}
+
+ABORT_VARIANT_VP_VP_VP(mul_overflow);
+
+void __ubsan_handle_negate_overflow(void* data_raw,
+ void* old_value_raw)
+{
+ struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
+ ubsan_value_handle_t old_value = (ubsan_value_handle_t) old_value_raw;
+ (void) old_value;
+ ubsan_abort(&data->location, "negation overflow");
+}
+
+ABORT_VARIANT_VP_VP(negate_overflow);
+
+void __ubsan_handle_divrem_overflow(void* data_raw,
+ void* lhs_raw,
+ void* rhs_raw)
+{
+ struct ubsan_overflow_data* data = (struct ubsan_overflow_data*) data_raw;
+ ubsan_value_handle_t lhs = (ubsan_value_handle_t) lhs_raw;
+ ubsan_value_handle_t rhs = (ubsan_value_handle_t) rhs_raw;
+ (void) lhs;
+ (void) rhs;
+ ubsan_abort(&data->location, "division remainder overflow");
+}
+
+ABORT_VARIANT_VP_VP_VP(divrem_overflow);
+
+struct ubsan_shift_out_of_bounds_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* lhs_type;
+ struct ubsan_type_descriptor* rhs_type;
+};
+
+void __ubsan_handle_shift_out_of_bounds(void* data_raw,
+ void* lhs_raw,
+ void* rhs_raw)
+{
+ struct ubsan_shift_out_of_bounds_data* data =
+ (struct ubsan_shift_out_of_bounds_data*) data_raw;
+ ubsan_value_handle_t lhs = (ubsan_value_handle_t) lhs_raw;
+ ubsan_value_handle_t rhs = (ubsan_value_handle_t) rhs_raw;
+ (void) lhs;
+ (void) rhs;
+ ubsan_abort(&data->location, "shift out of bounds");
+}
+
+ABORT_VARIANT_VP_VP_VP(shift_out_of_bounds);
+
+struct ubsan_out_of_bounds_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* array_type;
+ struct ubsan_type_descriptor* index_type;
+};
+
+void __ubsan_handle_out_of_bounds(void* data_raw,
+ void* index_raw)
+{
+ struct ubsan_out_of_bounds_data* data =
+ (struct ubsan_out_of_bounds_data*) data_raw;
+ ubsan_value_handle_t index = (ubsan_value_handle_t) index_raw;
+ (void) index;
+ ubsan_abort(&data->location, "out of bounds");
+}
+
+ABORT_VARIANT_VP_VP(out_of_bounds);
+
+struct ubsan_unreachable_data
+{
+ struct ubsan_source_location location;
+};
+
+__attribute__((noreturn))
+void __ubsan_handle_builtin_unreachable(void* data_raw)
+{
+ struct ubsan_unreachable_data* data =
+ (struct ubsan_unreachable_data*) data_raw;
+ ubsan_abort(&data->location, "reached unreachable");
+}
+
+__attribute__((noreturn))
+void __ubsan_handle_missing_return(void* data_raw)
+{
+ struct ubsan_unreachable_data* data =
+ (struct ubsan_unreachable_data*) data_raw;
+ ubsan_abort(&data->location, "missing return");
+}
+
+struct ubsan_vla_bound_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* type;
+};
+
+void __ubsan_handle_vla_bound_not_positive(void* data_raw,
+ void* bound_raw)
+{
+ struct ubsan_vla_bound_data* data = (struct ubsan_vla_bound_data*) data_raw;
+ ubsan_value_handle_t bound = (ubsan_value_handle_t) bound_raw;
+ (void) bound;
+ ubsan_abort(&data->location, "negative variable array length");
+}
+
+ABORT_VARIANT_VP_VP(vla_bound_not_positive);
+
+struct ubsan_float_cast_overflow_data
+{
+ // TODO: Remove this GCC 5.x compatibility after switching to GCC 6.x. The
+ // GCC developers accidentally forgot the source location. Their
+ // libubsan probes to see if it looks like a path, but we don't need
+ // to maintain compatibility with multiple gcc releases. See below.
+#if !(defined(__GNUC__) && __GNUC__< 6)
+ struct ubsan_source_location location;
+#endif
+ struct ubsan_type_descriptor* from_type;
+ struct ubsan_type_descriptor* to_type;
+};
+
+void __ubsan_handle_float_cast_overflow(void* data_raw,
+ void* from_raw)
+{
+ struct ubsan_float_cast_overflow_data* data =
+ (struct ubsan_float_cast_overflow_data*) data_raw;
+ ubsan_value_handle_t from = (ubsan_value_handle_t) from_raw;
+ (void) from;
+#if !(defined(__GNUC__) && __GNUC__< 6)
+ ubsan_abort(&data->location, "float cast overflow");
+#else
+ ubsan_abort(((void) data, &unknown_location), "float cast overflow");
+#endif
+}
+
+ABORT_VARIANT_VP_VP(float_cast_overflow);
+
+struct ubsan_invalid_value_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* type;
+};
+
+void __ubsan_handle_load_invalid_value(void* data_raw,
+ void* value_raw)
+{
+ struct ubsan_invalid_value_data* data =
+ (struct ubsan_invalid_value_data*) data_raw;
+ ubsan_value_handle_t value = (ubsan_value_handle_t) value_raw;
+ (void) value;
+ ubsan_abort(&data->location, "invalid value load");
+}
+
+ABORT_VARIANT_VP_VP(load_invalid_value);
+
+struct ubsan_function_type_mismatch_v1_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* type;
+};
+
+void __ubsan_handle_function_type_mismatch_v1(void* data_raw,
+ void* value_raw)
+{
+ struct ubsan_function_type_mismatch_v1_data* data =
+ (struct ubsan_function_type_mismatch_v1_data*) data_raw;
+ ubsan_value_handle_t value = (ubsan_value_handle_t) value_raw;
+ (void) value;
+ ubsan_abort(&data->location, "function type mismatch");
+}
+
+ABORT_VARIANT_VP_VP(function_type_mismatch_v1);
+
+struct ubsan_nonnull_return_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_source_location attr_location;
+};
+
+void __ubsan_handle_nonnull_return(void* data_raw)
+{
+ struct ubsan_nonnull_return_data* data =
+ (struct ubsan_nonnull_return_data*) data_raw;
+ ubsan_abort(&data->location, "null return");
+}
+
+ABORT_VARIANT_VP(nonnull_return);
+
+struct ubsan_nonnull_arg_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_source_location attr_location;
+};
+
+// TODO: GCC's libubsan does not have the second parameter, but its builtin
+// somehow has it and conflict if we don't match it.
+void __ubsan_handle_nonnull_arg(void* data_raw,
+ intptr_t index_raw)
+{
+ struct ubsan_nonnull_arg_data* data =
+ (struct ubsan_nonnull_arg_data*) data_raw;
+ ubsan_value_handle_t index = (ubsan_value_handle_t) index_raw;
+ (void) index;
+ ubsan_abort(&data->location, "null argument");
+}
+
+ABORT_VARIANT_VP_IP(nonnull_arg);
+
+struct ubsan_cfi_bad_icall_data
+{
+ struct ubsan_source_location location;
+ struct ubsan_type_descriptor* type;
+};
+
+void __ubsan_handle_cfi_bad_icall(void* data_raw,
+ void* value_raw)
+{
+ struct ubsan_cfi_bad_icall_data* data =
+ (struct ubsan_cfi_bad_icall_data*) data_raw;
+ ubsan_value_handle_t value = (ubsan_value_handle_t) value_raw;
+ (void) value;
+ ubsan_abort(&data->location,
+ "control flow integrity check failure during indirect call");
+}
+
+ABORT_VARIANT_VP_VP(cfi_bad_icall);