mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2026-06-13 06:31:51 +01:00
lib: sbi: add UBSan support
UBSan (Undefined Behavior Sanitizer) is a tool implemented using compiler instrumentation at runtime that allows checking for statements whose output is not deterministic or defined by the C standard. Compiling and running OpenSBI with UBSan instrumentation will print a message in the console if any sentence performs such an action. Support involves two main components: 1. The UBSan implementation hooks (derived from NetBSD), used by the compiler to handle the check output. 2. A test suite integrated with the SBI unit test framework to verify correct operation at runtime. Usage: make UBSAN=y PLATFORM=generic ... The test suite is built when both UBSAN=y and CONFIG_SBIUNIT=y are enabled. When UBSan is enabled, FW_PAYLOAD_OFFSET may need to be increased due to the size increase added by the instrumentation. A value of 0x400000 has been tested. UBSan adds runtime overhead and is intended for development builds only, not for production. Note: This patch marks __stack_chk_guard in sbi_init.c as a weak symbol to prevent multiple definition errors at compile time with UBSan instrumentation enabled. This resolves the conflict between the .globl definitions in sbi_init.c and test_head.S. Signed-off-by: Marcos Oduardo <marcos.oduardo@gmail.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20260515163321.2038366-1-marcos.oduardo@gmail.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
committed by
Anup Patel
parent
c175c97a27
commit
7bdcf55705
@@ -24,3 +24,8 @@ libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_bitops_test.o
|
||||
|
||||
carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += string_test_suite
|
||||
libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_string_test.o
|
||||
|
||||
ifeq ($(UBSAN),y)
|
||||
carray-sbi_unit_tests-$(CONFIG_SBIUNIT) += ubsan_test_suite
|
||||
libsbi-objs-$(CONFIG_SBIUNIT) += tests/sbi_ubsan_test.o
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Author: Marcos Oduardo <marcos.oduardo@gmail.com>
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_unit_test.h>
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_ubsan.h>
|
||||
|
||||
#define UBSAN_EXPECT_FIRES(test, stmt) \
|
||||
do { \
|
||||
unsigned long _before = sbi_ubsan_report_count; \
|
||||
stmt; \
|
||||
SBIUNIT_EXPECT_NE(test, sbi_ubsan_report_count, _before); \
|
||||
} while (0)
|
||||
|
||||
static void test_ubsan_add_overflow(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile int a = 0x7FFFFFFF; //INT_MAx
|
||||
volatile int b = 1;
|
||||
volatile int c;
|
||||
UBSAN_EXPECT_FIRES(test, c = a + b);
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static void test_ubsan_sub_overflow(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile int a = 0x80000000; //INT_MIN
|
||||
volatile int b = 1;
|
||||
volatile int c;
|
||||
UBSAN_EXPECT_FIRES(test, c = a - b);
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static void test_ubsan_mul_overflow(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile int a = 0x7FFFFFFF;
|
||||
volatile int b = 2;
|
||||
volatile int c;
|
||||
UBSAN_EXPECT_FIRES(test, c = a * b);
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static void test_ubsan_divrem(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile int a = 10;
|
||||
volatile int b = 0;
|
||||
volatile int c;
|
||||
UBSAN_EXPECT_FIRES(test, c = a / b);
|
||||
(void)c;
|
||||
}
|
||||
|
||||
static void test_ubsan_oob(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile int idx = 5;
|
||||
int arr[3] = { 1, 2, 3 };
|
||||
volatile int val;
|
||||
UBSAN_EXPECT_FIRES(test, val = arr[idx]);
|
||||
(void)val;
|
||||
}
|
||||
|
||||
static void test_ubsan_shift_too_large(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile unsigned long val = 1;
|
||||
volatile int shift = 64;
|
||||
volatile unsigned long res;
|
||||
UBSAN_EXPECT_FIRES(test, res = val << shift);
|
||||
(void)res;
|
||||
}
|
||||
|
||||
static void test_ubsan_shift_negative(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile int val = 1;
|
||||
volatile int shift = -1;
|
||||
volatile int res;
|
||||
|
||||
UBSAN_EXPECT_FIRES(test, res = val << shift);
|
||||
(void)res;
|
||||
}
|
||||
|
||||
static void test_ubsan_load_invalid_bool(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile char bool_val = 5;
|
||||
volatile bool *b_ptr = (bool *)&bool_val;
|
||||
volatile int taken = 0;
|
||||
UBSAN_EXPECT_FIRES(test, if (*b_ptr) taken = 1);
|
||||
(void)taken;
|
||||
}
|
||||
|
||||
static void test_ubsan_pointer_overflow(struct sbiunit_test_case *test)
|
||||
{
|
||||
volatile uintptr_t base = 0xFFFFFFFFFFFFFFFEUL;
|
||||
volatile char *ptr = (char *)base;
|
||||
volatile char *res;
|
||||
UBSAN_EXPECT_FIRES(test, res = ptr + 5);
|
||||
(void)res;
|
||||
}
|
||||
|
||||
static struct sbiunit_test_case ubsan_tests[] = {
|
||||
SBIUNIT_TEST_CASE(test_ubsan_add_overflow),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_sub_overflow),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_mul_overflow),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_divrem),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_oob),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_shift_too_large),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_shift_negative),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_load_invalid_bool),
|
||||
SBIUNIT_TEST_CASE(test_ubsan_pointer_overflow),
|
||||
SBIUNIT_END_CASE,
|
||||
};
|
||||
|
||||
SBIUNIT_TEST_SUITE(ubsan_test_suite, ubsan_tests);
|
||||
Reference in New Issue
Block a user