cve-rs 0.7.0

Blazingly fast memory vulnerabilities, written in 100% safe Rust.
Documentation
//! So far, all our bugs are implemented using a single soundness hole in the Rust compiler.
//!
//! The explanation is detailed in the [`lifetime_expansion`] module.

#![deny(unsafe_code)]

// The actual exploit
pub mod lifetime_expansion;

// The bugs we created with the exploit
pub mod buffer_overflow;
pub mod references;
pub mod segfault;
pub mod transmute;
pub mod use_after_free;

pub use lifetime_expansion::*;

pub use buffer_overflow::buffer_overflow;
pub use segfault::segfault;
pub use transmute::transmute;
pub use use_after_free::use_after_free;

pub use references::{not_alloc, null, null_mut};

/// Construct a [`String`] from a pointer, capacity and length, in a completely safe manner.
///
/// [`String`] is a `Vec<u8>` which is a `(RawVec, usize)` which is a `((Unique, usize), usize)`.
///
/// Rust explicitly says that structs are not guaranteed to have members in order,
/// so instead we determine that order at runtime.
///
/// # Safety
///
/// This function is 100% memory-safe.
///
/// Nevetheless, remember to use [`std::mem::forget`] to deallocate the fake [`String`], otherwise Rust
/// will think the pointer has been allocated by the global allocator and free it the wrong way.
///
/// > As they say: *Trust, but Verify.*
#[inline(always)]
pub fn construct_fake_string(ptr: *mut u8, cap: usize, len: usize) -> String {
	let sentinel_string = crate::transmute::<_, String>([0usize, 1usize, 2usize]);

	let mut actual_buf = [0usize; 3];
	actual_buf[sentinel_string.as_ptr() as usize] = ptr as usize;
	actual_buf[sentinel_string.capacity()] = cap;
	actual_buf[sentinel_string.len()] = len;

	std::mem::forget(sentinel_string);

	crate::transmute::<_, String>(actual_buf)
}

#[cfg(any(feature = "give-up", feature = "step-on-lego"))]
fn seed() -> u64 {
	use std::time::SystemTime;

	let seed = SystemTime::now()
		.duration_since(SystemTime::UNIX_EPOCH)
		.unwrap();

	seed.as_secs()
}

/// It can be fatal if you step hard enough.
#[cfg(any(feature = "give-up", feature = "step-on-lego"))]
pub fn step_on_lego() -> u32 {
	let mut rng = oorandom::Rand64::new(seed() as u128);

	let lego = crate::transmute::<usize, &'static u32>(rng.rand_u64() as usize);

	*lego
}

/// Good for job security.
#[cfg(any(feature = "give-up", feature = "step-on-lego"))]
pub fn give_up<T: 'static>() -> Box<T> {
	let size = std::mem::size_of::<T>();

	let mut v = Vec::with_capacity(size);

	let mut rng = oorandom::Rand32::new(seed());

	for _ in 0..size {
		v.push((rng.rand_u32() & u32::from(u8::MAX)) as u8);
	}

	crate::transmute(v.into_boxed_slice())
}

/// Download more RAM from the internet.
///
/// Cannot control the amount we're gonna get. It's hard to fetch these days.
#[cfg(feature = "download-more-ram")]
pub fn download_more_ram<'a, T: 'static>() -> &'a mut [T] {
	const URL: &str =
		"http://www.randomnumberapi.com/api/v1.0/randomnumber?min=1073741824&max=34359738368&count=2";

	let resp = ureq::get(URL).call().unwrap().into_string().unwrap();

	let (ptr, len) = resp[1..(resp.len() - 2)].split_once(',').unwrap();

	let downloaded_ram = {
		let sentinel_slice = crate::transmute::<_, &[u8]>([0usize, 1usize]);

		let ptr = ptr.parse::<usize>().unwrap();
		let len = len.parse::<usize>().unwrap();

		let mut actual_buf = [0usize; 2];
		actual_buf[sentinel_slice.as_ptr() as usize] = ptr;
		actual_buf[sentinel_slice.len()] = len;

		crate::transmute::<_, Box<[T]>>(actual_buf)
	};

	Box::leak(downloaded_ram)
}

#[cfg(test)]
mod tests {
	#[test]
	#[cfg(feature = "give-up")]
	fn can_give_up() {
		let job_security = crate::give_up::<u64>();
		Box::leak(job_security);
	}

	#[test]
	#[cfg(feature = "download-more-ram")]
	fn can_download_more_ram() {
		crate::download_more_ram::<u64>();
	}
}