Summary
The smallvec crate's SmallVec::leak() method fails to check whether its contents are stored on the stack (inline buffer) or the heap.
When called on a stack-allocated SmallVec, the method returns a 'static mutable reference to the freed stack memory, resulting in Undefined Behavior (UB) via Stack Use-After-Return (UAR).
This vulnerability was present in the v2 branch of the smallvec GitHub repository starting with commit ad9f438. The vulnerability was not present in any published version of this crate.
Details
The core vulnerability lies in the implementation of SmallVec::leak() in lib.rs:
// lib.rs (Line 1684 - 1687)
pub fn leak<'a>(self) -> &'a mut [T] {
let mut me = ManuallyDrop::new(self);
unsafe { core::slice::from_raw_parts_mut(me.as_mut_ptr(), me.len()) }
}
- The function does not check whether
self has spilled onto the heap using self.spilled() or self.is_inline().
- When a
SmallVec stores data within its inline capacity (on the stack), the pointer returned by as_mut_ptr() points to the stack frame.
- After
leak() returns, the stack frame is popped and invalidated, leaving a dangling pointer.
- The caller receives a
'static mut [T] that points to invalidated stack memory — any read or write operation constitutes Undefined Behavior (UB).
- The combination of ManuallyDrop and lack of spill check allows returning a reference to transient stack data that is no longer valid once the function returns.
PoC
Tested on:
The following Rust code reliably reproduces the UAR condition:
#![forbid(unsafe_code)]
use smallvec::SmallVec;
// Function that leaks stack memory
fn inline_bad_static_slice() -> &'static mut [i32] {
let v: SmallVec<i32, 256> = SmallVec::from_buf([0xAAAA; 256]);
return v.leak();
}
fn main() {
let s = inline_bad_static_slice(); // UAR state begins
println!("Writing to the instance s");
s[0] = s[0].wrapping_add(3);
let _final_s0_value = s[0];
println!("It may induce `Illegal Instruction` in release mode");
if _final_s0_value == 0xAAAD {
eprintln!("Write successful.");
} else {
eprintln!("Write failed: {}", _final_s0_value);
}
}
Expected Output (ASAN):
$ RUSTFLAGS="-Z sanitizer=address" cargo +nightly run
Writing to the instance s
=================================================================
==107354==ERROR: AddressSanitizer: stack-use-after-return on address 0x73b871e00028 at pc 0x5756d0f277f8 bp 0x7fffcef495b0 sp 0x7fffcef495a8
READ of size 4 at 0x73b871e00028 thread T0...
Expected Output (Release):
$ cargo run --release
Writing to the instance s
It may induce `Illegal Instruction` in release mode
Illegal instruction (core dumped)
indicating corruption of critical stack data.
Impact
Type: Stack-based Use-After-Return (UAR)
Writing to freed stack memory can:
- Overwrite return addresses or stack variables.
- Lead to Denial-of-Service (DoS) or Potential Control-flow Disruption.
Author: Sungjin Kim (ksj1230)
Summary
The
smallveccrate'sSmallVec::leak()method fails to check whether its contents are stored on the stack (inline buffer) or the heap.When called on a stack-allocated
SmallVec, the method returns a'staticmutable reference to the freed stack memory, resulting in Undefined Behavior (UB) via Stack Use-After-Return (UAR).This vulnerability was present in the
v2branch of thesmallvecGitHub repository starting with commit ad9f438. The vulnerability was not present in any published version of this crate.Details
The core vulnerability lies in the implementation of SmallVec::leak() in lib.rs:
selfhas spilled onto the heap usingself.spilled()orself.is_inline().SmallVecstores data within its inline capacity (on the stack), the pointer returned byas_mut_ptr()points to the stack frame.leak()returns, the stack frame is popped and invalidated, leaving a dangling pointer.'static mut [T]that points to invalidated stack memory — any read or write operation constitutes Undefined Behavior (UB).PoC
Tested on:
The following Rust code reliably reproduces the UAR condition:
Expected Output (ASAN):
$ RUSTFLAGS="-Z sanitizer=address" cargo +nightly run Writing to the instance s ================================================================= ==107354==ERROR: AddressSanitizer: stack-use-after-return on address 0x73b871e00028 at pc 0x5756d0f277f8 bp 0x7fffcef495b0 sp 0x7fffcef495a8 READ of size 4 at 0x73b871e00028 thread T0...Expected Output (Release):
indicating corruption of critical stack data.
Impact
Type: Stack-based Use-After-Return (UAR)
Writing to freed stack memory can:
Author: Sungjin Kim (ksj1230)