Table of Contents
Fetching ...

SafeFFI: Efficient Sanitization at the Boundary Between Safe and Unsafe Code in Rust and Mixed-Language Applications

Oliver Braunsdorf, Tim Lange, Konrad Hohentanner, Julian Horsch, Johannes Kinder

TL;DR

SafeFFI addresses memory-safety challenges in Rust and mixed-language applications by shifting sanitizer checks away from every pointer dereference to the boundary where raw pointers cast to safe pointers occur. It achieves this by annotating pointer types in MIR and propagating them through LLVM IR, hoisting checks to safe-pointer creation sites, and injecting a single dynamic boundary check (safeffi_ensure) when necessary. The approach eliminates the need for expensive whole-program points-to analyses, reducing compile-time overhead and enabling substantial runtime gains, with median improvements from 3.22x to 2.51x and up to 98% elision of sanitizer checks in evaluated crates. Empirically, SafeFFI preserves sanitizer correctness (detecting known vulnerabilities) while improving debuggability and scalability, and it folds neatly into existing Rust/LLVM toolchains with open-source availability for reproducibility and extension to other sanitizers.

Abstract

Unsafe Rust code is necessary for interoperability with C/C++ libraries and implementing low-level data structures, but it can cause memory safety violations in otherwise memory-safe Rust programs. Sanitizers can catch such memory errors at runtime, but introduce many unnecessary checks even for memory accesses guaranteed safe by the Rust type system. We introduce SafeFFI, a system for optimizing memory safety instrumentation in Rust binaries such that checks occur at the boundary between unsafe and safe code, handing over the enforcement of memory safety from the sanitizer to the Rust type system. Unlike previous approaches, our design avoids expensive whole-program analysis and adds much less compile-time overhead (2.64x compared to over 8.83x). On a collection of popular Rust crates and known vulnerable Rust code, SafeFFI achieves superior performance compared to state-of-the-art systems, reducing sanitizer checks by up to 98%, while maintaining correctness and flagging all spatial and temporal memory safety violations.

SafeFFI: Efficient Sanitization at the Boundary Between Safe and Unsafe Code in Rust and Mixed-Language Applications

TL;DR

SafeFFI addresses memory-safety challenges in Rust and mixed-language applications by shifting sanitizer checks away from every pointer dereference to the boundary where raw pointers cast to safe pointers occur. It achieves this by annotating pointer types in MIR and propagating them through LLVM IR, hoisting checks to safe-pointer creation sites, and injecting a single dynamic boundary check (safeffi_ensure) when necessary. The approach eliminates the need for expensive whole-program points-to analyses, reducing compile-time overhead and enabling substantial runtime gains, with median improvements from 3.22x to 2.51x and up to 98% elision of sanitizer checks in evaluated crates. Empirically, SafeFFI preserves sanitizer correctness (detecting known vulnerabilities) while improving debuggability and scalability, and it folds neatly into existing Rust/LLVM toolchains with open-source availability for reproducibility and extension to other sanitizers.

Abstract

Unsafe Rust code is necessary for interoperability with C/C++ libraries and implementing low-level data structures, but it can cause memory safety violations in otherwise memory-safe Rust programs. Sanitizers can catch such memory errors at runtime, but introduce many unnecessary checks even for memory accesses guaranteed safe by the Rust type system. We introduce SafeFFI, a system for optimizing memory safety instrumentation in Rust binaries such that checks occur at the boundary between unsafe and safe code, handing over the enforcement of memory safety from the sanitizer to the Rust type system. Unlike previous approaches, our design avoids expensive whole-program analysis and adds much less compile-time overhead (2.64x compared to over 8.83x). On a collection of popular Rust crates and known vulnerable Rust code, SafeFFI achieves superior performance compared to state-of-the-art systems, reducing sanitizer checks by up to 98%, while maintaining correctness and flagging all spatial and temporal memory safety violations.
Paper Structure (41 sections, 7 figures, 1 table, 1 algorithm)

This paper contains 41 sections, 7 figures, 1 table, 1 algorithm.

Figures (7)

  • Figure 1: SafeFFI Architecture Overview. Rust and C/C++ are compiled to LLVM IR, a common intermediate representation for sanitizer instrumentation. The orange boxes depict our extensions to rustc and LLVM in this compilation workflow.
  • Figure 2: A simplified example that shows which sanitizer checks can be elided using our SafeFFI optimization
  • Figure 3: Example of a stack temporal violation that SafeFFI catches by inserting an additional sanitizer check after the pointer returned in the caller function .
  • Figure 4: The NoFree SCC Analysis is performed on all dependencies to determine possibly heap-deallocating functions.
  • Figure 5: Sanitizer checks after elision by SafeFFI and RustSan, respectively, as fractions of original checks for individual packages. For SafeFFI, checks are subdivided into remaining unsafe checks and added cast, stack and heap checks.
  • ...and 2 more figures