-
Notifications
You must be signed in to change notification settings - Fork 3
Closed
Description
Hello 🦀 ,
while scanning crates.io, we (Rust group @sslab-gatech) have noticed a soundness/memory safety issue in this crate which allows safe Rust code to trigger undefined behavior.
Issue
It is possible to make ARefss
contain a non-Send
/ non-Sync
object,
since there is no Send + Sync
bound on V
in the ARefss::map()
function.
pub fn map<V: ?Sized, F: FnOnce(&U) -> &V>(self, f: F) -> ARefss<'a, V>
Proof of Concept
I wrote a short program that can trigger undefined behavior in safe Rust using this crate.
Test environment
- OS: Windows
- crate version :
reffers-0.6.0
- compiled with
rustc 1.47.0 (18bf6b4f0 2020-10-07)
- program exhibits a segmentation fault when compiled and run in
release
mode.
Error message from the program
error: process didn't exit successfully: `target\release\examples\reffers.exe` (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
Segmentation fault
use std::cell::Cell;
use std::sync::Arc;
use reffers::aref::ARefss;
#[derive(Debug, Clone, Copy)]
enum RefOrInt<'a> {
Ref(&'a u64),
Int(u64),
}
static X: u64 = 0;
fn main() {
let arc_0 = Arc::new(ARefss::new(Arc::new(0)).map(|_| {
// New item is totally unrelated to the previously stored item.
// New item is allowed to be !Sync, !Send.
Box::leak(Box::new(Cell::new(RefOrInt::Ref(&X))))
// Box::leak(Box::new(std::rc::Rc::new(0)))
}));
let arc_child = Arc::clone(&arc_0);
std::thread::spawn(move || {
let arc_child = arc_child;
let smuggled_cell = arc_child.as_ref();
loop {
smuggled_cell.set(RefOrInt::Int(0xdeadbeef));
smuggled_cell.set(RefOrInt::Ref(&X));
}
});
loop {
if let RefOrInt::Ref(addr) = arc_0.get() {
if addr as *const _ as usize == 0xdeadbeef {
// Due to the data race, obtaining Ref(0xdeadbeef) is possible
println!("Pointer is now: {:p}", addr);
println!("Dereferencing addr will now segfault: {}", *addr);
}
}
}
}
Thank you for checking out this issue 🦀
Metadata
Metadata
Assignees
Labels
No labels