mirror of
https://github.com/Noratrieb/crimes.git
synced 2026-01-14 17:15:01 +01:00
crimes
This commit is contained in:
commit
b7b4283a77
4 changed files with 140 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
.idea
|
||||
16
Cargo.lock
generated
Normal file
16
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ohno"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"sptr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sptr"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0d4365121b91e8522958da77ce29c004333daeaf0711225c4727c8c5f49941"
|
||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "ohno"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
sptr = "0.3.1"
|
||||
113
src/main.rs
Normal file
113
src/main.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// we are law abiding citizens using only the best features of the strict provenance world
|
||||
use sptr::Strict;
|
||||
// used to store provenance
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
// writing a cfged version for 32 bit is trivial, we don't care
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
compile_error!("not supported");
|
||||
|
||||
// a pointer sized buffer used to store a single pointer
|
||||
type Buf = MaybeUninit<[usize; 1]>;
|
||||
// a double pointer sized buffer used to store two pointers and rip out the center
|
||||
type DBuf = MaybeUninit<[usize; 2]>;
|
||||
|
||||
/// just a pointer, doesn't matter which one
|
||||
type Ptr = *const u8;
|
||||
|
||||
/// combines two provenances into a single pointer sized value
|
||||
unsafe fn combine(prov_a: Ptr, prov_b: Ptr) -> Buf {
|
||||
// a buffer where we write in both pointers and then read out of from center, 1/2 of each provenance
|
||||
let mut double_buf = DBuf::zeroed();
|
||||
|
||||
let ptr = double_buf.as_mut_ptr();
|
||||
|
||||
// write the a pointer to the first slot
|
||||
ptr.cast::<Ptr>().write(prov_a);
|
||||
// write the b pointer to the second slot
|
||||
ptr.cast::<Buf>().add(1).cast::<Ptr>().write(prov_b);
|
||||
|
||||
// and read out the center
|
||||
let center = ptr.cast::<u8>().add(4).cast::<Buf>().read();
|
||||
center
|
||||
}
|
||||
|
||||
/// extracts the two provenances from [`combine`]
|
||||
unsafe fn extract(buf: Buf) -> (Ptr, Ptr) {
|
||||
let mut double_buf = DBuf::zeroed();
|
||||
|
||||
// write the the pointer sized value into the center of the double buffer
|
||||
// splitting the provenances between the first and second slow
|
||||
double_buf
|
||||
.as_mut_ptr()
|
||||
.cast::<u8>()
|
||||
.add(4)
|
||||
.cast::<Buf>()
|
||||
.write(buf);
|
||||
|
||||
// a copy of the first half of the dbuf, where the second half of it contains a provenance
|
||||
let mut a_buf: Buf = double_buf.as_ptr().cast::<Buf>().read();
|
||||
// a copy of the second half of the dbuf, where the first half of it contains b provenance
|
||||
let mut b_buf: Buf = double_buf.as_ptr().cast::<Buf>().add(1).read();
|
||||
|
||||
// the pointer to the dbuf
|
||||
let ptr = double_buf.as_ptr();
|
||||
|
||||
// copy the 4 a provenance bytes from the dbuf into the empty space in the a_buf
|
||||
// this way a_buf now contains 8 a provenance bytes
|
||||
std::ptr::copy_nonoverlapping(
|
||||
ptr.cast::<MaybeUninit<u8>>().add(4),
|
||||
a_buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
|
||||
4,
|
||||
);
|
||||
|
||||
// repeat the same thing for the b provenance
|
||||
std::ptr::copy_nonoverlapping(
|
||||
ptr.cast::<MaybeUninit<u8>>().add(8),
|
||||
b_buf.as_mut_ptr().cast::<MaybeUninit<u8>>().add(4),
|
||||
4,
|
||||
);
|
||||
|
||||
// both buffers are now filled with fancy provenance bytes, read the pointers out and return them
|
||||
let a = a_buf.as_ptr().cast::<Ptr>().read();
|
||||
let b = b_buf.as_ptr().cast::<Ptr>().read();
|
||||
|
||||
(a, b)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
// two innocent looking variants
|
||||
let a = 5u8;
|
||||
let b = 3u8;
|
||||
|
||||
// two innocent looking pointers
|
||||
let a_ptr = &a as Ptr;
|
||||
let b_ptr = &b as Ptr;
|
||||
|
||||
// extract the addresses for later use. in the real xorlist, these would be xored
|
||||
let a_addr = Strict::addr(a_ptr);
|
||||
let b_addr = Strict::addr(b_ptr);
|
||||
|
||||
// if we were implementing an actual xorlist, we would be setting the addresses of
|
||||
// the pointers to our xored address so that the combined buffer stores the full address
|
||||
// and we could get it out through more complex magic. this is besides the point of this
|
||||
// demonstration, it is only concerned with combining provenances
|
||||
|
||||
// combine the provenances
|
||||
let cursed = combine(a_ptr, b_ptr);
|
||||
|
||||
// do crimes here
|
||||
|
||||
// and get them out again
|
||||
let (a_prov, b_prov) = extract(cursed);
|
||||
|
||||
// make them pointers again!
|
||||
let new_a = Strict::with_addr(a_prov, a_addr);
|
||||
let new_b = Strict::with_addr(b_prov, b_addr);
|
||||
|
||||
// it works now, right? :ferrisClueless:
|
||||
assert_eq!(*new_a, 5);
|
||||
assert_eq!(*new_b, 3);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue