Kernel: Add ubsan
My brain has been melting since I'm getting very random bugs. I hope I can debug them better with ubsan :)
This commit is contained in:
		
							parent
							
								
									e480f9c195
								
							
						
					
					
						commit
						06db890d49
					
				|  | @ -18,6 +18,8 @@ export INCLUDEDIR=$PREFIX/include | ||||||
| export CFLAGS='-O2 -g' | export CFLAGS='-O2 -g' | ||||||
| export CPPFLAGS='--std=c++20' | export CPPFLAGS='--std=c++20' | ||||||
|   |   | ||||||
|  | export UBSAN=1 | ||||||
|  | 
 | ||||||
| # Configure the cross-compiler to use the desired system root. | # Configure the cross-compiler to use the desired system root. | ||||||
| export SYSROOT="$(pwd)/sysroot" | export SYSROOT="$(pwd)/sysroot" | ||||||
| export CC="$CC --sysroot=$SYSROOT" | export CC="$CC --sysroot=$SYSROOT" | ||||||
|  |  | ||||||
|  | @ -27,6 +27,10 @@ CPPFLAGS:=$(CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS) | ||||||
| LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS) | LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS) | ||||||
| LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS) | LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS) | ||||||
| 
 | 
 | ||||||
|  | ifeq ($(UBSAN), 1) | ||||||
|  | CFLAGS:=$(CFLAGS) -fsanitize=undefined | ||||||
|  | endif | ||||||
|  | 
 | ||||||
| BUILDDIR=$(abspath build) | BUILDDIR=$(abspath build) | ||||||
|   |   | ||||||
| KERNEL_OBJS=					\
 | KERNEL_OBJS=					\
 | ||||||
|  | @ -58,6 +62,7 @@ kernel/Thread.o					\ | ||||||
| kernel/TTY.o					\ | kernel/TTY.o					\ | ||||||
| kernel/VesaTerminalDriver.o		\ | kernel/VesaTerminalDriver.o		\ | ||||||
| icxxabi.o						\ | icxxabi.o						\ | ||||||
|  | ubsan.o							\ | ||||||
|   |   | ||||||
| OBJS=					\
 | OBJS=					\
 | ||||||
| $(ARCHDIR)/crti.o		\ | $(ARCHDIR)/crti.o		\ | ||||||
|  |  | ||||||
|  | @ -47,9 +47,9 @@ MMU::MMU() | ||||||
| 		m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present; | 		m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// create and identity map first 4 MiB
 | 	// create and identity map first 6 MiB
 | ||||||
| 	uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK); | 	uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK); | ||||||
| 	for (uint64_t i = 0; i < 2; i++) | 	for (uint64_t i = 0; i < 3; i++) | ||||||
| 	{ | 	{ | ||||||
| 		uint64_t* page_table = allocate_page_aligned_page(); | 		uint64_t* page_table = allocate_page_aligned_page(); | ||||||
| 		for (uint64_t j = 0; j < 512; j++) | 		for (uint64_t j = 0; j < 512; j++) | ||||||
|  |  | ||||||
|  | @ -118,9 +118,10 @@ enable_sse: | ||||||
| 	ret | 	ret | ||||||
| 
 | 
 | ||||||
| initialize_paging: | initialize_paging: | ||||||
| 	# identity map first 4 MiB | 	# identity map first 6 MiB | ||||||
| 	movl $(0x00000000           + 0x83), boot_page_directory1 + 0 | 	movl $(0x00000000           + 0x83), boot_page_directory1 + 0 | ||||||
| 	movl $(0x00200000           + 0x83), boot_page_directory1 + 8 | 	movl $(0x00200000           + 0x83), boot_page_directory1 + 8 | ||||||
|  | 	movl $(0x00400000           + 0x83), boot_page_directory1 + 16 | ||||||
| 	movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table | 	movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table | ||||||
| 
 | 
 | ||||||
| 	# enable PAE | 	# enable PAE | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ static uint64_t* allocate_page_aligned_page() | ||||||
| 
 | 
 | ||||||
| MMU::MMU() | MMU::MMU() | ||||||
| { | { | ||||||
| 	// Identity map from 4 KiB -> 4 MiB
 | 	// Identity map from 4 KiB -> 6 MiB
 | ||||||
| 	m_highest_paging_struct = allocate_page_aligned_page(); | 	m_highest_paging_struct = allocate_page_aligned_page(); | ||||||
| 	 | 	 | ||||||
| 	uint64_t* pdpt = allocate_page_aligned_page(); | 	uint64_t* pdpt = allocate_page_aligned_page(); | ||||||
|  | @ -44,7 +44,7 @@ MMU::MMU() | ||||||
| 	uint64_t* pd = allocate_page_aligned_page(); | 	uint64_t* pd = allocate_page_aligned_page(); | ||||||
| 	pdpt[0] = (uint64_t)pd | Flags::ReadWrite | Flags::Present; | 	pdpt[0] = (uint64_t)pd | Flags::ReadWrite | Flags::Present; | ||||||
| 
 | 
 | ||||||
| 	for (uint32_t i = 0; i < 2; i++) | 	for (uint32_t i = 0; i < 3; i++) | ||||||
| 	{ | 	{ | ||||||
| 		uint64_t* pt = allocate_page_aligned_page(); | 		uint64_t* pt = allocate_page_aligned_page(); | ||||||
| 		for (uint64_t j = 0; j < 512; j++) | 		for (uint64_t j = 0; j < 512; j++) | ||||||
|  |  | ||||||
|  | @ -41,9 +41,9 @@ | ||||||
| 	# we will identity map first 4 MiB | 	# we will identity map first 4 MiB | ||||||
| 
 | 
 | ||||||
| 	# 0 MiB -> 1 MiB: bootloader stuff | 	# 0 MiB -> 1 MiB: bootloader stuff | ||||||
| 	# 1 MiB -> 2 MiB: kernel | 	# 1 MiB -> 4 MiB: kernel | ||||||
| 	# 2 MiB -> 3 MiB: kmalloc | 	# 4 MiB -> 5 MiB: kmalloc | ||||||
| 	# 3 MiB -> 4 MiB: kmalloc_fixed | 	# 5 MiB -> 6 MiB: kmalloc_fixed | ||||||
| 	.align 4096
 | 	.align 4096
 | ||||||
| 	boot_pml4: | 	boot_pml4: | ||||||
| 		.skip 512 * 8 | 		.skip 512 * 8 | ||||||
|  | @ -127,9 +127,10 @@ enable_sse: | ||||||
| 	ret | 	ret | ||||||
| 
 | 
 | ||||||
| initialize_paging: | initialize_paging: | ||||||
| 	# identity map first 4 MiB | 	# identity map first 6 MiB | ||||||
| 	movl $(0x00000000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 0 | 	movl $(0x00000000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 0 | ||||||
| 	movl $(0x00200000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 8 | 	movl $(0x00200000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 8 | ||||||
|  | 	movl $(0x00400000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 16 | ||||||
| 
 | 
 | ||||||
| 	# set pdpte1 and pml4e1 | 	# set pdpte1 and pml4e1 | ||||||
| 	movl $(boot_pd1   + PG_READ_WRITE + PG_PRESENT), boot_pdpt1	 | 	movl $(boot_pd1   + PG_READ_WRITE + PG_PRESENT), boot_pdpt1	 | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ private: | ||||||
| static_assert(sizeof(kmalloc_node) == s_kmalloc_min_align); | static_assert(sizeof(kmalloc_node) == s_kmalloc_min_align); | ||||||
| struct kmalloc_info | struct kmalloc_info | ||||||
| { | { | ||||||
| 	static constexpr uintptr_t	base = 0x00200000; | 	static constexpr uintptr_t	base = 0x00400000; | ||||||
| 	static constexpr size_t		size = 1 * MB; | 	static constexpr size_t		size = 1 * MB; | ||||||
| 	static constexpr uintptr_t	end = base + size; | 	static constexpr uintptr_t	end = base + size; | ||||||
| 
 | 
 | ||||||
|  | @ -313,11 +313,10 @@ void* kmalloc(size_t size, size_t align) | ||||||
| 	if (size == 0 || size >= info.size) | 	if (size == 0 || size >= info.size) | ||||||
| 		return nullptr; | 		return nullptr; | ||||||
| 
 | 
 | ||||||
| 	ASSERT(align); |  | ||||||
| 	ASSERT(is_power_of_two(align)); | 	ASSERT(is_power_of_two(align)); | ||||||
| 
 | 
 | ||||||
| 	// if the size fits into fixed node, we will try to use that since it is faster
 | 	// if the size fits into fixed node, we will try to use that since it is faster
 | ||||||
| 	if (align == s_kmalloc_min_align && size < sizeof(kmalloc_fixed_info::node::data)) | 	if (align == s_kmalloc_min_align && size <= sizeof(kmalloc_fixed_info::node::data)) | ||||||
| 		if (void* result = kmalloc_fixed()) | 		if (void* result = kmalloc_fixed()) | ||||||
| 			return result; | 			return result; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,108 @@ | ||||||
|  | #include <kernel/Debug.h> | ||||||
|  | #include <kernel/Panic.h> | ||||||
|  | 
 | ||||||
|  | extern "C" | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	struct source_location | ||||||
|  | 	{ | ||||||
|  | 		const char *file; | ||||||
|  | 		uint32_t line; | ||||||
|  | 		uint32_t column; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	struct type_descriptor | ||||||
|  | 	{ | ||||||
|  | 		uint16_t kind; | ||||||
|  | 		uint16_t info; | ||||||
|  | 		char name[1]; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	struct type_mismatch_data | ||||||
|  | 	{ | ||||||
|  | 		source_location location; | ||||||
|  | 		const type_descriptor& type; | ||||||
|  | 		uint8_t alignment; | ||||||
|  | 		uint8_t type_check_kind; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	struct out_of_bounds_data | ||||||
|  | 	{ | ||||||
|  | 		source_location location; | ||||||
|  | 		const type_descriptor& left_type; | ||||||
|  | 		const type_descriptor& right_type; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct shift_out_of_bounds_data | ||||||
|  | 	{ | ||||||
|  | 		source_location location; | ||||||
|  | 		const type_descriptor& left_type; | ||||||
|  | 		const type_descriptor& right_type; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct pointer_overflow_data | ||||||
|  | 	{ | ||||||
|  | 		source_location location; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct invalid_value_data | ||||||
|  | 	{ | ||||||
|  | 		source_location location; | ||||||
|  | 		const type_descriptor& type; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct overflow_data | ||||||
|  | 	{ | ||||||
|  | 		source_location location; | ||||||
|  | 		const type_descriptor& type; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	using value_handle = uintptr_t; | ||||||
|  | 
 | ||||||
|  | 	static 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", "_Nonnull binding to", | ||||||
|  | 		"dynamic operation on" | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	#define HANDLER(handler, fatal, ...)															\ | ||||||
|  | 		void handler(__VA_ARGS__)																	\ | ||||||
|  | 		{																							\ | ||||||
|  | 			if constexpr(fatal)																		\ | ||||||
|  | 				Kernel::panic("{}:{} {}", data->location.file, data->location.line, __FUNCTION__);	\ | ||||||
|  | 			else																					\ | ||||||
|  | 				derrorln("{}:{} {}", data->location.file, data->location.line, __FUNCTION__);		\ | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	static void print_location_impl(const source_location& location, const char* function) | ||||||
|  | 	{ | ||||||
|  | 		derrorln("{}:{} {}", location.file, location.line, function); | ||||||
|  | 	} | ||||||
|  | 	#define print_location(location) print_location_impl(location, __FUNCTION__) | ||||||
|  | 
 | ||||||
|  | 	HANDLER(__ubsan_handle_pointer_overflow, false, pointer_overflow_data* data, value_handle, value_handle) | ||||||
|  | 	HANDLER(__ubsan_handle_load_invalid_value, false, invalid_value_data* data, value_handle) | ||||||
|  | 	HANDLER(__ubsan_handle_out_of_bounds, false, out_of_bounds_data* data, value_handle) | ||||||
|  | 	HANDLER(__ubsan_handle_shift_out_of_bounds, false, shift_out_of_bounds_data* data, value_handle, value_handle) | ||||||
|  | 
 | ||||||
|  | 	HANDLER(__ubsan_handle_add_overflow, false, overflow_data* data, value_handle, value_handle) | ||||||
|  | 	HANDLER(__ubsan_handle_sub_overflow, false, overflow_data* data, value_handle, value_handle) | ||||||
|  | 	HANDLER(__ubsan_handle_mul_overflow, false, overflow_data* data, value_handle, value_handle) | ||||||
|  | 	HANDLER(__ubsan_handle_divrem_overflow, false, overflow_data* data, value_handle, value_handle) | ||||||
|  | 	HANDLER(__ubsan_handle_negate_overflow, false, overflow_data* data, value_handle) | ||||||
|  | 
 | ||||||
|  | 	void __ubsan_handle_type_mismatch_v1(type_mismatch_data* data, value_handle pointer) | ||||||
|  | 	{ | ||||||
|  | 		print_location(data->location); | ||||||
|  | 		const char* kind = type_check_kinds[data->type_check_kind]; | ||||||
|  | 		uintptr_t alignment = (uintptr_t)1 << data->alignment; | ||||||
|  | 		if (!pointer) | ||||||
|  | 			derrorln("{} null pointer of type {}", kind, data->type.name); | ||||||
|  | 		else if (pointer & (alignment - 1)) | ||||||
|  | 			derrorln("{} misaligned address {} for type {}, which requires {} byte alignment", kind, (void*)pointer, data->type.name, alignment); | ||||||
|  | 		else | ||||||
|  | 			derrorln("{} address {} with insufficient space for an object of type {}", kind, (void*)pointer, data->type.name); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue