-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
183 changed files
with
48,601 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
[package] | ||
name = "snapchange" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
vmm-sys-util = "0.11.0" | ||
kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } | ||
kvm-ioctls = "0.12.0" | ||
anyhow = "1.0.40" | ||
libc = "0.2.98" | ||
bitflags = "1.2.1" | ||
x86_64 = { version = "0.14.10", default-features = false, features = ["instructions"] } | ||
clap = { version = "4.1.8", features = ["derive"] } | ||
serde_json = "1.0" | ||
serde = { version = "1.0", features = ["derive"] } | ||
serde-hex = "0.1.0" | ||
nix = "0.22.2" | ||
iced-x86 = "1.13.0" | ||
thiserror = "1.0" | ||
ctrlc = "3.2.0" | ||
core_affinity = "0.5.10" | ||
lazy_static = "1.4.0" | ||
log = "0.4" | ||
env_logger = "0.9.0" | ||
clap-verbosity-flag = "2.0" | ||
rand = "0.8" | ||
rand_core = "0.6" | ||
ahash = "0.8" | ||
|
||
# For addr2line implementation | ||
addr2line = "0.17.0" | ||
memmap = "0.7" | ||
object = { version = "0.27.1", default-features = false, features = ["read"], optional = true } | ||
|
||
# For MSRs to/from primitive | ||
num_enum = "0.5.7" | ||
|
||
# For stats TUI | ||
tui = "0.19.0" | ||
crossterm = "0.22.1" | ||
tui-logger = "0.8.1" | ||
toml = "0.7.2" | ||
|
||
[profile.release] | ||
debug = true | ||
incremental = true | ||
|
||
[features] | ||
default = [] | ||
redqueen = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Brief roadmap of the source files | ||
|
||
Below is a brief roadmap of the source code and where to potentially start reading: | ||
|
||
* `src/commands/[fuzz|minimize|trace|coverage|project].rs` - Contains the logic for each command | ||
- Each command follows roughly the same logic: | ||
|
||
``` | ||
Initialize a KVM environment | ||
Create a `FuzzVm` which executes and maintains the state of the Guest VM | ||
Prepare the Guest VM by mutating input or modifying state | ||
loop { | ||
Run the Guest VM (fuzzvm.run()) | ||
Handle the exit condition of the VM (handle_vmexit) | ||
Save metadata | ||
} | ||
``` | ||
* `src/fuzzvm.rs` - Provides `FuzzVm` to handle the main state of the Guest. | ||
- This struct is how a researcher can read/write state into the guest | ||
- Examples: | ||
- fuzzvm.read_bytes() | ||
- fuzzvm.read::<u32>() | ||
- fuzzvm.read::<[u8; 128]>() | ||
- fuzzvm.write_bytes() | ||
- fuzzvm.write::<u32>() | ||
- fuzzvm.write::<[u8; 128]>() | ||
- fuzzvm.rip() | fuzzvm.set_rip() | ||
- fuzzvm.rax() | fuzzvm.set_rax() | ||
- fuzzvm.hexdump() | ||
- fuzzvm.translate() | ||
- fuzzvm.print_context() | ||
* `src/fuzzer.rs` - Provides the `Fuzzer` trait that each target specific fuzzer will implement | ||
* `src/stats.rs` - Aggregates and displays the statistics from each core |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
all: check docs | ||
|
||
check: | ||
# Clippy checks | ||
RUST_BACKTRACE=full cargo clippy --color always -- \ | ||
--no-deps \ | ||
--allow clippy::verbose_bit_mask \ | ||
--allow clippy::print_with_newline \ | ||
--allow clippy::write_with_newline \ | ||
--allow clippy::module_name_repetitions \ | ||
--allow clippy::missing_errors_doc \ | ||
--deny missing_docs \ | ||
--deny clippy::missing_docs_in_private_items \ | ||
--deny clippy::pedantic \ | ||
--allow clippy::struct_excessive_bools \ | ||
--allow clippy::redundant_field_names \ | ||
--allow clippy::must_use_candidate \ | ||
--allow clippy::manual_flatten | ||
|
||
docs: check | ||
# Documentation build regardless of arch | ||
cargo doc --no-deps |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "fuzzer_template" | ||
version = "0.1.0" | ||
edition = "2021" | ||
exclude = ["qemu_snapshot", "snapshot"] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
anyhow = "1.0.68" | ||
snapchange = { version = "0.1.0", path = ".." } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# Snapchange benchmark | ||
|
||
This is the basic snapchange benchmark for gathering performance data across several factors: | ||
|
||
* Instructions per iteration | ||
* Breakpoints triggered per iteration | ||
* Dirty Pages restored per iteration | ||
* Number of cores used | ||
|
||
Building the benchmark is a script: | ||
|
||
```sh | ||
$ ./make_bench_target.sh | ||
``` | ||
|
||
Executing the benchmark is also a simple script: | ||
|
||
```sh | ||
$ ./bench.sh | ||
``` | ||
|
||
This will generate a `data_120s` directory containing all of a `stats` file for each benchmark | ||
configuration. There is a small utility used to convert the data to be used for generating | ||
the comparison graphs. | ||
|
||
```sh | ||
$ cd gather_data | ||
$ cargo run -r -- ../data_120s | ||
$ cd .. | ||
``` | ||
|
||
This will create a `data_120s.dat` data file with the extracted data ready for [seaborn](https://seaborn.pydata.org/) | ||
to generate several graphs. | ||
|
||
```sh | ||
$ pip3 install seaborn | ||
$ python3 generate_graph.py ./data_120.dat | ||
``` | ||
|
||
## Benchmark harness | ||
|
||
The benchmark harness is a small [assembly snippet](./bench_harness/src/main.rs): | ||
|
||
``` | ||
// Execute the dirty pages and instructions for this benchmark | ||
// R9 - Memory that can be dirtied (should NOT have to be set in the benchmark fuzzer) | ||
// R10 - Number of pages to dirty (at least 1) | ||
// RCX - Number of instructions to execute (not including dirtying pages) | ||
unsafe { | ||
std::arch::asm!( | ||
r#" | ||
4: | ||
mov byte ptr [r9], 0x41 | ||
add r9, 0x1000 | ||
dec r10 | ||
jnz 4b | ||
2: | ||
dec rcx | ||
jnz 2b | ||
"#, | ||
in("r9") scratch, | ||
options(nostack) | ||
); | ||
} | ||
``` | ||
|
||
This section will dirty pages by writing a single byte to each page. The number of pages to dirty | ||
is set in `rdi` | ||
|
||
``` | ||
4: | ||
mov byte ptr [r9], 0x41 | ||
add r9, 0x1000 | ||
dec r10 | ||
jnz 4b | ||
``` | ||
|
||
For number of instructions, there is a tight loop that executes. The number of instructions is stored in `rcx`. | ||
|
||
``` | ||
2: | ||
dec rcx | ||
jnz 2b | ||
``` | ||
|
||
The number of instructions and dirty pages cores are given to the harness via environment variables. | ||
|
||
For running the benchmark with `1000` pages, `1000000` instructions, and `8` cores. | ||
|
||
```PAGES=1000 INSTRS=1000000 timeout 120s cargo run -r -- fuzz -c 8 --timeout 120s``` | ||
|
||
For running the benchmark with `1000` pages, `1000000` breakpoints, and `8` cores. | ||
|
||
```PAGES=1000 VMEXITS=1000000 timeout 120s cargo run -r -- fuzz -c 8 --timeout 120s``` |
Oops, something went wrong.