Skip to content

Commit

Permalink
Add support for ubsan (Undefined Behavior Sanitization) (#271)
Browse files Browse the repository at this point in the history
  • Loading branch information
willdurand authored Nov 5, 2021
1 parent 3d492fc commit 07173a9
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 8 deletions.
6 changes: 6 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,9 @@ jobs:
command: |
export TERM=xterm
make clean run-test
- run:
name: integration tests with ubsan
command: |
export TERM=xterm
make clean run-test UBSAN=1
no_output_timeout: 2m
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ WERRORS += -Werror=incompatible-pointer-types
WERRORS += -Werror=shift-count-overflow
WERRORS += -Werror=switch

CFLAGS := -DKERNEL_NAME=\"$(OS_NAME)\"
CFLAGS += -DKERNEL_NAME=\"$(OS_NAME)\"
CFLAGS += -DGIT_HASH=\"$(GIT_HASH)\"
CFLAGS += -DLOGS_WITH_COLORS
CFLAGS += -std=c11 -ffreestanding -nostdinc -nostdlib -fno-builtin
Expand Down Expand Up @@ -220,7 +220,16 @@ console-font: $(KERNEL_CONSOLE_FONT)
$(INITRD): $(INITRD_DIR) userland
$(PROGRESS) "TAR" $@
cp -R userland/bin $(INITRD_DIR)
echo "$(OS_NAME) ($(ARCH)) build info\n\nhash: $(GIT_HASH)\ndate: $(shell date)" > $(INITRD_DIR)/info
echo "$(OS_NAME) ($(ARCH)) build info" > $(INITRD_DIR)/info
echo "" >> $(INITRD_DIR)/info
echo "hash: $(GIT_HASH)" >> $(INITRD_DIR)/info
echo "date: $(shell date)" >> $(INITRD_DIR)/info
echo "mode: $(BUILD_MODE)" >> $(INITRD_DIR)/info
echo "" >> $(INITRD_DIR)/info
echo "compiler: $(shell $(CC) --version | head -n 1)" >> $(INITRD_DIR)/info
echo "" >> $(INITRD_DIR)/info
echo "CFLAGS: $(CFLAGS)" >> $(INITRD_DIR)/info
echo "INCLUDES: $(INCLUDES)" >> $(INITRD_DIR)/info
cd $(INITRD_DIR) && tar -cf ../$@ *

# We mark this target as .PHONY to write the file every time.
Expand Down Expand Up @@ -261,6 +270,7 @@ run-test: ## run the OS in test mode
run-test: QEMU_OPTIONS += -curses -serial file:./log/test.log
run-test: GRUB_KERNEL_CMDLINE = /bin/boot-and-exit
run-test: run
cat initrd/info
.PHONY: run-test

clean: ## remove build artifacts
Expand Down
7 changes: 4 additions & 3 deletions external/liballoc/liballoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ static struct liballoc_major* allocate_new_page(unsigned int size)
return maj;
}

void* PREFIX(malloc)(size_t req_size)
__attribute__((no_sanitize("undefined"))) void* PREFIX(malloc)(size_t req_size)
{
int startedBet = 0;
unsigned long long bestSize = 0;
Expand Down Expand Up @@ -558,7 +558,7 @@ void* PREFIX(malloc)(size_t req_size)
return NULL;
}

void PREFIX(free)(void* ptr)
__attribute__((no_sanitize("undefined"))) void PREFIX(free)(void* ptr)
{
struct liballoc_minor* min;
struct liballoc_major* maj;
Expand Down Expand Up @@ -700,7 +700,8 @@ void* PREFIX(calloc)(size_t nobj, size_t size)
return p;
}

void* PREFIX(realloc)(void* p, size_t size)
__attribute__((no_sanitize("undefined"))) void* PREFIX(realloc)(void* p,
size_t size)
{
void* ptr;
struct liballoc_minor* min;
Expand Down
110 changes: 110 additions & 0 deletions include/ubsan.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* @file
* @see https://wiki.osdev.org/Undefined_Behavior_Sanitization
*/
#ifndef UBSAN_H
#define UBSAN_H

#include <stdint.h>

typedef struct ubsan_type
{
uint16_t kind;
uint16_t info;
char name[];
} ubsan_type_t;

typedef struct ubsan_source_location
{
const char* file;
uint32_t line;
uint32_t column;
} ubsan_source_location_t;

typedef struct ubsan_mismatch_v1_data
{
ubsan_source_location_t location;
ubsan_type_t* type;
uint8_t alignment;
uint8_t kind;
} ubsan_mismatch_v1_data_t;

typedef struct ubsan_overflow_data
{
ubsan_source_location_t location;
ubsan_type_t* type;
} ubsan_overflow_data_t;

typedef struct ubsan_shift_out_of_bounds_data
{
ubsan_source_location_t location;
ubsan_type_t* lhs_type;
ubsan_type_t* rhs_type;
} ubsan_shift_out_of_bounds_data_t;

typedef struct ubsan_out_of_bounds_data
{
ubsan_source_location_t location;
ubsan_type_t* array_type;
ubsan_type_t* index_type;
} ubsan_out_of_bounds_data_t;

typedef struct ubsan_invalid_value_data
{
ubsan_source_location_t location;
ubsan_type_t* type;
} ubsan_invalid_value_data_t;

typedef struct ubsan_float_cast_overflow_data
{
ubsan_source_location_t location;
ubsan_type_t* from_type;
ubsan_type_t* to_type;
} ubsan_float_cast_overflow_data_t;

typedef struct ubsan_pointer_overflow_data
{
ubsan_source_location_t location;
} ubsan_pointer_overflow_data_t;

// TODO: check why it is _v1
void __ubsan_handle_type_mismatch_v1(ubsan_mismatch_v1_data_t* data,
uintptr_t ptr);

void __ubsan_handle_add_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs);

void __ubsan_handle_sub_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs);

void __ubsan_handle_mul_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs);

void __ubsan_handle_negate_overflow(ubsan_overflow_data_t* data,
void* old_value);

void __ubsan_handle_divrem_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs);

void __ubsan_handle_shift_out_of_bounds(ubsan_shift_out_of_bounds_data_t* data,
void* lhs,
void* rhs);

void __ubsan_handle_out_of_bounds(ubsan_out_of_bounds_data_t* data,
void* index);

void __ubsan_handle_load_invalid_value(ubsan_invalid_value_data_t* data,
void* value);

void __ubsan_handle_float_cast_overflow(ubsan_float_cast_overflow_data_t* data,
void* from);

void __ubsan_handle_pointer_overflow(ubsan_pointer_overflow_data_t* data,
void* lhs,
void* rhs);

#endif
2 changes: 1 addition & 1 deletion src/arch/x86_64/core/tss.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ typedef struct tss
uint64_t reserved2;
uint16_t reserved3;
uint16_t iopb_offset;
} tss_t;
} __attribute__((packed)) tss_t;

void tss_init();

Expand Down
3 changes: 2 additions & 1 deletion src/arch/x86_64/net/ntp.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ int ntp_request(net_interface_t* interface,
}

ntp_header.transmit_ts.seconds = ntohl(ntp_header.transmit_ts.seconds);
ntp_header.transmit_ts.fraction = ntohl(ntp_header.transmit_ts.fraction);
ntp_header.transmit_ts.fraction =
ntohl((uint32_t)ntp_header.transmit_ts.fraction);

*server_time = ntp_header.transmit_ts.seconds - NTP_TIMESTAMP_DELTA;

Expand Down
3 changes: 2 additions & 1 deletion src/libc/arpa/inet_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ in_addr_t inet_addr(const char* s)

in_addr_t inet_addr2(uint8_t ip[4])
{
return (in_addr_t)(ip[0] | (ip[1] << 8) | (ip[2] << 16) | (ip[3] << 24));
return (in_addr_t)(ip[0] | (ip[1] << 8) | (ip[2] << 16) |
((uint32_t)ip[3] << 24));
}
145 changes: 145 additions & 0 deletions src/libc/ubsan.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#include "ubsan.h"
#include <stdio.h>

#ifdef __is_libk

#include <kernel/panic.h>

#endif

#define UNUSED(x) (void)(x)

void ubsan_panic_at(ubsan_source_location_t* location, const char* error);

void __ubsan_handle_type_mismatch_v1(ubsan_mismatch_v1_data_t* data,
uintptr_t ptr)
{
const char* error = "type mismatch";

if (!ptr) {
error = "null pointer access";
} else if (data->alignment && (ptr & (data->alignment - 1))) {
error = "unaligned access";
}

ubsan_panic_at(&data->location, error);
}

void __ubsan_handle_add_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs)
{
UNUSED(*lhs);
UNUSED(*rhs);

ubsan_panic_at(&data->location, "add overflow");
}

void __ubsan_handle_sub_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs)
{
UNUSED(*lhs);
UNUSED(*rhs);

ubsan_panic_at(&data->location, "sub overflow");
}

void __ubsan_handle_mul_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs)
{
UNUSED(*lhs);
UNUSED(*rhs);

ubsan_panic_at(&data->location, "mul overflow");
}

void __ubsan_handle_negate_overflow(ubsan_overflow_data_t* data,
void* old_value)
{
UNUSED(*old_value);

ubsan_panic_at(&data->location, "negation overflow");
}

void __ubsan_handle_divrem_overflow(ubsan_overflow_data_t* data,
void* lhs,
void* rhs)
{
UNUSED(*lhs);
UNUSED(*rhs);

ubsan_panic_at(&data->location, "negation overflow");
}

void __ubsan_handle_shift_out_of_bounds(ubsan_shift_out_of_bounds_data_t* data,
void* lhs,
void* rhs)
{
UNUSED(*lhs);
UNUSED(*rhs);

ubsan_panic_at(&data->location, "shift out of bounds");
}

void __ubsan_handle_out_of_bounds(ubsan_out_of_bounds_data_t* data, void* index)
{
UNUSED(*index);

ubsan_panic_at(&data->location, "shift out of bounds");
}

void __ubsan_handle_load_invalid_value(ubsan_invalid_value_data_t* data,
void* value)
{
UNUSED(*value);

ubsan_panic_at(&data->location, "invalid value load");
}

void __ubsan_handle_float_cast_overflow(ubsan_float_cast_overflow_data_t* data,
void* from)
{
UNUSED(*from);

ubsan_panic_at(&data->location, "float cast overflow");
}

void __ubsan_handle_pointer_overflow(ubsan_pointer_overflow_data_t* data,
void* lhs,
void* rhs)
{
UNUSED(*lhs);
UNUSED(*rhs);

ubsan_panic_at(&data->location, "pointer overflow");
}

void ubsan_panic_at(ubsan_source_location_t* location, const char* error)
{
#ifdef __is_libk
if (location) {
PANIC("ubsan: file=%s line=%d column=%d error=%s",
location->file,
location->line,
location->column,
error);
} else {
PANIC("ubsan: file=(unknown) line=(unknown) column=(unknown) error=%s",
error);
}
#else
if (location) {
printf("ubsan: file=%s line=%d column=%d error=%s\n",
location->file,
location->line,
location->column,
error);
} else {
printf("ubsan: file=(unknown) line=(unknown) column=(unknown) error=%s\n",
error);
}
// TODO: use `abort()`
#endif
}

0 comments on commit 07173a9

Please sign in to comment.