Skip to content

AD3037: RustEnableSanitizers

Summary

Property Value
ID AD3037
Name RustEnableSanitizers
Category Security
Severity Note
Applies to ELF (Linux/Unix)

Description

Sanitizers are powerful dynamic analysis tools that detect various classes of bugs at runtime. For Rust binaries, sanitizers can catch issues that even Rust's strong type system cannot prevent.

Why This Matters

Rust's ownership system prevents most memory safety issues in safe code, but sanitizers catch bugs that slip through: unsafe code, FFI boundaries, concurrency issues, and memory leaks that the borrow checker can't detect.

What Sanitizers Catch in Rust

Sanitizer Catches Rust Safety Gap
AddressSanitizer Buffer overflow, use-after-free Unsafe blocks
MemorySanitizer Uninitialized reads FFI return values
ThreadSanitizer Data races Interior mutability
LeakSanitizer Memory leaks Rc/Arc cycles

Unsafe Code Detection

unsafe {
    let ptr: *mut i32 = some_allocation();
    *ptr = 42;
    free(ptr);
    *ptr = 100;  // Use-after-free: ASan catches this!
}

FFI Boundary Issues

extern "C" {
    fn get_data() -> *mut Data;  // What if C returns uninitialized?
}

let data = unsafe { get_data() };
// MSan detects if the returned memory is uninitialized

Concurrency Bugs

use std::cell::UnsafeCell;

struct RacyCounter(UnsafeCell<i32>);
unsafe impl Sync for RacyCounter {}  // User said it's fine...

// TSan catches the actual data race at runtime

Memory Leaks

use std::rc::Rc;
use std::cell::RefCell;

struct Node {
    next: Option<Rc<RefCell<Node>>>,
}

// Rc cycle = memory leak
// LSan detects the leak

When to Use Sanitizers

Build Type Sanitizers Purpose
Development Optional Catch bugs early
CI/CD testing Recommended Automated detection
Fuzzing Essential Find edge cases
Production No Too much overhead

Performance Overhead

Sanitizer Runtime Overhead Memory Overhead
ASan 2x 2-3x
MSan 3x 2-3x
TSan 5-15x 5-10x
LSan Low (on exit) Low

CI Integration Value

CI Pipeline with Sanitizers:
  1. Build with ASan
  2. Run test suite
  3. Any sanitizer report = build failure
  4. Bugs caught before merge

Without Sanitizers:
  Bugs may reach production
  Only crash reports reveal issues

Sanitizers are valuable for: - AddressSanitizer (ASan): Detects memory errors like buffer overflows, use-after-free, and memory leaks - MemorySanitizer (MSan): Detects uninitialized memory reads - ThreadSanitizer (TSan): Detects data races in multithreaded code - LeakSanitizer (LSan): Detects memory leaks

While Rust's ownership system prevents many memory safety issues, sanitizers are still valuable for: - Detecting bugs in unsafe code blocks - Finding issues in FFI calls to C/C++ libraries - Catching subtle concurrency bugs - Identifying memory leaks in complex ownership patterns

Note: Sanitizers add significant runtime overhead and should typically only be used in debug/test builds.

Category

Security

Resolution

Enable sanitizers when building Rust binaries for testing:

# AddressSanitizer
RUSTFLAGS="-Z sanitizer=address" cargo +nightly build

# MemorySanitizer (requires nightly and special setup)
RUSTFLAGS="-Z sanitizer=memory" cargo +nightly build

# ThreadSanitizer
RUSTFLAGS="-Z sanitizer=thread" cargo +nightly build

# LeakSanitizer (part of ASan, or standalone)
RUSTFLAGS="-Z sanitizer=leak" cargo +nightly build

For CI/CD integration:

# GitHub Actions example
- name: Run tests with sanitizers
  run: |
    RUSTFLAGS="-Z sanitizer=address" cargo +nightly test

Detection

This rule detects sanitizers by looking for their runtime library symbols:

Sanitizer Detected Symbols
AddressSanitizer __asan_init, __asan_report_*
MemorySanitizer __msan_init, __msan_warning
ThreadSanitizer __tsan_init, __tsan_read, __tsan_write
UBSan __ubsan_handle_*
LeakSanitizer __lsan_init, __lsan_do_leak_check
HWAddressSanitizer __hwasan_init, __hwasan_check

Applicability

This rule applies to: - ELF binaries compiled with Rust (detected via rustc producer or Rust-specific symbols) - Both executables and shared libraries

Result Interpretation

This rule is informational: - Pass (Note): Reports which sanitizers are detected in the binary - Note: Reports when no sanitizers are detected, with a suggestion to consider using them for test builds

Examples

Pass (Sanitizers Detected)

'myapp' is a Rust binary with sanitizer instrumentation: AddressSanitizer, ThreadSanitizer.

Note (No Sanitizers)

'myapp' is a Rust binary without sanitizer instrumentation. For debug/test builds,
consider using '-Zsanitizer=address' or other sanitizers to detect memory safety issues.

Notes

  • Sanitizers require nightly Rust (cargo +nightly)
  • Some sanitizers (like MSan) require all dependencies to be built with instrumentation
  • ASan typically adds 2-3x memory overhead and slows execution by 2x
  • TSan adds significant memory overhead (~5-10x)
  • Production binaries should NOT include sanitizer instrumentation

References