mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2026-06-12 22:31:45 +01:00
7bdcf55705
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>
115 lines
2.9 KiB
C
115 lines
2.9 KiB
C
/*
|
|
* 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);
|