From 04be20a75a6e09d9c2f801fc0e6ffd4e5b486950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 1 May 2021 15:24:28 +0200 Subject: [PATCH] Implement stack protection support this adds kernel & libroot stack protector hooks. it uses /dev/random in userspace. A configure option --enable-stack-protector is added to activate -fstack-protector on selected system components (ATM apps, kits, servers). Change-Id: If3a2920ba9aa0a85eaff4ba6778947f8c76ade31 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3895 Reviewed-by: Adrien Destugues --- build/jam/ArchitectureRules | 16 +++++ configure | 2 + headers/private/kernel/stack_protector.h | 12 ++++ headers/private/libroot/libroot_private.h | 1 + src/system/kernel/Jamfile | 1 + src/system/kernel/main.cpp | 3 + src/system/kernel/stack_protector.cpp | 34 +++++++++++ src/system/libroot/libroot_init.c | 1 + src/system/libroot/os/Jamfile | 1 + src/system/libroot/os/stack_protector.cpp | 58 +++++++++++++++++++ src/tests/system/libroot/os/Jamfile | 8 +++ .../system/libroot/os/stack_protector_test.c | 16 +++++ 12 files changed, 153 insertions(+) create mode 100644 headers/private/kernel/stack_protector.h create mode 100644 src/system/kernel/stack_protector.cpp create mode 100644 src/system/libroot/os/stack_protector.cpp create mode 100644 src/tests/system/libroot/os/stack_protector_test.c diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules index a8ecf832ba..95b65528ea 100644 --- a/build/jam/ArchitectureRules +++ b/build/jam/ArchitectureRules @@ -600,6 +600,16 @@ rule ArchitectureSetupWarnings architecture } } + rule EnableStackProtector dirTokens : scope { + # enable stack protector, if requested + if $(HAIKU_USE_STACK_PROTECTOR) = 1 { + AppendToConfigVar CCFLAGS : HAIKU_TOP $(dirTokens) : + -fstack-protector : $(scope) ; + AppendToConfigVar C++FLAGS : HAIKU_TOP $(dirTokens) : + -fstack-protector : $(scope) ; + } + } + # Work-around for GCC 2 problem -- despite -Wno-multichar it reports # multichar warnings in headers/private/kernel/debugger_keymaps.h included # by src/system/kernel/arch/x86/arch_debug_console.cpp. @@ -746,6 +756,12 @@ rule ArchitectureSetupWarnings architecture EnableWerror src system libroot posix locale ; EnableWerror src system libroot posix wchar ; EnableWerror src system runtime_loader ; + + EnableStackProtector src apps ; + EnableStackProtector src kits ; + EnableStackProtector src preferences ; + EnableStackProtector src servers ; + EnableStackProtector src system kernel ; } diff --git a/configure b/configure index 5d7a1391e8..e837d06291 100755 --- a/configure +++ b/configure @@ -92,6 +92,7 @@ options: --with-gdb specify the path to a GDB source dir, to build GDB for each arch we build the cross-tools for. + --use-stack-protector Build with stack protection enabled environment variables: CC The host compiler. Defaults to "gcc". @@ -803,6 +804,7 @@ while [ $# -gt 0 ] ; do --no-full-xattr)HAIKU_HOST_USE_XATTR=0; shift 1;; --no-xattr) HAIKU_HOST_USE_XATTR_REF=0; shift 1;; --with-gdb) gdbSources=$2; shift 2;; + --use-stack-protector) HAIKU_USE_STACK_PROTECTOR=1; shift 1;; *) echo Invalid argument: \`$1\'; exit 1;; esac done diff --git a/headers/private/kernel/stack_protector.h b/headers/private/kernel/stack_protector.h new file mode 100644 index 0000000000..5a20c52a61 --- /dev/null +++ b/headers/private/kernel/stack_protector.h @@ -0,0 +1,12 @@ +/* + * Copyright 2021, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_STACK_PROTECTOR_H +#define _KERNEL_STACK_PROTECTOR_H + + +void stack_protector_init(); + + +#endif /* _KERNEL_STACK_PROTECTOR_H */ diff --git a/headers/private/libroot/libroot_private.h b/headers/private/libroot/libroot_private.h index 5055848b03..e2e977ac17 100644 --- a/headers/private/libroot/libroot_private.h +++ b/headers/private/libroot/libroot_private.h @@ -55,6 +55,7 @@ void __reinit_pwd_backend_after_fork(void); int32 __arch_get_stack_trace(addr_t* returnAddresses, int32 maxCount, int32 skipFrames, addr_t stackBase, addr_t stackEnd); +void __init_stack_protector(void); void __set_stack_protection(void); diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index 5f45850d25..993bdd49e2 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -47,6 +47,7 @@ KernelMergeObject kernel_core.o : sem.cpp shutdown.cpp signal.cpp + stack_protector.cpp system_info.cpp smp.cpp syscalls.cpp diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp index 813f508b96..f4b948c9f4 100644 --- a/src/system/kernel/main.cpp +++ b/src/system/kernel/main.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,8 @@ _start(kernel_args *bootKernelArgs, int currentCPU) thread_init(&sKernelArgs); TRACE("init kernel daemons\n"); kernel_daemon_init(); + TRACE("init stack protector\n"); + stack_protector_init(); arch_platform_init_post_thread(&sKernelArgs); TRACE("init I/O interrupts\n"); diff --git a/src/system/kernel/stack_protector.cpp b/src/system/kernel/stack_protector.cpp new file mode 100644 index 0000000000..ac299760ea --- /dev/null +++ b/src/system/kernel/stack_protector.cpp @@ -0,0 +1,34 @@ +/* + * Copyright 2021, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include + + +extern "C" { + +long __stack_chk_guard; + + +void +__stack_chk_fail() +{ + panic("stack smashing detected\n"); +} + + +} + + +void +stack_protector_init() +{ + __stack_chk_guard = secure_get_random(); +} + diff --git a/src/system/libroot/libroot_init.c b/src/system/libroot/libroot_init.c index 3dfe64ee6a..52cc2bd7e2 100644 --- a/src/system/libroot/libroot_init.c +++ b/src/system/libroot/libroot_init.c @@ -80,6 +80,7 @@ initialize_before(image_id imageID) __init_heap(); __init_env_post_heap(); __init_pwd_backend(); + __init_stack_protector(); __set_stack_protection(); } diff --git a/src/system/libroot/os/Jamfile b/src/system/libroot/os/Jamfile index 572f8921e7..97137fc5b8 100644 --- a/src/system/libroot/os/Jamfile +++ b/src/system/libroot/os/Jamfile @@ -34,6 +34,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { port.c scheduler.c sem.c + stack_protector.cpp system_info.cpp system_revision.c team.c diff --git a/src/system/libroot/os/stack_protector.cpp b/src/system/libroot/os/stack_protector.cpp new file mode 100644 index 0000000000..1c803d08ec --- /dev/null +++ b/src/system/libroot/os/stack_protector.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2021, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include + + +extern "C" { + +long __stack_chk_guard = 0; + + +void +__init_stack_protector() +{ + if (__stack_chk_guard != 0) + return; + + bool done = false; + int fd = open("/dev/random", O_RDONLY, 0); + if (fd >= 0) { + done = read(fd, &__stack_chk_guard, sizeof(__stack_chk_guard)) + == sizeof(__stack_chk_guard); + close(fd); + } + + if (!done) { + ((unsigned char *)(void *)__stack_chk_guard)[0] = 0; + ((unsigned char *)(void *)__stack_chk_guard)[1] = 0; + ((unsigned char *)(void *)__stack_chk_guard)[2] = '\n'; + ((unsigned char *)(void *)__stack_chk_guard)[3] = 0xff; + } +} + + +void +__stack_chk_fail() +{ + sigset_t mask; + sigfillset(&mask); + sigdelset(&mask, SIGABRT); + sigprocmask(SIG_BLOCK, &mask, NULL); + + abort(); +} + +} + + +#if __GNUC__ >= 4 +extern "C" void __stack_chk_fail_local() __attribute__((visibility("hidden"))); +__weak_reference(__stack_chk_fail, __stack_chk_fail_local); +#endif diff --git a/src/tests/system/libroot/os/Jamfile b/src/tests/system/libroot/os/Jamfile index 41f8d01280..b6028376e9 100644 --- a/src/tests/system/libroot/os/Jamfile +++ b/src/tests/system/libroot/os/Jamfile @@ -28,6 +28,14 @@ SimpleTest get_cpu_num_test : get_cpu_num_test.cpp ; + +CCFLAGS += -fstack-protector ; +SimpleTest stack_protector_test : + stack_protector_test.c +; + + + # Tell Jam where to find these sources SEARCH on [ FGristFiles driver_settings.cpp diff --git a/src/tests/system/libroot/os/stack_protector_test.c b/src/tests/system/libroot/os/stack_protector_test.c new file mode 100644 index 0000000000..d835a101e1 --- /dev/null +++ b/src/tests/system/libroot/os/stack_protector_test.c @@ -0,0 +1,16 @@ +#include +#include +#include + +void get_input(char *data) +{ + strcpy(data, "01234567"); +} + + +int main(void) +{ + char buffer[8]; + get_input(buffer); + return buffer[0]; +}