From 10c9683da499230afbccb2ce80d13c7373c6ef98 Mon Sep 17 00:00:00 2001 From: buj Date: Wed, 21 Feb 2024 23:37:41 +0700 Subject: [PATCH 1/9] Added better C compatibility --- src/references.rs | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/src/references.rs b/src/references.rs index b1838f0..bb09518 100644 --- a/src/references.rs +++ b/src/references.rs @@ -1,6 +1,12 @@ //! Reimplementations of [`std::ptr::null()`] and [`std::ptr::null_mut()`], with safe code only. //! Relies on [`crate::transmute`] under the hood. +use std::{ + cell::Cell, + marker::PhantomData, + ops::{Deref, DerefMut}, +}; + /// Equivalent to [`std::ptr::null()`], but returns an null reference instead. pub fn null<'a, T: 'static>() -> &'a T { crate::transmute(0usize) @@ -15,3 +21,116 @@ pub fn null_mut<'a, T: 'static>() -> &'a mut T { pub fn not_alloc<'a, T: 'static>() -> &'a mut T { null_mut() } + +/// Easily dereferencable raw pointer. Can be freely moved or copied. Do you really +/// desire to have such power? If so, do as you wish. You've been warned. +/// +/// `Ref` is guaranteed to be the same size as `usize` +#[derive(Copy, PartialEq, Eq, PartialOrd, Ord)] +#[repr(C)] +pub struct Ref(usize, PhantomData>) +where + T: Sized; +impl Clone for Ref { + fn clone(&self) -> Self { + Self(self.0, PhantomData) + } +} +impl Ref { + pub fn addr(&self) -> usize { + self.0 + } + + pub fn as_ptr(&self) -> *const T { + crate::transmute(self.0) + } + + pub fn as_ptr_mut(&mut self) -> *mut T { + crate::transmute(self.0) + } + + pub fn into_box(&self) -> Box { + crate::transmute(self.0) + } +} +impl Ref> { + pub fn flatten(self) -> Ref { + self.deref().clone() + } +} +impl AsRef for Ref { + fn as_ref(&self) -> &T { + crate::transmute(self.0) + } +} +impl AsMut for Ref { + fn as_mut(&mut self) -> &mut T { + crate::transmute(self.0) + } +} +impl Deref for Ref { + type Target = T; + + fn deref(&self) -> &Self::Target { + crate::transmute(self.0) + } +} +impl DerefMut for Ref { + fn deref_mut(&mut self) -> &mut Self::Target { + crate::transmute(self.0) + } +} +impl From for Ref { + fn from(value: T) -> Self { + new(value) + } +} + +/// Brinding https://rust-lang.github.io/rfcs/0809-box-and-in-for-stdlib.html back with +/// better C emulation. +/// +/// `Ref` is guaranteed to be the size of a `usize` for all `Sized` types. For non-`Sized` +/// types we have no current support anyway. +pub fn new(o: T) -> Ref +where + T: Sized, +{ + let boxx = Box::new(o); + crate::transmute(boxx) +} + +/// Accompaning `free` function for unnewing your `new` +/// +/// Memory under passed reference will be freed. Upon freeing, using the same `Ref` +/// again or calling `free` on it is Undefined Behavior. +pub fn free(reff: Ref) +where + T: Sized, +{ + let boxx: Box = crate::transmute(reff); + drop(boxx); // whoopsie +} + +#[cfg(test)] +mod tests { + use super::Ref; + + #[test] + fn crossref_works() { + let reff = Ref::from(3); + #[allow(clippy::clone_on_copy)] + let other = reff.clone(); + + assert_eq!(reff.addr(), other.addr()); + } + + #[test] + fn fearless_concurrency() { + let reff = Ref::from(0); + for _ in 0..10 { + let mut reff = reff; + std::thread::spawn(move || *reff += 1); + } + assert!(*reff <= 10); // The easiest RNG you'll even see + } +} From 2a8f6171aa031dd1fe39aff853e40cc4dd047212 Mon Sep 17 00:00:00 2001 From: buj Date: Wed, 21 Feb 2024 23:40:35 +0700 Subject: [PATCH 2/9] Enabling self-advertisement --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bc47c8f..0c5e95d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cve-rs" description = "Blazingly fast memory vulnerabilities, written in 100% safe Rust." -authors = ["Speykious", "BrightShard", "Creative0708"] +authors = ["Speykious", "BrightShard", "Creative0708", "buj"] version = "0.5.0" edition = "2021" license-file = "LICENSE" From e6ef359fad11004a649ad1a33562f9a6a4e19fc2 Mon Sep 17 00:00:00 2001 From: buj Date: Wed, 21 Feb 2024 23:42:34 +0700 Subject: [PATCH 3/9] Added Ref to root level export --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 522507c..5b1fcea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ pub use segfault::segfault; pub use transmute::transmute; pub use use_after_free::use_after_free; -pub use references::{null, null_mut}; +pub use references::{null, null_mut, Ref}; /// Construct a [`String`] from a pointer, capacity and length, in a completely safe manner. /// From 47e98c3ce0aaa6ef6a88879fb4292d16db9c3511 Mon Sep 17 00:00:00 2001 From: buj Date: Wed, 21 Feb 2024 23:44:35 +0700 Subject: [PATCH 4/9] Prelude and new/free default export --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 5b1fcea..989ac00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ pub use segfault::segfault; pub use transmute::transmute; pub use use_after_free::use_after_free; -pub use references::{null, null_mut, Ref}; +pub use references::{free, new, null, null_mut, Ref}; /// Construct a [`String`] from a pointer, capacity and length, in a completely safe manner. /// @@ -119,3 +119,7 @@ mod tests { crate::download_more_ram::(); } } + +pub mod prelude { + pub use super::{free, new}; +} From 3665a5c71a4cb5f26b602810a899b11b5f880a3c Mon Sep 17 00:00:00 2001 From: buj Date: Thu, 22 Feb 2024 02:25:19 +0700 Subject: [PATCH 5/9] Fixed From impl --- src/references.rs | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/references.rs b/src/references.rs index bb09518..80691a0 100644 --- a/src/references.rs +++ b/src/references.rs @@ -2,9 +2,10 @@ //! Relies on [`crate::transmute`] under the hood. use std::{ - cell::Cell, marker::PhantomData, ops::{Deref, DerefMut}, + rc::Rc, + sync::Arc, }; /// Equivalent to [`std::ptr::null()`], but returns an null reference instead. @@ -28,7 +29,7 @@ pub fn not_alloc<'a, T: 'static>() -> &'a mut T { /// `Ref` is guaranteed to be the same size as `usize` #[derive(Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(C)] -pub struct Ref(usize, PhantomData>) +pub struct Ref(usize, PhantomData>) where T: Sized; impl Clone for Ref { @@ -49,6 +50,14 @@ impl Ref { crate::transmute(self.0) } + pub fn from_ptr(ptr: *const T) -> Self { + Self(ptr as usize, PhantomData) + } + + pub fn from_ptr_mut(ptr: *mut T) -> Self { + Self(ptr as usize, PhantomData) + } + pub fn into_box(&self) -> Box { crate::transmute(self.0) } @@ -80,9 +89,24 @@ impl DerefMut for Ref { crate::transmute(self.0) } } -impl From for Ref { - fn from(value: T) -> Self { - new(value) +impl From<&T> for Ref { + fn from(value: &T) -> Self { + crate::transmute(value) + } +} +impl From> for Ref { + fn from(value: Box) -> Self { + crate::transmute(value) + } +} +impl From> for Ref { + fn from(value: Rc) -> Self { + crate::transmute(value) + } +} +impl From> for Ref { + fn from(value: Arc) -> Self { + crate::transmute(value) } } @@ -113,11 +137,11 @@ where #[cfg(test)] mod tests { - use super::Ref; + use super::new; #[test] fn crossref_works() { - let reff = Ref::from(3); + let reff = new(3); #[allow(clippy::clone_on_copy)] let other = reff.clone(); @@ -126,7 +150,7 @@ mod tests { #[test] fn fearless_concurrency() { - let reff = Ref::from(0); + let reff = new(0); for _ in 0..10 { let mut reff = reff; std::thread::spawn(move || *reff += 1); From dacbe9017688966e6439069e902c96505d54732f Mon Sep 17 00:00:00 2001 From: buj Date: Thu, 22 Feb 2024 02:51:49 +0700 Subject: [PATCH 6/9] Methods I think --- src/references.rs | 47 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/references.rs b/src/references.rs index 80691a0..fc5e402 100644 --- a/src/references.rs +++ b/src/references.rs @@ -38,6 +38,15 @@ impl Clone for Ref { } } impl Ref { + pub fn new(value: T) -> Self { + Self(Box::leak(Box::new(value)) as *const _ as usize, PhantomData) + } + + pub fn free(self) { + let boxx: Box = crate::transmute(self); + drop(boxx); + } + pub fn addr(&self) -> usize { self.0 } @@ -96,17 +105,19 @@ impl From<&T> for Ref { } impl From> for Ref { fn from(value: Box) -> Self { - crate::transmute(value) + let reff = crate::transmute(&*value); + std::mem::forget(value); + reff } } impl From> for Ref { fn from(value: Rc) -> Self { - crate::transmute(value) + crate::transmute(&*value) } } impl From> for Ref { fn from(value: Arc) -> Self { - crate::transmute(value) + crate::transmute(&*value) } } @@ -115,12 +126,11 @@ impl From> for Ref { /// /// `Ref` is guaranteed to be the size of a `usize` for all `Sized` types. For non-`Sized` /// types we have no current support anyway. -pub fn new(o: T) -> Ref +pub fn new(value: T) -> Ref where T: Sized, { - let boxx = Box::new(o); - crate::transmute(boxx) + Ref::new(value) } /// Accompaning `free` function for unnewing your `new` @@ -131,13 +141,14 @@ pub fn free(reff: Ref) where T: Sized, { - let boxx: Box = crate::transmute(reff); - drop(boxx); // whoopsie + reff.free() } #[cfg(test)] mod tests { - use super::new; + use std::sync::Arc; + + use super::{new, Ref}; #[test] fn crossref_works() { @@ -157,4 +168,22 @@ mod tests { } assert!(*reff <= 10); // The easiest RNG you'll even see } + + #[test] + fn from_box() { + let boxx = Box::new(3); + let addr = boxx.as_ref() as *const i32 as usize; + let reff: Ref = boxx.into(); + + assert_eq!(reff.addr(), addr); + } + + #[test] + fn arc_doesnt_break() { + let mut arc1 = Arc::new(123); + let arc2 = arc1.clone(); + let arc2: Ref = arc2.into(); + assert!(Arc::get_mut(&mut arc1).is_some()); + let _ = arc2; + } } From 9b217ba8e34b6289d3a92661b03bd95a9a250d39 Mon Sep 17 00:00:00 2001 From: buj Date: Thu, 22 Feb 2024 20:55:56 +0700 Subject: [PATCH 7/9] Better C/C++ inclusivity + trait bounds --- src/lib.rs | 4 ++-- src/references.rs | 60 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7002e5b..5662d8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ pub use segfault::segfault; pub use transmute::transmute; pub use use_after_free::use_after_free; -pub use references::{free, new, not_alloc, null, null_mut, Ref}; +pub use references::{delete, free, malloc, new, not_alloc, null, null_mut, Ref}; /// Construct a [`String`] from a pointer, capacity and length, in a completely safe manner. /// @@ -121,5 +121,5 @@ mod tests { } pub mod prelude { - pub use super::{free, new}; + pub use super::{delete, free, malloc, new}; } diff --git a/src/references.rs b/src/references.rs index 4a9ee77..e2c0e9c 100644 --- a/src/references.rs +++ b/src/references.rs @@ -49,6 +49,10 @@ impl Ref { drop(boxx); } + pub fn cast(self) -> Ref { + Ref(self.0, PhantomData) + } + pub fn addr(&self) -> usize { self.0 } @@ -60,18 +64,6 @@ impl Ref { pub fn as_ptr_mut(&mut self) -> *mut T { crate::transmute(self.0) } - - pub fn from_ptr(ptr: *const T) -> Self { - Self(ptr as usize, PhantomData) - } - - pub fn from_ptr_mut(ptr: *mut T) -> Self { - Self(ptr as usize, PhantomData) - } - - pub fn into_box(&self) -> Box { - crate::transmute(self.0) - } } impl Ref> { pub fn flatten(self) -> Ref { @@ -122,6 +114,28 @@ impl From> for Ref { crate::transmute(&*value) } } +impl From<*const T> for Ref { + fn from(value: *const T) -> Self { + Self(value as usize, PhantomData) + } +} +impl From<*mut T> for Ref { + fn from(value: *mut T) -> Self { + Self(value as usize, PhantomData) + } +} + +/// Brinding https://rust-lang.github.io/rfcs/0809-box-and-in-for-stdlib.html back with +/// better C emulation. +/// +/// `Ref` is guaranteed to be the size of a `usize` for all `Sized` types. For non-`Sized` +/// types we have no current support anyway. +pub fn malloc(value: T) -> Ref +where + T: Sized, +{ + Ref::new(value) +} /// Brinding https://rust-lang.github.io/rfcs/0809-box-and-in-for-stdlib.html back with /// better C emulation. @@ -135,7 +149,18 @@ where Ref::new(value) } -/// Accompaning `free` function for unnewing your `new` +/// Accompaning `delete` function for unnewing your `new` +/// +/// Memory under passed reference will be freed. Upon freeing, using the same `Ref` +/// again or calling `delete` on it is Undefined Behavior. +pub fn delete(reff: Ref) +where + T: Sized, +{ + reff.free() +} + +/// Accompaning `free` function for unmalloccing your `malloc` /// /// Memory under passed reference will be freed. Upon freeing, using the same `Ref` /// again or calling `free` on it is Undefined Behavior. @@ -188,4 +213,13 @@ mod tests { assert!(Arc::get_mut(&mut arc1).is_some()); let _ = arc2; } + + #[test] + fn ptr_into_ref() { + let val = 512; + let ptr = &val as *const i32; + let mut rf: Ref = ptr.into(); + *rf = 69420; + assert_eq!(*rf, 69420); + } } From eab512933f87714469aff121b4f3cb30c070bd60 Mon Sep 17 00:00:00 2001 From: buj Date: Thu, 22 Feb 2024 21:33:55 +0700 Subject: [PATCH 8/9] extern "C" yes_mangle --- src/references.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/references.rs b/src/references.rs index e2c0e9c..ce84e8c 100644 --- a/src/references.rs +++ b/src/references.rs @@ -130,7 +130,7 @@ impl From<*mut T> for Ref { /// /// `Ref` is guaranteed to be the size of a `usize` for all `Sized` types. For non-`Sized` /// types we have no current support anyway. -pub fn malloc(value: T) -> Ref +pub extern "C" fn malloc(value: T) -> Ref where T: Sized, { @@ -142,7 +142,7 @@ where /// /// `Ref` is guaranteed to be the size of a `usize` for all `Sized` types. For non-`Sized` /// types we have no current support anyway. -pub fn new(value: T) -> Ref +pub extern "C" fn new(value: T) -> Ref where T: Sized, { @@ -153,7 +153,7 @@ where /// /// Memory under passed reference will be freed. Upon freeing, using the same `Ref` /// again or calling `delete` on it is Undefined Behavior. -pub fn delete(reff: Ref) +pub extern "C" fn delete(reff: Ref) where T: Sized, { @@ -164,7 +164,7 @@ where /// /// Memory under passed reference will be freed. Upon freeing, using the same `Ref` /// again or calling `free` on it is Undefined Behavior. -pub fn free(reff: Ref) +pub extern "C" fn free(reff: Ref) where T: Sized, { From 50438649d84f19d2ee9dcdaafb1733defec86d8b Mon Sep 17 00:00:00 2001 From: Buj <42136194+5GameMaker@users.noreply.github.com> Date: Sat, 24 Feb 2024 22:18:43 +0700 Subject: [PATCH 9/9] Loosened trait bounds Dropping `Sync` requirement for a `Ref` to be `Send`+`Sync` --- src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/references.rs b/src/references.rs index 053e02f..d0dc57b 100644 --- a/src/references.rs +++ b/src/references.rs @@ -31,7 +31,7 @@ pub fn not_alloc<'a, T: 'static>() -> &'a mut T { /// `Ref` is guaranteed to be the same size as `usize` #[derive(Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(C)] -pub struct Ref(usize, PhantomData>) +pub struct Ref(usize, PhantomData>) where T: Sized; impl Clone for Ref {