1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
//! A memory-safe segmentation fault, using the lifetime expansion exploit.
//!
//! We use this hole to create a 'static reference to a dropped (yes, dropped) smart
//! pointer. The smart pointer exists on the stack, but was dropped, so the reference
//! is borrowing arbitrary data on the stack. We can then fill the stack with 0s, which
//! replaces the smart pointer's address with 0, creating a null pointer in safe Rust.
//! By accessing the contents of the pointer, we force Rust to dereference the null pointer,
//! causing a segfault.
use {crate::lifetime_expansion, std::hint::black_box};
/// Returns a static reference to a dropped (yes, dropped) box.
#[inline(never)]
#[allow(clippy::borrowed_box)]
fn get_dropped_box() -> &'static Box<Box<u8>> {
let box_ = black_box(Box::new(Box::new(8)));
lifetime_expansion::expand(&box_)
}
/// Gets a reference to a dropped smart pointer, then fills the stack with 0s.
/// This overrides where the smart pointer used to be and replaces its address
/// with all 0s, creating a null pointer. We then read the data from the box,
/// which forces Rust to dereference the smart pointer, causing it to dereference
/// a null pointer.
///
/// In theory this should work with a normal box, but in practice Rust reads random
/// memory instead of segfaulting on a null pointer. We think this is due to compiler
/// optimisations.
pub fn segfault() {
println!(
"\
Source code for this file is available here: \
https://github.com/Speykious/cve-rs/blob/main/src/segfault.rs
"
);
let my_ref = get_dropped_box();
black_box([0; 1024]);
println!("{my_ref:?}");
}