mirror of
https://github.com/rustsec/advisory-db.git
synced 2026-07-16 00:12:29 -04:00
Add thin-vec GHSA-xphw-cqx3-667j
This commit is contained in:
119
crates/thin-vec/RUSTSEC-0000-0000.md
Normal file
119
crates/thin-vec/RUSTSEC-0000-0000.md
Normal file
@@ -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<usize>, &'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<dyn Trait> 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.
|
||||
Reference in New Issue
Block a user