-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Hello,
We are @purseclab, and we are fuzzing Rust crates to identify memory violation bugs. While analyzing this crate, we discovered that SliceVec::split_off
can duplicate ownership of elements of type T
, potentially leading to a double-free memory violation when the generic type implements Drop
.
The PoC below causes a double-free memory violation.
PoC:
#![forbid(unsafe_code)]
use arenavec::*;
#[derive(Debug)]
struct CustomType0(String);
impl Drop for CustomType0{
fn drop(&mut self){
println!("Attempting to free: {:?}", self.0.as_ptr());
}
}
fn main() {
let arena0 = arenavec::rc::Arena::init_capacity(arenavec::common::ArenaBacking::MemoryMap, 300).unwrap();
let handle0 = arena0.inner();
let mut sv1 = arenavec::common::SliceVec::with_capacity(handle0.clone(), 4);
sv1.push(CustomType0(String::from("BUG")));
sv1.push(CustomType0(String::from("BUG")));
let _ = sv1.split_off(0);
println!("exiting...")
}
Bug Description:
The method SliceVec::split_off
in lines 407-412 copies the elements from the self
object to the ret
object.
Lines 400 to 415 in f931efb
pub fn split_off(&mut self, at: usize) -> Self | |
where | |
H: Clone, | |
{ | |
let mut ret = Self::with_capacity(self.slice.handle.clone(), self.slice.len - at); | |
ret.slice.len = self.slice.len - at; | |
unsafe { | |
ptr::copy_nonoverlapping( | |
self.slice.ptr.as_ptr().add(at), | |
ret.slice.ptr.as_ptr(), | |
ret.len()); | |
} | |
ret | |
} |
If these elements are heap-allocated and implement the Drop
trait, this copy duplicates their ownership. In the specific case where at == 0
, split_off
creates a new SliceVec
(ret
) with the same length and elements as self
.
In the provided PoC, when split_off
returns, ret
is dropped, and its elements are deallocated. Later, when the original SliceVec
(sv1
) is dropped at the end of main
, it attempts to deallocate the same elements again. This results in a double-free violation.
Output:
Attempting to free: 0x502000000010
Attempting to free: 0x502000000030
exiting...
Attempting to free: 0x502000000010
=================================================================
==4170119==ERROR: AddressSanitizer: attempting double-free on 0x502000000010 in thread T0:
#0 0x55a232e8f116 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xca116) (BuildId: 69e067aa5f1d3584)
#1 0x55a232eba556 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf5556) (BuildId: 69e067aa5f1d3584)
#2 0x55a232ebe55a (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf955a) (BuildId: 69e067aa5f1d3584)
#3 0x55a232ebdec9 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8ec9) (BuildId: 69e067aa5f1d3584)
#4 0x55a232ebde9a (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8e9a) (BuildId: 69e067aa5f1d3584)
#5 0x55a232ebde49 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8e49) (BuildId: 69e067aa5f1d3584)
#6 0x55a232ebdf0a (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8f0a) (BuildId: 69e067aa5f1d3584)
#7 0x55a232ebdf89 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8f89) (BuildId: 69e067aa5f1d3584)
#8 0x55a232ebe8aa (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf98aa) (BuildId: 69e067aa5f1d3584)
#9 0x55a232ebdd82 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8d82) (BuildId: 69e067aa5f1d3584)
#10 0x55a232ebddd9 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8dd9) (BuildId: 69e067aa5f1d3584)
#11 0x55a232ebda4e (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8a4e) (BuildId: 69e067aa5f1d3584)
#12 0x55a232ebdd6a (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8d6a) (BuildId: 69e067aa5f1d3584)
#13 0x55a232eba81d (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf581d) (BuildId: 69e067aa5f1d3584)
#14 0x55a232ebf074 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xfa074) (BuildId: 69e067aa5f1d3584)
#15 0x55a232ed8381 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0x113381) (BuildId: 69e067aa5f1d3584)
#16 0x55a232ebef18 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf9f18) (BuildId: 69e067aa5f1d3584)
#17 0x55a232ebdb9d (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8b9d) (BuildId: 69e067aa5f1d3584)
#18 0x7fe0d2967d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)
#19 0x7fe0d2967e3f (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)
#20 0x55a232e0bfe4 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0x46fe4) (BuildId: 69e067aa5f1d3584)
0x502000000010 is located 0 bytes inside of 3-byte region [0x502000000010,0x502000000013)
freed by thread T0 here:
#0 0x55a232e8f116 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xca116) (BuildId: 69e067aa5f1d3584)
#1 0x55a232eba556 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf5556) (BuildId: 69e067aa5f1d3584)
#2 0x55a232ebe55a (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf955a) (BuildId: 69e067aa5f1d3584)
#3 0x55a232ebdec9 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8ec9) (BuildId: 69e067aa5f1d3584)
#4 0x55a232ebdd82 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8d82) (BuildId: 69e067aa5f1d3584)
#5 0x55a232ebdd6a (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8d6a) (BuildId: 69e067aa5f1d3584)
#6 0x55a232ed8381 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0x113381) (BuildId: 69e067aa5f1d3584)
#7 0x55a232ebef18 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf9f18) (BuildId: 69e067aa5f1d3584)
#8 0x55a232ebdb9d (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8b9d) (BuildId: 69e067aa5f1d3584)
previously allocated by thread T0 here:
#0 0x55a232e8f3af (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xca3af) (BuildId: 69e067aa5f1d3584)
#1 0x55a232eb9fbf (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf4fbf) (BuildId: 69e067aa5f1d3584)
#2 0x55a232eba250 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf5250) (BuildId: 69e067aa5f1d3584)
#3 0x55a232eba5b8 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf55b8) (BuildId: 69e067aa5f1d3584)
#4 0x55a232ebfc8c (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xfac8c) (BuildId: 69e067aa5f1d3584)
#5 0x55a232eba784 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf5784) (BuildId: 69e067aa5f1d3584)
#6 0x55a232ebd8fa (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf88fa) (BuildId: 69e067aa5f1d3584)
#7 0x55a232ebdd6a (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8d6a) (BuildId: 69e067aa5f1d3584)
#8 0x55a232ed8381 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0x113381) (BuildId: 69e067aa5f1d3584)
#9 0x55a232ebef18 (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf9f18) (BuildId: 69e067aa5f1d3584)
#10 0x55a232ebdb9d (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xf8b9d) (BuildId: 69e067aa5f1d3584)
SUMMARY: AddressSanitizer: double-free (/home/user/arenavec_split_off_df/target/debug/arenavec_split_off_df+0xca116) (BuildId: 69e067aa5f1d3584)
==4170119==ABORTING
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: arenavec-0.1.1
- OS: Ubuntu 20.04.6 LTS