mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
Merge pull request #26759 from medhefgo/boot-stack-protector
boot: Add support for stack protector/trapping math/ubsan
This commit is contained in:
commit
0bc2bcf4fe
23
meson.build
23
meson.build
@ -366,6 +366,8 @@ possible_common_cc_flags = [
|
||||
'-Werror=implicit-int',
|
||||
'-Werror=incompatible-pointer-types',
|
||||
'-Werror=int-conversion',
|
||||
'-Werror=missing-declarations',
|
||||
'-Werror=missing-prototypes',
|
||||
'-Werror=overflow',
|
||||
'-Werror=override-init',
|
||||
'-Werror=return-type',
|
||||
@ -397,7 +399,16 @@ possible_common_cc_flags = [
|
||||
'-Wno-error=#warnings', # clang
|
||||
'-Wno-string-plus-int', # clang
|
||||
|
||||
'-fdiagnostics-show-option',
|
||||
'-fno-common',
|
||||
'-fstack-protector',
|
||||
'-fstack-protector-strong',
|
||||
'-fstrict-flex-arrays',
|
||||
'--param=ssp-buffer-size=4',
|
||||
]
|
||||
|
||||
possible_common_link_flags = [
|
||||
'-fstack-protector',
|
||||
]
|
||||
|
||||
c_args = get_option('c_args')
|
||||
@ -432,7 +443,6 @@ possible_link_flags = [
|
||||
'-Wl,--fatal-warnings',
|
||||
'-Wl,-z,now',
|
||||
'-Wl,-z,relro',
|
||||
'-fstack-protector',
|
||||
]
|
||||
|
||||
if get_option('b_sanitize') == 'none'
|
||||
@ -454,16 +464,9 @@ if get_option('mode') == 'release'
|
||||
endif
|
||||
|
||||
possible_cc_flags = [
|
||||
'-Werror=missing-declarations',
|
||||
'-Werror=missing-prototypes',
|
||||
'-fdiagnostics-show-option',
|
||||
'-fno-common',
|
||||
'-fno-strict-aliasing',
|
||||
'-fstack-protector',
|
||||
'-fstack-protector-strong',
|
||||
'-fstrict-flex-arrays=1',
|
||||
'-fvisibility=hidden',
|
||||
'--param=ssp-buffer-size=4',
|
||||
]
|
||||
|
||||
if get_option('buildtype') != 'debug'
|
||||
@ -486,6 +489,10 @@ add_project_arguments(
|
||||
),
|
||||
language : 'c')
|
||||
|
||||
add_project_link_arguments(
|
||||
cc.get_supported_link_arguments(possible_common_link_flags),
|
||||
language : 'c')
|
||||
|
||||
userspace_c_args += cc.get_supported_arguments(possible_cc_flags)
|
||||
userspace_c_ld_args += cc.get_supported_link_arguments(possible_link_flags)
|
||||
|
||||
|
@ -882,6 +882,10 @@ char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) {
|
||||
# undef memcmp
|
||||
# undef memcpy
|
||||
# undef memset
|
||||
_used_ void *memchr(const void *p, int c, size_t n);
|
||||
_used_ int memcmp(const void *p1, const void *p2, size_t n);
|
||||
_used_ void *memcpy(void * restrict dest, const void * restrict src, size_t n);
|
||||
_used_ void *memset(void *p, int c, size_t n);
|
||||
#else
|
||||
/* And for userspace unit testing we need to give them an efi_ prefix. */
|
||||
# define memchr efi_memchr
|
||||
@ -890,7 +894,7 @@ char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) {
|
||||
# define memset efi_memset
|
||||
#endif
|
||||
|
||||
_used_ void *memchr(const void *p, int c, size_t n) {
|
||||
void *memchr(const void *p, int c, size_t n) {
|
||||
if (!p || n == 0)
|
||||
return NULL;
|
||||
|
||||
@ -902,7 +906,7 @@ _used_ void *memchr(const void *p, int c, size_t n) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_used_ int memcmp(const void *p1, const void *p2, size_t n) {
|
||||
int memcmp(const void *p1, const void *p2, size_t n) {
|
||||
const uint8_t *up1 = p1, *up2 = p2;
|
||||
int r;
|
||||
|
||||
@ -922,7 +926,7 @@ _used_ int memcmp(const void *p1, const void *p2, size_t n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_used_ void *memcpy(void * restrict dest, const void * restrict src, size_t n) {
|
||||
void *memcpy(void * restrict dest, const void * restrict src, size_t n) {
|
||||
if (!dest || !src || n == 0)
|
||||
return dest;
|
||||
|
||||
@ -949,7 +953,7 @@ _used_ void *memcpy(void * restrict dest, const void * restrict src, size_t n) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
_used_ void *memset(void *p, int c, size_t n) {
|
||||
void *memset(void *p, int c, size_t n) {
|
||||
if (!p || n == 0)
|
||||
return p;
|
||||
|
||||
|
@ -1,17 +1,33 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "log.h"
|
||||
#include "proto/rng.h"
|
||||
#include "proto/simple-text-io.h"
|
||||
|
||||
static unsigned log_count = 0;
|
||||
|
||||
_noreturn_ static void freeze(void) {
|
||||
void freeze(void) {
|
||||
for (;;)
|
||||
BS->Stall(60 * 1000 * 1000);
|
||||
}
|
||||
|
||||
_noreturn_ static void panic(const char16_t *message) {
|
||||
if (ST->ConOut->Mode->CursorColumn > 0)
|
||||
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n");
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTRED, EFI_BLACK));
|
||||
ST->ConOut->OutputString(ST->ConOut, (char16_t *) message);
|
||||
freeze();
|
||||
}
|
||||
|
||||
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) {
|
||||
log_error("systemd-boot assertion '%s' failed at %s:%u@%s. Halting.", expr, file, line, function);
|
||||
static bool asserting = false;
|
||||
|
||||
/* Let's be paranoid. */
|
||||
if (asserting)
|
||||
panic(u"systemd-boot: Nested assertion failure, halting.");
|
||||
|
||||
asserting = true;
|
||||
log_error("systemd-boot: Assertion '%s' failed at %s:%u@%s, halting.", expr, file, line, function);
|
||||
freeze();
|
||||
}
|
||||
|
||||
@ -44,16 +60,43 @@ void log_wait(void) {
|
||||
log_count = 0;
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
/* These override the (weak) div0 handlers from libgcc as they would otherwise call raise() instead. */
|
||||
_used_ intptr_t __stack_chk_guard = (intptr_t) 0x70f6967de78acae3;
|
||||
|
||||
_used_ _noreturn_ int __aeabi_idiv0(int return_value) {
|
||||
log_error("Division by zero.");
|
||||
freeze();
|
||||
}
|
||||
|
||||
_used_ _noreturn_ long long __aeabi_ldiv0(long long return_value) {
|
||||
log_error("Division by zero.");
|
||||
freeze();
|
||||
/* We can only set a random stack canary if this function attribute is available,
|
||||
* otherwise this may create a stack check fail. */
|
||||
#if STACK_PROTECTOR_RANDOM
|
||||
void __stack_chk_guard_init(void) {
|
||||
EFI_RNG_PROTOCOL *rng;
|
||||
if (BS->LocateProtocol(MAKE_GUID_PTR(EFI_RNG_PROTOCOL), NULL, (void **) &rng) == EFI_SUCCESS)
|
||||
(void) rng->GetRNG(rng, NULL, sizeof(__stack_chk_guard), (void *) &__stack_chk_guard);
|
||||
}
|
||||
#endif
|
||||
|
||||
_used_ _noreturn_ void __stack_chk_fail(void);
|
||||
_used_ _noreturn_ void __stack_chk_fail_local(void);
|
||||
void __stack_chk_fail(void) {
|
||||
panic(u"systemd-boot: Stack check failed, halting.");
|
||||
}
|
||||
void __stack_chk_fail_local(void) {
|
||||
__stack_chk_fail();
|
||||
}
|
||||
|
||||
/* Called by libgcc for some fatal errors like integer overflow with -ftrapv. */
|
||||
_used_ _noreturn_ void abort(void);
|
||||
void abort(void) {
|
||||
panic(u"systemd-boot: Unknown error, halting.");
|
||||
}
|
||||
|
||||
#if defined(__ARM_EABI__)
|
||||
/* These override the (weak) div0 handlers from libgcc as they would otherwise call raise() instead. */
|
||||
_used_ _noreturn_ int __aeabi_idiv0(int return_value);
|
||||
_used_ _noreturn_ long long __aeabi_ldiv0(long long return_value);
|
||||
|
||||
int __aeabi_idiv0(int return_value) {
|
||||
panic(u"systemd-boot: Division by zero, halting.");
|
||||
}
|
||||
|
||||
long long __aeabi_ldiv0(long long return_value) {
|
||||
panic(u"systemd-boot: Division by zero, halting.");
|
||||
}
|
||||
#endif
|
||||
|
@ -3,6 +3,23 @@
|
||||
|
||||
#include "efi-string.h"
|
||||
|
||||
#if defined __has_attribute
|
||||
# if __has_attribute(no_stack_protector)
|
||||
# define HAVE_NO_STACK_PROTECTOR_ATTRIBUTE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_NO_STACK_PROTECTOR_ATTRIBUTE) && \
|
||||
(defined(__SSP__) || defined(__SSP_ALL__) || \
|
||||
defined(__SSP_STRONG__) || defined(__SSP_EXPLICIT__))
|
||||
# define STACK_PROTECTOR_RANDOM 1
|
||||
__attribute__((no_stack_protector, noinline)) void __stack_chk_guard_init(void);
|
||||
#else
|
||||
# define STACK_PROTECTOR_RANDOM 0
|
||||
# define __stack_chk_guard_init()
|
||||
#endif
|
||||
|
||||
_noreturn_ void freeze(void);
|
||||
void log_wait(void);
|
||||
_gnu_printf_(2, 3) EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...);
|
||||
#define log_error_status(status, ...) log_internal(status, __VA_ARGS__)
|
||||
|
@ -139,6 +139,7 @@ efi_c_args += cc.get_supported_arguments(
|
||||
'-fwide-exec-charset=UCS2',
|
||||
# gcc docs says this is required for ms_abi to work correctly.
|
||||
'-maccumulate-outgoing-args',
|
||||
'-mstack-protector-guard=global',
|
||||
)
|
||||
|
||||
# Debug information has little value in release builds as no normal human being knows
|
||||
@ -178,20 +179,23 @@ efi_disabled_c_args = cc.get_supported_arguments(
|
||||
'-fcf-protection=none',
|
||||
'-fno-asynchronous-unwind-tables',
|
||||
'-fno-exceptions',
|
||||
'-fno-trapv',
|
||||
'-fno-sanitize=all',
|
||||
'-fno-stack-clash-protection',
|
||||
'-fno-stack-protector',
|
||||
'-fno-unwind-tables',
|
||||
)
|
||||
efi_c_args += efi_disabled_c_args
|
||||
efi_c_ld_args += efi_disabled_c_args
|
||||
efi_override_options = [
|
||||
'b_coverage=false',
|
||||
'b_pgo=off',
|
||||
'b_sanitize=none',
|
||||
]
|
||||
|
||||
if get_option('b_sanitize') == 'undefined'
|
||||
efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize-link-runtime')
|
||||
else
|
||||
efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize=all')
|
||||
efi_override_options += 'b_sanitize=none'
|
||||
endif
|
||||
|
||||
efi_c_args += efi_disabled_c_args
|
||||
efi_c_ld_args += efi_disabled_c_args
|
||||
|
||||
if cc.get_id() == 'clang'
|
||||
# clang is too picky sometimes.
|
||||
efi_c_args += '-Wno-unused-command-line-argument'
|
||||
@ -254,6 +258,10 @@ stub_sources = files(
|
||||
'stub.c',
|
||||
)
|
||||
|
||||
if get_option('b_sanitize') == 'undefined'
|
||||
libefi_sources += files('ubsan.c')
|
||||
endif
|
||||
|
||||
if host_machine.cpu_family() in ['x86', 'x86_64']
|
||||
stub_sources += files('linux_x86.c')
|
||||
endif
|
||||
|
46
src/boot/efi/ubsan.c
Normal file
46
src/boot/efi/ubsan.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "log.h"
|
||||
|
||||
typedef struct {
|
||||
const char *filename;
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
} SourceLocation;
|
||||
|
||||
/* Note that all ubsan handlers have a pointer to a type-specific struct passed as first argument.
|
||||
* Since we do not inspect the extra data in it we can just treat it as a SourceLocation struct
|
||||
* directly to keep things simple. */
|
||||
|
||||
#define HANDLER(name, ...) \
|
||||
_used_ _noreturn_ void __ubsan_handle_##name(__VA_ARGS__); \
|
||||
void __ubsan_handle_##name(__VA_ARGS__) { \
|
||||
log_error("systemd-boot: %s in %s@%u:%u", \
|
||||
__func__, \
|
||||
location->filename, \
|
||||
location->line, \
|
||||
location->column); \
|
||||
freeze(); \
|
||||
}
|
||||
|
||||
#define UNARY_HANDLER(name) HANDLER(name, SourceLocation *location, uintptr_t v)
|
||||
#define BINARY_HANDLER(name) HANDLER(name, SourceLocation *location, uintptr_t v1, uintptr_t v2)
|
||||
|
||||
UNARY_HANDLER(load_invalid_value);
|
||||
UNARY_HANDLER(negate_overflow);
|
||||
UNARY_HANDLER(out_of_bounds);
|
||||
UNARY_HANDLER(type_mismatch_v1);
|
||||
UNARY_HANDLER(vla_bound_not_positive);
|
||||
|
||||
BINARY_HANDLER(add_overflow);
|
||||
BINARY_HANDLER(divrem_overflow);
|
||||
BINARY_HANDLER(implicit_conversion);
|
||||
BINARY_HANDLER(mul_overflow);
|
||||
BINARY_HANDLER(pointer_overflow);
|
||||
BINARY_HANDLER(shift_out_of_bounds);
|
||||
BINARY_HANDLER(sub_overflow);
|
||||
|
||||
HANDLER(builtin_unreachable, SourceLocation *location);
|
||||
HANDLER(invalid_builtin, SourceLocation *location);
|
||||
HANDLER(nonnull_arg, SourceLocation *location);
|
||||
HANDLER(nonnull_return_v1, SourceLocation *attr_location, SourceLocation *location);
|
@ -172,10 +172,12 @@ void hexdump(const char16_t *prefix, const void *data, size_t size);
|
||||
EFI_SYSTEM_TABLE *ST; \
|
||||
EFI_BOOT_SERVICES *BS; \
|
||||
EFI_RUNTIME_SERVICES *RT; \
|
||||
EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table); \
|
||||
EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) { \
|
||||
ST = system_table; \
|
||||
BS = system_table->BootServices; \
|
||||
RT = system_table->RuntimeServices; \
|
||||
__stack_chk_guard_init(); \
|
||||
notify_debugger((identity), (wait_for_debugger)); \
|
||||
EFI_STATUS err = func(image); \
|
||||
log_wait(); \
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "proto/device-path.h"
|
||||
#include "string-util-fundamental.h"
|
||||
#include "util.h"
|
||||
#include "vmm.h"
|
||||
|
||||
#define QEMU_KERNEL_LOADER_FS_MEDIA_GUID \
|
||||
{ 0x1428f772, 0xb64a, 0x441e, { 0xb8, 0xc3, 0x9e, 0xbd, 0xd7, 0xf8, 0x93, 0xc7 } }
|
||||
|
Loading…
x
Reference in New Issue
Block a user