cve-rs icon indicating copy to clipboard operation
cve-rs copied to clipboard

We've been defeated by Miri.

Open Speykious opened this issue 1 year ago • 6 comments

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

Speykious avatar Feb 16 '24 12:02 Speykious

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: https://github.com/rust-lang/rust/issues/32670

vimpostor avatar Feb 21 '24 01:02 vimpostor

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: https://github.com/rust-lang/rust/issues/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.

AsafFisher avatar Feb 22 '24 13:02 AsafFisher

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.

AmJayden avatar Mar 21 '24 07:03 AmJayden

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

vimpostor avatar Mar 21 '24 11:03 vimpostor

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

AmJayden avatar Mar 28 '24 17:03 AmJayden