Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

We've been defeated by Miri. #3

Open
Speykious opened this issue Feb 16, 2024 · 5 comments
Open

We've been defeated by Miri. #3

Speykious opened this issue Feb 16, 2024 · 5 comments

Comments

@Speykious
Copy link
Owner

Speykious commented Feb 16, 2024

Miri is too strong. Even without any unsafe blocks, it detects problems.

Miri defeats our tests

cve on ξ‚  main is πŸ“¦ v0.1.0 via πŸ¦€ v1.76.0 
❯ cargo +nightly miri test  
Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)... done
   Compiling cve-rs v0.1.0 (/home/speykious/Documents/programming/rust/cve)
    Finished test [unoptimized] target(s) in 0.07s
     Running unittests src/main.rs (target/miri/x86_64-unknown-linux-gnu/debug/deps/cve_rs-5d4da50aad7811b6)

running 1 test
test transmute::tests::test_transmute ... error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
  --> src/transmute.rs:28:17
   |
28 |     let ref_to_b = get_dangling_ref::<B>();
   |                    ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free)
   |
   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
   = note: BACKTRACE:
   = note: inside `transmute::transmute::<f32, i32>` at src/transmute.rs:28:17: 28:40
note: inside `transmute::tests::test_transmute`
  --> src/transmute.rs:51:5
   |
51 |                 transmute::transmute::<f32, i32>(420.69),
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure
  --> src/transmute.rs:45:21
   |
39 |     #[test]
   |     ------- in this procedural macro expansion
...
45 |     fn test_transmute() {
   |                        ^
   = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

Miri defeats our CLI

error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
  --> src/segfault.rs:55:15
   |
55 |     let my_ref = get_dropped_box();
   |                  ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free)
   |
   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
   = note: BACKTRACE:
   = note: inside `segfault::segfault` at src/segfault.rs:55:15: 55:32
note: inside `main`
  --> src/main.rs:16:17
   |
16 |         "segfault" => segfault::segfault(),
   |                       ^^^^^^^^^^^^^^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@vimpostor
Copy link

vimpostor commented Feb 21, 2024

Miri is too strong. Even without any unsafe blocks, it detects problems.

Well, at least we always have the alternative possibility to port this from using transmute shenanigans to using std::fs to write/read to /proc/self/mem: rust-lang/rust#32670

@AsafFisher
Copy link

Miri is too strong. Even without any unsafe blocks, it detects problems.

Well, at least we always have the alternative possibility to port this from using transmute shenanigans to using std::fs to write/read to /proc/self/mem: rust-lang/rust#32670

This is a bad approach as this will cause this project to be platform specific. The aim of the project is to give a platform agnostic/cross platform solution for safe vulnerabilities in your projects.

@AmJayden
Copy link

Miri is too strong. Even without any unsafe blocks, it detects problems.

Well, at least we always have the alternative possibility to port this from using transmute shenanigans to using std::fs to write/read to /proc/self/mem: rust-lang/rust#32670

Even if you were to do this, this is actually an unsafe operation at its core, there's no safety guarantees behind calling into operating system code and the underlying functionality for it is all implemented with unsafe, thus meaning that it's not 100% safe code either.

@vimpostor
Copy link

there's no safety guarantees behind calling into operating system code and the underlying functionality for it is all implemented with unsafe, thus meaning that it's not 100% safe code either.

Yes, it is safe, as it is using Rust's std::fsAPI without using the unsafe keyword once, meaning it enjoys:

  • zero-cost abstractions
  • move semantics
  • guaranteed memory safety
  • threads without data races
  • trait-based generics
  • pattern matching
  • type inference
  • minimal runtime
  • efficient C bindings

@AmJayden
Copy link

there's no safety guarantees behind calling into operating system code and the underlying functionality for it is all implemented with unsafe, thus meaning that it's not 100% safe code either.

Yes, it is safe, as it is using Rust's std::fsAPI without using the unsafe keyword once, meaning it enjoys:

  • zero-cost abstractions
  • move semantics
  • guaranteed memory safety
  • threads without data races
  • trait-based generics
  • pattern matching
  • type inference
  • minimal runtime
  • efficient C bindings

No, this isn't the case. I advise you to look at your target's underlying filesystem implementation. The underlying standard library code cannot access your system's filesystem without making a syscall, which is unsafe. You aren't truly bypassing Rust's safety checks by just calling into code with underlying unsafety. Rust's safety model doesn't guarantee that your operating system will be free of bugs or ways to break memory safety, it guarantees safety within exclusively Rust code interacting with itself. You can check your target's filesystem implementation to see for yourself how they implement it, here's how it's done on Linux:

impl FileDesc {
    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let result = cvt(unsafe { abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
        Ok(result as usize)
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let result = cvt(unsafe { abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
        Ok(result as usize)
    }
    // ...
}

https://github.com/rust-lang/rust/blob/c5e7f45b6219a963e8e27ef6e15587f22e80a3f5/library/std/src/sys/pal/hermit/fd.rs#L29

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants