Skip to content

Report a Soundness/Security Issue in SmallVec::leak()

High
mbrubeck published GHSA-5h7v-3586-wm8c Nov 16, 2025

Package

cargo smallvec (Rust)

Affected versions

none

Patched versions

2.0.0-alpha.12

Description

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)

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Changed
Confidentiality
Low
Integrity
Low
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:H

CVE ID

No known CVE

Weaknesses

Improper Control of a Resource Through its Lifetime

The product does not maintain or incorrectly maintains control over a resource throughout its lifetime of creation, use, and release. Learn more on MITRE.

Out-of-bounds Write

The product writes data past the end, or before the beginning, of the intended buffer. Learn more on MITRE.

Expired Pointer Dereference

The product dereferences a pointer that contains a location for memory that was previously valid, but is no longer valid. Learn more on MITRE.

Credits