Igris Blog
Understanding UBSAN

Understanding UBSAN

January 4, 2025
4 min read
Table of Contents

Undefined Behavior Sanitizer (UBSAN) is a powerful runtime checker that helps detect undefined behavior in C and C++ code. The Linux kernel integrates UBSAN to catch subtle memory and arithmetic errors that could otherwise lead to security vulnerabilities or unpredictable behavior.

What is Undefined Behavior?

Undefined behavior (UB) occurs when a program executes an operation that is not defined by the C standard. Some common examples include:

  • Signed integer overflow
  • Use of uninitialized memory
  • Out-of-bounds array access
  • Dereferencing NULL pointers
  • Misaligned memory access

Since undefined behavior can lead to inconsistent program execution, UBSAN is used to catch these issues at runtime.

Enabling UBSAN in the Linux Kernel

To enable UBSAN in your kernel build, use the following configuration options:

CONFIG_UBSAN=y
CONFIG_UBSAN_TRAP=y # Optional: Stops execution on UB detection

If you want to include only specific UBSAN checks, you can select:

CONFIG_UBSAN_BOUNDS=y  # Detects out-of-bounds array access
CONFIG_UBSAN_SHIFT=y   # Detects invalid shift operations
CONFIG_UBSAN_DIV_ZERO=y # Detects division by zero

Rebuild and install the kernel, then boot into it.

Live Example: Detecting Integer Overflow

Let’s write a simple kernel module that triggers an integer overflow:

#include <linux/module.h>
#include <linux/kernel.h>
 
static int __init ubsan_test_init(void) {
    int a = INT_MAX;
    int b = 1;
    int c = a + b;  // This causes signed integer overflow
    pr_info("UBSAN test: a=%d, b=%d, c=%d\n", a, b, c);
    return 0;
}
 
static void __exit ubsan_test_exit(void) {
    pr_info("UBSAN test module exiting\n");
}
 
module_init(ubsan_test_init);
module_exit(ubsan_test_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Security Researcher");
MODULE_DESCRIPTION("UBSAN Test Module");

Compiling and Running

Compile the module and insert it into the kernel:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
sudo insmod ubsan_test.ko

Expected UBSAN Output

If UBSAN is enabled, you’ll see an error message similar to:

[  105.123456] UBSAN: Undefined behavior in ubsan_test.c:7:9
[  105.123467] signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
[  105.123479] CPU: 0 PID: 1234 Comm: insmod Not tainted 5.10.0 #1
[  105.123490] Call Trace:
[  105.123501]  dump_stack+0x6d/0x88
[  105.123512]  ubsan_test_init+0x2f/0x1000 [ubsan_test]
[  105.123523]  do_one_initcall+0x48/0x1a0
[  105.123534]  ? do_init_module+0x21/0x220
[  105.123545]  do_init_module+0x50/0x220
[  105.123556]  load_module+0x1e92/0x21a0
[  105.123567]  __do_sys_finit_module+0xad/0x110
[  105.123578]  do_syscall_64+0x33/0x40
[  105.123589]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  105.123600] RIP: 0033:0x7f2b3c9e515d

If CONFIG_UBSAN_TRAP=y is set, the system will panic instead of continuing execution.

Cleaning Up

To remove the module:

sudo rmmod ubsan_test

Expected output:

[  120.456789] UBSAN test module exiting

Why UBSAN Matters for Security

UBSAN helps find critical memory safety issues and logic errors that attackers might exploit. It plays a vital role in hardening the kernel against:

  • Integer overflows leading to privilege escalation
  • Out-of-bounds reads/writes causing memory corruption
  • Type mismatches that can lead to unexpected execution paths

By enabling UBSAN in testing environments, developers can catch and fix undefined behavior before it becomes a security risk.

Conclusion

UBSAN is a valuable tool for detecting undefined behavior in the Linux kernel. By enabling it in kernel builds and leveraging it during fuzz testing (e.g., with syzkaller), developers can proactively identify and fix critical security bugs.