-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
Hello,
We are @purseclab, and we are fuzzing Rust crates to identify memory violation bugs. Over the past few months, we discovered four distinct double-free vulnerabilities in slice-deque-0.3.0
, which we reported on the original crate's (now unmaintained) GitHub repository:
- Double Free caused by extend_from_slice (Double Free in SliceDeque::extend_from_slice gnzlbg/slice_deque#99)
- Double Free caused by shrink_to_fit (Double Free caused by SliceDeque::shrink_to_fit gnzlbg/slice_deque#100)
- Double Free caused by insert (Double Free due to Ownership Duplication gnzlbg/slice_deque#97)
- Double Free caused by into_iter (Double Free by Using Only Safe Rust gnzlbg/slice_deque#96)
We recently became aware that slice-ring-buffer
is an actively maintained fork of slice-deque
with a focus on addressing security issues. For that reason, we are sharing these findings with you, as the same vulnerabilities are still present in the latest version: slice-ring-buffer-0.3.4
Following, we provide a PoC that can trigger all 4 memory safety bugs.
PoC:
use slice_ring_buffer::*;
use std::io;
#[derive(Debug, Clone)]
struct StructA(String);
impl Drop for StructA {
fn drop(&mut self) {
println!("Dropping StructA with data at: {:?}", self.0.as_ptr());
}
}
fn main() {
println!("Select a bug:");
println!("1 - DF due to extend_from_slice");
println!("2 - DF due to shrink_to_fit");
println!("3 - DF due to insert");
println!("4 - DF due to into_iter");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read input");
match input.trim() {
"1" => {
let mut dq1 = SliceRingBuffer::new();
dq1.push_back(StructA(String::from("AAAA")));
println!("pushed");
dq1.pop_back();
println!("popped");
let other = &[StructA(String::from("BBBB"))];
dq1.extend_from_slice(other);
println!("extended: {:?}", dq1);
}
"2" => {
let mut dq1 = SliceRingBuffer::new();
dq1.push_back(StructA(String::from("AAAA")));
dq1.reserve_exact(170);
dq1.shrink_to_fit();
println!("After shrink: {:?}", dq1.capacity());
}
"3" => {
let mut vec = vec![
String::from("0"), String::from("1"), String::from("2"),
String::from("3"), String::from("4"), String::from("5"),
];
let mut slice_deq = SliceRingBuffer::from(&vec[..]);
println!("slice_deq_old = {:#?}", slice_deq);
slice_deq.insert(3, String::from("X"));
println!("slice_deq_new = {:#?}", slice_deq);
}
"4" => {
let slice_deque = slice_ring_buffer::from_elem(String::from("DF"), 10);
let iter1 = SliceRingBuffer::into_iter(slice_deque);
let iter2 = &iter1.clone();
}
_ => {
println!("Invalid option. Please select a number between 1 and 4.");
}
}
}
How to Build and Run the PoC:
RUSTFLAGS="-Zsanitizer=address" cargo run
Details:
- Compiler Version: rustc 1.81.0-nightly (8337ba918 2024-06-12)
- Library Version: slice-ring-buffer-0.3.4
- OS: Ubuntu 20.04.6 LTS
Metadata
Metadata
Assignees
Labels
No labels