sandbox: add handler for exceptions

Add a handler for SIGILL, SIGBUS, SIGSEGV.

When an exception occurs print the program counter and the loaded
UEFI binaries and reset the system if CONFIG_SANDBOX_CRASH_RESET=y
or exit to the OS otherwise.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Heinrich Schuchardt 2020-11-12 00:29:56 +01:00 committed by Simon Glass
parent 21f9075def
commit b46f30a378
5 changed files with 105 additions and 0 deletions

View File

@ -51,6 +51,15 @@ config HOST_64BIT
endchoice
config SANDBOX_CRASH_RESET
bool "Reset on crash"
help
If an illegal instruction or an illegal memory access occurs, the
sandbox by default writes a crash dump and exits. If you set this
flag, the sandbox is reset instead. This may be useful when running
test suites like the UEFI self certification test which continue
with the next test after a crash.
config SANDBOX_BITS_PER_LONG
int
default 32 if HOST_32BIT

View File

@ -3,6 +3,8 @@
* Copyright (c) 2011 The Chromium OS Authors.
*/
#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@ -15,11 +17,13 @@
#include <string.h>
#include <termios.h>
#include <time.h>
#include <ucontext.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <linux/compiler_attributes.h>
#include <linux/types.h>
#include <asm/getopt.h>
@ -191,6 +195,42 @@ static void os_sigint_handler(int sig)
raise(SIGINT);
}
static void os_signal_handler(int sig, siginfo_t *info, void *con)
{
ucontext_t __maybe_unused *context = con;
unsigned long pc;
#if defined(__x86_64__)
pc = context->uc_mcontext.gregs[REG_RIP];
#elif defined(__aarch64__)
pc = context->uc_mcontext.pc;
#elif defined(__riscv)
pc = context->uc_mcontext.__gregs[REG_PC];
#else
const char msg[] =
"\nUnsupported architecture, cannot read program counter\n";
os_write(1, msg, sizeof(msg));
pc = 0;
#endif
os_signal_action(sig, pc);
}
int os_setup_signal_handlers(void)
{
struct sigaction act;
act.sa_sigaction = os_signal_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO | SA_NODEFER;
if (sigaction(SIGILL, &act, NULL) ||
sigaction(SIGBUS, &act, NULL) ||
sigaction(SIGSEGV, &act, NULL))
return -1;
return 0;
}
/* Put tty into raw mode so <tab> and <ctrl+c> work */
void os_tty_raw(int fd, bool allow_sigs)
{

View File

@ -451,6 +451,10 @@ int main(int argc, char *argv[])
if (ret)
goto err;
ret = os_setup_signal_handlers();
if (ret)
goto err;
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
gd->malloc_base = CONFIG_MALLOC_F_ADDR;
#endif

View File

@ -6,7 +6,13 @@
*/
#include <common.h>
#include <efi_loader.h>
#include <irq_func.h>
#include <os.h>
#include <asm-generic/signal.h>
#include <asm/u-boot-sandbox.h>
DECLARE_GLOBAL_DATA_PTR;
int interrupt_init(void)
{
@ -21,3 +27,32 @@ int disable_interrupts(void)
{
return 0;
}
void os_signal_action(int sig, unsigned long pc)
{
efi_restore_gd();
switch (sig) {
case SIGILL:
printf("\nIllegal instruction\n");
break;
case SIGBUS:
printf("\nBus error\n");
break;
case SIGSEGV:
printf("\nSegmentation violation\n");
break;
default:
break;
}
printf("pc = 0x%lx, ", pc);
printf("pc_reloc = 0x%lx\n\n", pc - gd->reloc_off);
efi_print_image_infos((void *)pc);
if (IS_ENABLED(CONFIG_SANDBOX_CRASH_RESET)) {
printf("resetting ...\n\n");
sandbox_reset();
} else {
sandbox_exit();
}
}

View File

@ -407,4 +407,21 @@ void *os_find_text_base(void);
*/
void os_relaunch(char *argv[]);
/**
* os_setup_signal_handlers() - setup signal handlers
*
* Install signal handlers for SIGBUS and SIGSEGV.
*
* Return: 0 for success
*/
int os_setup_signal_handlers(void);
/**
* os_signal_action() - handle a signal
*
* @sig: signal
* @pc: program counter
*/
void os_signal_action(int sig, unsigned long pc);
#endif