Skip to content

Commit f1896bd

Browse files
committed
Rewrite README
1 parent d97f46f commit f1896bd

1 file changed

Lines changed: 23 additions & 28 deletions

File tree

README.md

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
1-
## Poor Man's Memory Sanitizer
1+
## libdiffuzz: poor man's Memory Sanitizer
22

3-
This is a trivial fork of [AFL](http://lcamtuf.coredump.cx/afl/)'s libdislocator that can be used to detect uses of uninitialized memory. It is designed to be used in case [Memory Sanitizer](https://clang.llvm.org/docs/MemorySanitizer.html) is not available for some reason, such as:
3+
This is a drop-in replacement for OS memory allocator that can be used to detect uses of uninitialized memory. It is designed to be used in case [Memory Sanitizer](https://clang.llvm.org/docs/MemorySanitizer.html) is not available for some reason, such as:
44

55
* Your code contains inline assembly or links to proprietary libraries that cannot be instrumented by MSAN
66
* You're debugging code that is specific to an exotic CPU architecture where MSAN is not available
7-
* You want to check Rust code for memory disclosure vulnerabilities and [Rust standard library still doesn't support MSAN](https://github.com/rust-lang/rust/issues/39610)
87
* You're debugging code that is specific to a freaky operating system such as macOS where no sane development tools are available
8+
* You want to check Rust code for memory disclosure vulnerabilities and [Rust standard library still doesn't support MSAN](https://github.com/rust-lang/rust/issues/39610)
9+
* You want to check if the bug MSAN found is actually exploitable, i.e. if the uninitialized memory contents actually show up in the output
910
* You want to find vulnerabilities in black-box binaries that you do not have the source code for (not always straightforward, see below)
1011

1112
**This is not a drop-in replacement for Memory Sanitizer!** It will likely require changes to your code or your testing setup, see below.
1213

1314
## How it works
1415

15-
When injected into a process, this library initializes every subsequent allocated region of memory to different values. Using this library you can detect uses of uninitialized memory simply by running a certain operation twice *in the same process* and comparing the outputs; if they differ, then the code uses uninitialized memory somewhere.
16+
When injected into a process, this library initializes every subsequent allocated region of memory to different values. Using this library you can detect uses of uninitialized memory simply by running a certain operation twice *in the same process* and comparing the outputs; if they differ, then the code uses uninitialized memory somewhere. Combine this with a fuzzer (e.g. [AFL](http://lcamtuf.coredump.cx/afl/), [honggfuzz](http://honggfuzz.com/)) to automatically discover cases when this happens. (This is called "differential fuzzing", hence the name).
1617

17-
Naturally, this is conditional on the same operation run twice returning the same results normally. If that is not the case in your program, and you cannot make it deterministic, you're out of luck.
18-
19-
This library also inherits all the checks that upstream libdislocator performs; see README.dislocator for details.
18+
Naturally, this is conditional on the same operation run twice returning the same results normally. If that is not the case in your program and you cannot make it deterministic - you're out of luck.
2019

2120
## TL;DR: usage
2221

23-
1. Clone this repository, run `make`; this will build libdislocator.so
22+
1. Clone this repository, run `make`; this will build libdiffuzz.so
2423
1. Make your code run the same operation twice in the same process and compare outputs.
25-
1. Run your code like this: `LD_PRELOAD=/path/to/libdislocator.so /path/to/your/binary`.
26-
1. If you're fuzzing with [AFL](http://lcamtuf.coredump.cx/afl/), use `AFL_PRELOAD=/path/to/libdislocator.so afl-fuzz ...`. If you're not fuzzing with AFL - you should!
24+
1. Run your code like this: `LD_PRELOAD=/path/to/libdiffuzz.so /path/to/your/binary`.
25+
1. If you're fuzzing with [AFL](http://lcamtuf.coredump.cx/afl/), use `AFL_PRELOAD=/path/to/libdiffuzz.so afl-fuzz ...` instead. If you're not fuzzing with AFL - you should!
2726
1. Brag that you've used differential fuzzing to find vulnerabilities in real code
2827

29-
## Quick start for Rust users
28+
## Quick start for Rust code
3029

31-
1. Clone this repository, run `make`; this will build libdislocator.so
32-
1. Make sure [this code](https://gist.github.com/Shnatsel/0c024a51b64c6e0b6c6e66f991904816) doesn't reliably crash when run on its own, but does crash when you run it like this: `LD_PRELOAD=/path/to/libdislocator.so target/release/membleed`
33-
1. If you haven't done regular fuzzing yet - do set up fuzzing with AFL. [It's not that hard.](https://fuzz.rs/book/afl/setup.html) Make sure you use the in-process mode, i.e. the `fuzz!` macro.
30+
1. Clone this repository, run `make`; this will build libdiffuzz.so
31+
1. Make sure [this code](https://gist.github.com/Shnatsel/0c024a51b64c6e0b6c6e66f991904816) doesn't reliably crash when run on its own, but does crash when you run it like this: `LD_PRELOAD=/path/to/libdiffuzz.so target/release/membleed`
32+
1. If you haven't done regular fuzzing yet - do set up fuzzing with AFL. [It's not that hard.](https://fuzz.rs/book/afl/setup.html)
3433
1. In your fuzz target run the same operation twice and `assert!` that they produce the same result. **TODO:** example
3534
1. Add the following to your fuzz harness:
3635
```rust
@@ -39,36 +38,32 @@ use std::alloc::System;
3938
#[global_allocator]
4039
static GLOBAL: System = System;
4140
```
42-
6. Run the [AFL.rs](https://github.com/rust-fuzz/afl.rs) fuzz target like this: `AFL_PRELOAD=/path/to/libdislocator.so cargo afl fuzz ...`
41+
6. Run the [AFL.rs](https://github.com/rust-fuzz/afl.rs) fuzz target like this: `AFL_PRELOAD=/path/to/libdiffuzz.so cargo afl fuzz ...`
4342

4443
## Auditing black-box binaries
4544

46-
If your target binary lets you feed it the same input several times - stellar! Simply preload libdislocator-numbering into a binary, feed it the same input twice and compare the outputs.
45+
If your target binary lets you feed it the same input several times - stellar! Simply preload libdiffuzz-numbering into a binary, feed it the same input twice and compare the outputs.
4746

48-
However, if your binary only accepts one input and then terminates, you will have to change the `u16 alloc_clobber_counter = 0;` in libdislocator-numbering to something unique to each process, such as milliseconds from system time, replace `alloc_clobber_counter++` in memset call with `alloc_clobber_counter`, then run the entire process twice and compare the outputs from the two runs. If they differ - congratulations, you've found a memory disclosure vulnerability!
47+
However, if your binary only accepts one input and then terminates, you will have to change the `u16 alloc_clobber_counter = 0;` in libdiffuzz-numbering to something unique to each process, such as milliseconds from system time, replace `alloc_clobber_counter++` in memset call with `alloc_clobber_counter`, then run the entire process twice and compare the outputs from the two runs. If they differ - congratulations, you've found a memory disclosure vulnerability!
4948

5049
Oh - if the output is inherently non-deterministic, you're out of luck.
5150

5251
## Limitations and future work
5352

54-
Unlike memory sanitizer, this thing will not make your program crash as soon as a read from uninitialized memory occurs. Instead, it lets you detect that it has occurred after the fact and only if the contents of uninitialized memory leak into the output. I.e. this will help you notice security vulnerabilities, but will not really aid in debugging.
55-
5653
Stack-based uninitialized reads are not detected.
5754

55+
Unlike memory sanitizer, this thing will not make your program crash as soon as a read from uninitialized memory occurs. Instead, it lets you detect that it has occurred after the fact and only if the contents of uninitialized memory leak into the output. I.e. this will help you notice security vulnerabilities, but will not really aid in debugging.
56+
5857
I have no idea how the global counter in C inside `malloc()` will behave in multi-threaded programs. FWIW I have just as much idea about what would happen if I made the counter atomic. So for now, be warned that in multi-threaded programs it may or may not actually detect uninitialized memory access. Contributions are welcome. For now you can work around this by applying the same hack as for black-box binaries.
5958

6059
This may miss single-byte uninitialized reads because the counter is `u16`; if you need to detect those, change it to `u8`, but be warned that it will be more likely to miss uninitialized reads that way.
6160

62-
Since this is a fork of libdislocator, which is a poor man's [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html), this is now poor man's ASAN+MSAN in one package. If you're interested in just the MSAN-like bits (e.g. if you did get the real ASAN running already), decoupling the "initialize buffer to specific values" bit into a separate library and dropping the rest of libdislocator might be worthwhile. For my purposes this all-in-one thing has been fast enough, but your mileage may vary.
63-
64-
There seems to be a memory leak in this library somewhere, which makes it unusable for persistent fuzzers such as honggfuzz. It's likely somewhere in libdislocator part (canaries around allocated memory?), reinforcing the theme of decoupling this from libdislocator.
65-
66-
Also, if you go down the "just MSAN" road, you might as well RIIR and/or write it as a Rust-specific allocator, now that the relevant traits are stabilized. Rust-specific allocator sure is going to be more ergonomic, but I'd much rather fix MSAN.
67-
68-
Also, I should either upstream this into AFL at some point or, failing that, hand this over to @rust-fuzz folks.
69-
7061
## Trophy case
7162

72-
List of bugs found using this tool, just to show that this whole idea is not completely bonkers:
63+
List of previously unknown (i.e. zero-day) vulnerabilities found using this tool, to show that this whole idea is not completely bonkers:
7364

7465
1. [Memory disclosure](https://github.com/ruuda/claxon/issues/10) in [Claxon](https://github.com/ruuda/claxon)
66+
67+
## See also
68+
69+
[libdislocator](https://github.com/mirrorer/afl/tree/master/libdislocator), poor man's Address Sanitizer that libdiffuzz is based on.

0 commit comments

Comments
 (0)