Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,21 @@ jobs:
with:
submodules: true

- if: ${{ matrix.toolchain == 'gcc' }}
id: toolchain-version
name: Get the toolchain version
run: |
python3 -c 'import scripts.build_utils.toolchain_builder as tb
print(f"key=gcc-{tb.GCC_VERSION}-binutils-{tb.BINUTILS_VERSION}")' \
>> "$GITHUB_OUTPUT"

- if: ${{ matrix.toolchain == 'gcc' }}
id: toolchain-cache
name: Restore the toolchain cache
uses: actions/cache/restore@v4.2.2
env:
gcc-version: 15.1.0
with:
path: "${{ github.workspace }}/toolchain/tools-${{ matrix.toolchain }}-${{ matrix.arch }}"
key: "${{ runner.os }}-${{ runner.arch }}-${{ matrix.arch }}-gcc-${{ env.gcc-version }}"
key: "${{ runner.os }}-${{ runner.arch }}-${{ matrix.arch }}-${{ steps.toolchain-version.outputs.key }}"

- name: Build the platform toolchain
run: "${{ github.workspace }}/build.py --arch ${{ matrix.arch }} --toolchain ${{ matrix.toolchain }} --no-tune-native --toolchain-only"
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ kernel-source/
bin/
hyper-*
toolchain/tools-*
toolchain/*_sources
toolchain/*.tar.gz*
__pycache__
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.18)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand Down
6 changes: 6 additions & 0 deletions kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ include(build_stamp.cmake)
include(target_helpers.cmake)
include(module.cmake)
include(ld_template.cmake)
include(ubsan.cmake)

# The base kernel executable that contains an empty stub symbol table
set(
Expand Down Expand Up @@ -122,6 +123,11 @@ endif ()

ultra_compile_options(-O${CONFIG_OPTIMIZATION_LEVEL})

if (CONFIG_UBSAN)
setup_ubsan()
ultra_sources_no_ubsan(ubsan.c)
endif ()

ultra_link_options(
-nostdlib
-Wl,--no-pie
Expand Down
32 changes: 32 additions & 0 deletions kernel/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,38 @@ config VERBOSE_INIT_LEVELS
config DEBUG_MM
bool "Enable debug assertions for the memory management subsystem"

menuconfig UBSAN
bool "Undefined behavior sanitizer"
depends on ARCH_HAS_UBSAN

if UBSAN

config UBSAN_BOUNDS
bool "Check array indices against their statically known bounds"
default y

config UBSAN_SHIFT
bool "Check for shifts that are out of range"
default y

config UBSAN_SIGNED_OVERFLOW
bool "Check for signed integer overflow"
default y

config UBSAN_DIV_ZERO
bool "Check for integer division by zero"
depends on TOOLCHAIN_GCC

config UBSAN_UNREACHABLE
bool "Check for control flow reaching __builtin_unreachable()"
default y

config UBSAN_BOOL
bool "Check for loads of bool values that are neither 0 nor 1"
default y

endif

endmenu

rsource "arch/Kconfig"
Expand Down
3 changes: 3 additions & 0 deletions kernel/arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ config ARCH_PHYS_ADDR_WIDTH
default 8 if (ARCH_64BIT || ARCH_FORCE_64BIT_PHYS_ADDR_WIDTH)
default 4 if ARCH_32BIT

config ARCH_HAS_UBSAN
bool

if ARCH_X86_64
rsource "x86_64/Kconfig"
endif
Expand Down
1 change: 1 addition & 0 deletions kernel/arch/x86_64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ config ARCH_X86_64_BASE
bool
select ARCH_LITTLE_ENDIAN
select ARCH_64BIT
select ARCH_HAS_UBSAN
select SMBIOS
select ACPI
select ACPI_PM
Expand Down
2 changes: 1 addition & 1 deletion kernel/bug.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
static bool s_panic_on_warn;
parameter_with_flags(s_panic_on_warn, PARAM_RUNTIME_WRITABLE);

static void finish_warn_report(struct registers *regs)
void finish_warn_report(struct registers *regs)
{
if (s_panic_on_warn) {
/*
Expand Down
2 changes: 1 addition & 1 deletion kernel/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ error_t register_console(struct console *con)
con->next = g_consoles;
g_consoles = con;

log_flush_console(con);
log_flush_consoles();
return EOK;
}

Expand Down
2 changes: 1 addition & 1 deletion kernel/include/common/bit.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#define BITS_PER_BYTE CHAR_BIT
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)

#define BIT_OF_TYPE(type, x) (((type)1) << (x))
#define BIT_OF_TYPE(type, x) ((type)(((type)1) << (x)))
#define BIT_U8(x) BIT_OF_TYPE(u8, (x))
#define BIT_U16(x) BIT_OF_TYPE(u16, (x))
#define BIT_U32(x) BIT_OF_TYPE(u32, (x))
Expand Down
7 changes: 2 additions & 5 deletions kernel/include/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,8 @@ enum log_level {

void vprint(const char *msg, va_list vlist);

// Defined in console.h
struct console;

// Writes every record the console has not seen yet to it
void log_flush_console(struct console *con);
// Writes out every record to every console that hasn't yet been output by it
void log_flush_consoles(void);

PRINTF_DECL(1, 2)
void print(const char *msg, ...);
Expand Down
24 changes: 22 additions & 2 deletions kernel/include/log_ring.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <common/error.h>
#include <common/attributes.h>
#include <common/bit.h>
#include <common/string_container.h>

/*
Expand Down Expand Up @@ -137,6 +138,15 @@ BUILD_BUG_ON(
offset_of_after(struct log_info_record, level)
);

enum log_ring_read_flags : u32 {
/*
* Skip a record that was reserved and never published, as long as
* newer records exist. Only for readers that know such a record will
* never be finished, e.g. during a panic.
*/
LOG_RING_READ_SKIP_UNPUBLISHED = BIT_U32(0),
};

/*
* Read a record from the log ring.
*
Expand All @@ -148,11 +158,21 @@ BUILD_BUG_ON(
* sequence number (if the requested record no longer exists
* due to being overwritten by other log messages) is written to 'out_rec'.
*/
error_t log_ring_read(
error_t log_ring_read_with_flags(
struct log_ring *ring, u64 seq_num, char *out_buf, size_t buf_size,
struct log_record *out_rec
enum log_ring_read_flags flags, struct log_record *out_rec
);

static inline error_t log_ring_read(
struct log_ring *ring, u64 seq_num, char *out_buf, size_t buf_size,
struct log_record *out_rec
)
{
return log_ring_read_with_flags(
ring, seq_num, out_buf, buf_size, 0, out_rec
);
}

/*
* Check whether reading a record with 'seq_num' would succeed. Note that this
* doesn't mean a record with this number actually exists, only that there is
Expand Down
2 changes: 2 additions & 0 deletions kernel/include/panic.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <common/attributes.h>
#include <common/helpers.h>

bool panic_in_progress(void);

NORETURN
PRINTF_DECL(1, 2)
void panic(const char *reason, ...);
Expand Down
4 changes: 4 additions & 0 deletions kernel/include/private/bug.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@
".short " TO_STR(trap_flags) "\n" \
".popsection\n" \
)

struct registers;

void finish_warn_report(struct registers *regs);
70 changes: 70 additions & 0 deletions kernel/include/private/ubsan.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once

#include <common/attributes.h>
#include <common/bit.h>
#include <common/types.h>

#define UBSAN_TYPE_KIND_INT 0
#define UBSAN_TYPE_INFO_SIGNED BIT_U16(0)
#define UBSAN_TYPE_INFO_LOG2_WIDTH MAKE_BIT_MASK_U16(15, 1)

struct ubsan_source_location {
const char *file;
u32 line;
u32 column;
};

struct ubsan_type {
u16 kind;
u16 info;
char name[];
};

struct ubsan_out_of_bounds_data {
struct ubsan_source_location loc;
const struct ubsan_type *array_type;
const struct ubsan_type *index_type;
};

struct ubsan_shift_data {
struct ubsan_source_location loc;
const struct ubsan_type *lhs_type;
const struct ubsan_type *rhs_type;
};

struct ubsan_value_data {
struct ubsan_source_location loc;
const struct ubsan_type *type;
};

struct ubsan_unreachable_data {
struct ubsan_source_location loc;
};

void __ubsan_handle_out_of_bounds(
struct ubsan_out_of_bounds_data *data, ptr_t index
);
void __ubsan_handle_shift_out_of_bounds(
struct ubsan_shift_data *data, ptr_t lhs, ptr_t rhs
);
void __ubsan_handle_add_overflow(
struct ubsan_value_data *data, ptr_t lhs, ptr_t rhs
);
void __ubsan_handle_sub_overflow(
struct ubsan_value_data *data, ptr_t lhs, ptr_t rhs
);
void __ubsan_handle_mul_overflow(
struct ubsan_value_data *data, ptr_t lhs, ptr_t rhs
);
void __ubsan_handle_negate_overflow(
struct ubsan_value_data *data, ptr_t value
);
void __ubsan_handle_divrem_overflow(
struct ubsan_value_data *data, ptr_t lhs, ptr_t rhs
);
void __ubsan_handle_load_invalid_value(
struct ubsan_value_data *data, ptr_t value
);

NORETURN
void __ubsan_handle_builtin_unreachable(struct ubsan_unreachable_data *data);
Loading
Loading