NYX Executor (GSoC '22) (#693)
* Add ccache * Update codecov.yml * Add libnyx * Fix * Add nyx build script * Fix build.sh && init executor.rs * Fix commit * Fix code * initialize `exector.rs` * refine API in `nyx_bridge.rs` * initialze `run_target` * add `test_nyxhelper` * initize `test_executor` * remove `nyx_beidge.rs` * make `test_executor` compile * Improve test * refine code * update version * fix docker * fix docker * Fix clippy * Fix build * fix build && add `set_timeout` * Fix and refine CI * fix CI * Fix CI * Add platform restrict * cargo fmt * add parallel mode * add example `nyx_libxml2_parallel` * fix fuzzer example * fix CI * add README * fix CI * fix CI * fix CI * remove unwrap and NyxResult * code format fix * add libnyx's rev * fix format * change Duration format && Fix CI * caego fmt * fix CI * fix CI * Add doc * test CI * Update test_all_fuzzers.sh * Update test_all_fuzzers.sh * Update test_all_fuzzers.sh * add cache for apt and cargo-install * Update build_and_test.yml * Update build_and_test.yml * tmp test CI * fix CI * remove debug cmd * remove test * code refine * code refine * code refine * code refine * add Makefile * fix example doc for nyx * add `NyxHelper::new_with_initial_timeout` * fix `NyxHelper::new` * fix curl parameter * code refine * add check for setup script * use afl-clang-fast in nyx * fix logic * fix makefile * fix CI * Update build_and_test.yml * Update build_and_test.yml * remove debug cmd Co-authored-by: syheliel <syheliel@gmail.com> Co-authored-by: Dominik Maier <dmnk@google.com>
This commit is contained in:
parent
d377fce4f3
commit
758e49ac70
74
.github/workflows/build_and_test.yml
vendored
74
.github/workflows/build_and_test.yml
vendored
@ -22,9 +22,13 @@ jobs:
|
|||||||
toolchain: nightly
|
toolchain: nightly
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: install mdbook
|
- name: install mdbook
|
||||||
run: cargo install mdbook
|
uses: baptiste0928/cargo-install@v1.3.0
|
||||||
|
with:
|
||||||
|
crate: mdbook
|
||||||
- name: install linkcheck
|
- name: install linkcheck
|
||||||
run: cargo install mdbook-linkcheck
|
uses: baptiste0928/cargo-install@v1.3.0
|
||||||
|
with:
|
||||||
|
crate: mdbook-linkcheck
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Build libafl debug
|
- name: Build libafl debug
|
||||||
run: cargo build -p libafl
|
run: cargo build -p libafl
|
||||||
@ -51,8 +55,10 @@ jobs:
|
|||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: set mold linker as default linker
|
- name: set mold linker as default linker
|
||||||
uses: rui314/setup-mold@v1
|
uses: rui314/setup-mold@v1
|
||||||
- name: Install deps
|
- name: Install and cache deps
|
||||||
run: sudo apt-get install -y llvm llvm-dev clang ninja-build clang-format-13 shellcheck gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
|
uses: awalsh128/cache-apt-pkgs-action@v1.1.0
|
||||||
|
with:
|
||||||
|
packages: llvm llvm-dev clang ninja-build clang-format-13 shellcheck libgtk-3-dev gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
|
||||||
- name: get clang version
|
- name: get clang version
|
||||||
run: command -v llvm-config && clang -v
|
run: command -v llvm-config && clang -v
|
||||||
- name: Install cargo-hack
|
- name: Install cargo-hack
|
||||||
@ -60,6 +66,27 @@ jobs:
|
|||||||
- name: Add nightly rustfmt and clippy
|
- name: Add nightly rustfmt and clippy
|
||||||
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# ---- format check ----
|
||||||
|
# pcguard edges and pcguard hitcounts are not compatible and we need to build them seperately
|
||||||
|
- name: Check pcguard edges
|
||||||
|
run: cargo check --features=sancov_pcguard_edges
|
||||||
|
- name: Format
|
||||||
|
run: cargo fmt -- --check
|
||||||
|
- name: Run clang-format style check for C/C++ programs.
|
||||||
|
run: clang-format-13 -n -Werror --style=file $(find . -type f \( -name '*.cpp' -o -iname '*.hpp' -o -name '*.cc' -o -name '*.cxx' -o -name '*.cc' -o -name '*.h' \) | grep -v '/target/' | grep -v 'libpng-1\.6\.37' | grep -v 'stb_image\.h' | grep -v 'dlmalloc\.c' | grep -v 'QEMU-Nyx')
|
||||||
|
- name: run shellcheck
|
||||||
|
run: shellcheck ./scripts/*.sh
|
||||||
|
- name: Run clippy
|
||||||
|
run: ./scripts/clippy.sh
|
||||||
|
|
||||||
|
# ---- doc check ----
|
||||||
|
- name: Build Docs
|
||||||
|
run: cargo doc
|
||||||
|
- name: Test Docs
|
||||||
|
run: cargo +nightly test --doc --all-features
|
||||||
|
|
||||||
|
# ---- build and feature check ----
|
||||||
- name: Run a normal build
|
- name: Run a normal build
|
||||||
run: cargo build --verbose
|
run: cargo build --verbose
|
||||||
# cargo-hack tests/checks each crate in the workspace
|
# cargo-hack tests/checks each crate in the workspace
|
||||||
@ -69,25 +96,8 @@ jobs:
|
|||||||
- name: Check each feature
|
- name: Check each feature
|
||||||
# Skipping python as it has to be built with the `maturin` tool
|
# Skipping python as it has to be built with the `maturin` tool
|
||||||
run: cargo hack check --feature-powerset --depth=2 --exclude-features=agpl,nautilus,python,sancov_pcguard_edges,arm,aarch64,i386 --no-dev-deps
|
run: cargo hack check --feature-powerset --depth=2 --exclude-features=agpl,nautilus,python,sancov_pcguard_edges,arm,aarch64,i386 --no-dev-deps
|
||||||
# pcguard edges and pcguard hitcounts are not compatible and we need to build them seperately
|
|
||||||
- name: Check pcguard edges
|
|
||||||
run: cargo check --features=sancov_pcguard_edges
|
|
||||||
- name: Build examples
|
- name: Build examples
|
||||||
run: cargo build --examples --verbose
|
run: cargo build --examples --verbose
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Format
|
|
||||||
run: cargo fmt -- --check
|
|
||||||
- name: Run clang-format style check for C/C++ programs.
|
|
||||||
run: clang-format-13 -n -Werror --style=file $(find . -type f \( -name '*.cpp' -o -iname '*.hpp' -o -name '*.cc' -o -name '*.cxx' -o -name '*.cc' -o -name '*.h' \) | grep -v '/target/' | grep -v 'libpng-1\.6\.37' | grep -v 'stb_image\.h' | grep -v 'dlmalloc\.c')
|
|
||||||
- name: run shellcheck
|
|
||||||
run: shellcheck ./scripts/*.sh
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Build Docs
|
|
||||||
run: cargo doc
|
|
||||||
- name: Test Docs
|
|
||||||
run: cargo +nightly test --doc --all-features
|
|
||||||
- name: Run clippy
|
|
||||||
run: ./scripts/clippy.sh
|
|
||||||
|
|
||||||
ubuntu-concolic:
|
ubuntu-concolic:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -122,9 +132,6 @@ jobs:
|
|||||||
run: cd ./bindings/pylibafl && maturin build
|
run: cd ./bindings/pylibafl && maturin build
|
||||||
|
|
||||||
fuzzers:
|
fuzzers:
|
||||||
env:
|
|
||||||
CC: ccache clang # use ccache in default
|
|
||||||
CXX: ccache clang # use ccache in default
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
@ -137,11 +144,6 @@ jobs:
|
|||||||
- name: set mold linker as default linker
|
- name: set mold linker as default linker
|
||||||
if: runner.os == 'Linux' # mold only support linux until now
|
if: runner.os == 'Linux' # mold only support linux until now
|
||||||
uses: rui314/setup-mold@v1
|
uses: rui314/setup-mold@v1
|
||||||
- name: add ccache
|
|
||||||
uses: hendrikmuhs/ccache-action@v1.2
|
|
||||||
with:
|
|
||||||
key: ${{ github.job }}-${{ matrix.os }}
|
|
||||||
max-size: 2000M
|
|
||||||
- name: enable mult-thread for `make`
|
- name: enable mult-thread for `make`
|
||||||
run: export MAKEFLAGS="-j$(expr $(nproc) \+ 1)"
|
run: export MAKEFLAGS="-j$(expr $(nproc) \+ 1)"
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
@ -149,19 +151,25 @@ jobs:
|
|||||||
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||||
- uses: lyricwulf/abc@v1
|
- uses: lyricwulf/abc@v1
|
||||||
with:
|
with:
|
||||||
linux: llvm llvm-dev clang nasm ninja-build gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
|
# todo: remove afl++-clang when nyx support samcov_pcguard
|
||||||
|
linux: llvm llvm-dev clang nasm ninja-build gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libgtk-3-dev afl++-clang pax-utils
|
||||||
# update bash for macos to support `declare -A` command`
|
# update bash for macos to support `declare -A` command`
|
||||||
macos: llvm libpng nasm coreutils z3 bash
|
macos: llvm libpng nasm coreutils z3 bash
|
||||||
|
- name: pip install
|
||||||
|
run: python3 -m pip install msgpack jinja2
|
||||||
- name: install cargo-make
|
- name: install cargo-make
|
||||||
run: cargo install --force cargo-make
|
uses: baptiste0928/cargo-install@v1.3.0
|
||||||
|
with:
|
||||||
|
crate: cargo-make
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true # recursively checkout submodules
|
||||||
- name: Build and run example fuzzers
|
- name: Build and run example fuzzers
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: ./scripts/test_all_fuzzers.sh
|
run: ./scripts/test_all_fuzzers.sh
|
||||||
- name: Build and run example fuzzers
|
- name: Build and run example fuzzers
|
||||||
if: runner.os == 'macOS' # use bash v4
|
if: runner.os == 'macOS' # use bash v4
|
||||||
run: /usr/local/bin/bash ./scripts/test_all_fuzzers.sh
|
run: /usr/local/bin/bash ./scripts/test_all_fuzzers.sh
|
||||||
- run: ccache --show-stats
|
|
||||||
|
|
||||||
nostd-build:
|
nostd-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -229,7 +237,7 @@ jobs:
|
|||||||
- name: Add nightly rustfmt and clippy
|
- name: Add nightly rustfmt and clippy
|
||||||
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: brew install z3
|
run: brew install z3 gtk+3
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: MacOS Build
|
- name: MacOS Build
|
||||||
run: cargo build --verbose
|
run: cargo build --verbose
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -46,3 +46,6 @@ __pycache__
|
|||||||
*.lafl_lock
|
*.lafl_lock
|
||||||
|
|
||||||
*atomic_file_testfile*
|
*atomic_file_testfile*
|
||||||
|
**/libxml2
|
||||||
|
**/corpus_discovered
|
||||||
|
**/libxml2-*.tar.gz
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,3 +1,9 @@
|
|||||||
[submodule "libafl_concolic/symcc_runtime/symcc"]
|
[submodule "libafl_concolic/symcc_runtime/symcc"]
|
||||||
path = libafl_concolic/symcc_runtime/symcc
|
path = libafl_concolic/symcc_runtime/symcc
|
||||||
url = https://github.com/AFLplusplus/symcc.git
|
url = https://github.com/AFLplusplus/symcc.git
|
||||||
|
[submodule "libafl_nyx/QEMU-Nyx"]
|
||||||
|
path = libafl_nyx/QEMU-Nyx
|
||||||
|
url = https://github.com/nyx-fuzz/QEMU-Nyx.git
|
||||||
|
[submodule "libafl_nyx/packer"]
|
||||||
|
path = libafl_nyx/packer
|
||||||
|
url = https://github.com/syheliel/packer.git
|
||||||
|
@ -13,6 +13,7 @@ members = [
|
|||||||
"libafl_frida",
|
"libafl_frida",
|
||||||
"libafl_qemu",
|
"libafl_qemu",
|
||||||
"libafl_sugar",
|
"libafl_sugar",
|
||||||
|
"libafl_nyx",
|
||||||
"libafl_concolic/symcc_runtime",
|
"libafl_concolic/symcc_runtime",
|
||||||
"libafl_concolic/symcc_libafl",
|
"libafl_concolic/symcc_libafl",
|
||||||
"libafl_concolic/test/dump_constraints",
|
"libafl_concolic/test/dump_constraints",
|
||||||
|
@ -63,6 +63,9 @@ COPY scripts/dummy.rs libafl_concolic/symcc_runtime/src/lib.rs
|
|||||||
COPY libafl_concolic/symcc_libafl/Cargo.toml libafl_concolic/symcc_libafl/
|
COPY libafl_concolic/symcc_libafl/Cargo.toml libafl_concolic/symcc_libafl/
|
||||||
COPY scripts/dummy.rs libafl_concolic/symcc_libafl/src/lib.rs
|
COPY scripts/dummy.rs libafl_concolic/symcc_libafl/src/lib.rs
|
||||||
|
|
||||||
|
COPY libafl_nyx/Cargo.toml libafl_nyx/build.rs libafl_nyx/
|
||||||
|
COPY scripts/dummy.rs libafl_nyx/src/lib.rs
|
||||||
|
|
||||||
COPY utils utils
|
COPY utils utils
|
||||||
|
|
||||||
RUN cargo build && cargo build --release
|
RUN cargo build && cargo build --release
|
||||||
@ -94,6 +97,8 @@ RUN touch libafl_frida/src/lib.rs
|
|||||||
COPY libafl_concolic/symcc_libafl libafl_concolic/symcc_libafl
|
COPY libafl_concolic/symcc_libafl libafl_concolic/symcc_libafl
|
||||||
COPY libafl_concolic/symcc_runtime libafl_concolic/symcc_runtime
|
COPY libafl_concolic/symcc_runtime libafl_concolic/symcc_runtime
|
||||||
COPY libafl_concolic/test libafl_concolic/test
|
COPY libafl_concolic/test libafl_concolic/test
|
||||||
|
COPY libafl_nyx/src libafl_nyx/src
|
||||||
|
RUN touch libafl_nyx/src/lib.rs
|
||||||
RUN cargo build && cargo build --release
|
RUN cargo build && cargo build --release
|
||||||
|
|
||||||
# Copy fuzzers over
|
# Copy fuzzers over
|
||||||
|
10
docs/src/core_concepts/launcher.md
Normal file
10
docs/src/core_concepts/launcher.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Launcher
|
||||||
|
|
||||||
|
Launcher is used to launch multiple fuzzer instances in parallel in one click. On `Unix` systems, Launcher will use `fork` if the `fork` feature is enabled. Else, it will start subsequent nodes with the same command line, and will set special `env` variables accordingly.
|
||||||
|
|
||||||
|
To use launcher, first you need to write an anonymous function `let mut run_client = |state: Option<_>, mut mgr, _core_id|{}`, which uses three parameters to create individual fuzzer. Then you can specify the `shmem_provider`,`broker_port`,`monitor`,`cores` and other stuff through `Launcher::builder()`:
|
||||||
|
1. To connect multiple nodes together via TCP, you can use the `remote_broker_addr`. this requires the `llmp_bind_public` compile-time feature for `LibAFL`.
|
||||||
|
2. To use multiple launchers for individual configurations, you can set `spawn_broker` to `false` on all but one.
|
||||||
|
3. Launcher will not select the cores automatically, so you need to specify the `cores` that you want.
|
||||||
|
|
||||||
|
For more examples, you can check out `qemu_launcher` and `libfuzzer_libpng_launcher` in `./fuzzers/`.
|
15
fuzzers/nyx_libxml2_parallel/Cargo.toml
Normal file
15
fuzzers/nyx_libxml2_parallel/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "nyx_libxml2_parallel"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
default-run = "nyx_libxml2_parallel"
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = {path = "../../libafl"}
|
||||||
|
libafl_cc = {path = "../../libafl_cc"}
|
||||||
|
libafl_nyx = {path = "../../libafl_nyx"}
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
57
fuzzers/nyx_libxml2_parallel/Makefile.toml
Normal file
57
fuzzers/nyx_libxml2_parallel/Makefile.toml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
# Variables
|
||||||
|
[env]
|
||||||
|
FUZZER_NAME='nyx_libxml2_parallel'
|
||||||
|
PROJECT_DIR = { script = ["pwd"] }
|
||||||
|
|
||||||
|
[config]
|
||||||
|
skip_core_tasks = true # skip `cargo test` to avoid error
|
||||||
|
|
||||||
|
[tasks.unsupported]
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
echo "Cargo-make not integrated yet on this platform"
|
||||||
|
'''
|
||||||
|
|
||||||
|
[tasks.build]
|
||||||
|
dependencies = [ "libxml2" ]
|
||||||
|
|
||||||
|
[tasks.libxml2]
|
||||||
|
linux_alias = "libxml2_unix"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.libxml2_unix]
|
||||||
|
# condition = { files_not_exist = ["./libxml2"]}
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
./setup_libxml2.sh
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Run the fuzzer
|
||||||
|
[tasks.run]
|
||||||
|
linux_alias = "run_unix"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.run_unix]
|
||||||
|
script_runner = "@shell"
|
||||||
|
script='''
|
||||||
|
cargo run
|
||||||
|
'''
|
||||||
|
dependencies = [ "libxml2" ]
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
[tasks.clean]
|
||||||
|
linux_alias = "clean_unix"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.clean_unix]
|
||||||
|
# Disable default `clean` definition
|
||||||
|
clear = true
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
make -C ./libxml2 clean
|
||||||
|
cargo clean
|
||||||
|
'''
|
15
fuzzers/nyx_libxml2_parallel/README.md
Normal file
15
fuzzers/nyx_libxml2_parallel/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
this example shows to use `libafl_nyx` to fuzz `libxml2`
|
||||||
|
|
||||||
|
# requirement
|
||||||
|
the following command will:
|
||||||
|
1. run `cargo build --release` to generate `libafl_cc`,`libafl_cxx`
|
||||||
|
2. download and extract `libxml2`
|
||||||
|
3. instruct `libxml2` using `libafl_cc` and `libafl_cxx`
|
||||||
|
4. prepare nyx shared dir and config file at `/tmp/nyx_libxml2`
|
||||||
|
5. open kvm support
|
||||||
|
```
|
||||||
|
./setup_libxml2.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
# run the fuzzer
|
||||||
|
use `cargo make run` to run the fuzzer. If you have setup all environment, you can use `cargo run` directly.
|
29
fuzzers/nyx_libxml2_parallel/setup_libxml2.sh
Executable file
29
fuzzers/nyx_libxml2_parallel/setup_libxml2.sh
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# cargo build --release
|
||||||
|
# PWD=$(pwd)
|
||||||
|
# export CC="$PWD/target/release/libafl_cc"
|
||||||
|
# export CXX="$PWD/target/release/libafl_cxx"
|
||||||
|
|
||||||
|
export CC=afl-clang-fast
|
||||||
|
export CXX=afl-clang-fast++
|
||||||
|
curl -C - https://gitlab.gnome.org/GNOME/libxml2/-/archive/v2.9.14/libxml2-v2.9.14.tar.gz --output libxml2-v2.9.14.tar.gz
|
||||||
|
tar -xf ./libxml2-v2.9.14.tar.gz --transform s/libxml2-v2.9.14/libxml2/ || exit
|
||||||
|
cd ./libxml2/ || exit
|
||||||
|
./autogen.sh --enable-shared=no || exit
|
||||||
|
make -j || exit
|
||||||
|
cd - || exit
|
||||||
|
python3 "../../libafl_nyx/packer/packer/nyx_packer.py" \
|
||||||
|
./libxml2/xmllint \
|
||||||
|
/tmp/nyx_libxml2 \
|
||||||
|
afl \
|
||||||
|
instrumentation \
|
||||||
|
-args "/tmp/input" \
|
||||||
|
-file "/tmp/input" \
|
||||||
|
--fast_reload_mode \
|
||||||
|
--purge || exit
|
||||||
|
|
||||||
|
python3 ../../libafl_nyx/packer/packer/nyx_config_gen.py /tmp/nyx_libxml2/ Kernel || exit
|
||||||
|
sudo modprobe -r kvm-intel # or kvm-amd for AMD
|
||||||
|
sudo modprobe -r kvm
|
||||||
|
sudo modprobe kvm enable_vmware_backdoor=y
|
||||||
|
sudo modprobe kvm-intel
|
34
fuzzers/nyx_libxml2_parallel/src/bin/libafl_cc.rs
Normal file
34
fuzzers/nyx_libxml2_parallel/src/bin/libafl_cc.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() > 1 {
|
||||||
|
let mut dir = env::current_exe().unwrap();
|
||||||
|
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
|
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||||
|
"cc" => false,
|
||||||
|
"++" | "pp" | "xx" => true,
|
||||||
|
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||||
|
};
|
||||||
|
|
||||||
|
dir.pop();
|
||||||
|
|
||||||
|
let mut cc = ClangWrapper::new();
|
||||||
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
|
.parse_args(&args)
|
||||||
|
.expect("Failed to parse the command line")
|
||||||
|
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||||
|
.run()
|
||||||
|
.expect("Failed to run the wrapped compiler")
|
||||||
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("LibAFL CC: No Arguments given");
|
||||||
|
}
|
||||||
|
}
|
5
fuzzers/nyx_libxml2_parallel/src/bin/libafl_cxx.rs
Normal file
5
fuzzers/nyx_libxml2_parallel/src/bin/libafl_cxx.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod libafl_cc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
libafl_cc::main();
|
||||||
|
}
|
104
fuzzers/nyx_libxml2_parallel/src/main.rs
Normal file
104
fuzzers/nyx_libxml2_parallel/src/main.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
bolts::{
|
||||||
|
core_affinity::Cores,
|
||||||
|
launcher::Launcher,
|
||||||
|
rands::{RandomSeed, StdRand},
|
||||||
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
|
tuples::tuple_list,
|
||||||
|
},
|
||||||
|
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus, Testcase},
|
||||||
|
events::EventConfig,
|
||||||
|
feedbacks::{CrashFeedback, MaxMapFeedback},
|
||||||
|
inputs::BytesInput,
|
||||||
|
monitors::MultiMonitor,
|
||||||
|
mutators::{havoc_mutations, StdScheduledMutator},
|
||||||
|
observers::StdMapObserver,
|
||||||
|
schedulers::RandScheduler,
|
||||||
|
stages::StdMutationalStage,
|
||||||
|
state::StdState,
|
||||||
|
Error, Fuzzer, StdFuzzer,
|
||||||
|
};
|
||||||
|
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
||||||
|
let broker_port = 7777;
|
||||||
|
|
||||||
|
let monitor = MultiMonitor::new(|s| println!("{}", s));
|
||||||
|
|
||||||
|
let cores = Cores::all().expect("unable to get all core id");
|
||||||
|
let parent_cpu_id = cores
|
||||||
|
.ids
|
||||||
|
.first()
|
||||||
|
.expect("unable to get first core id")
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
// region: fuzzer start function
|
||||||
|
let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id: usize| {
|
||||||
|
// nyx shared dir, created by nyx-fuzz/packer/packer/nyx_packer.py
|
||||||
|
let share_dir = Path::new("/tmp/nyx_libxml2/");
|
||||||
|
let cpu_id = _core_id as u32;
|
||||||
|
let parallel_mode = true;
|
||||||
|
// nyx stuff
|
||||||
|
let mut helper = NyxHelper::new(
|
||||||
|
share_dir,
|
||||||
|
cpu_id,
|
||||||
|
true,
|
||||||
|
parallel_mode,
|
||||||
|
Some(parent_cpu_id.id as u32),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let trace_bits =
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(helper.trace_bits, helper.map_size) };
|
||||||
|
let observer = StdMapObserver::new("trace", trace_bits);
|
||||||
|
|
||||||
|
let input = BytesInput::new(b"22".to_vec());
|
||||||
|
let rand = StdRand::new();
|
||||||
|
let mut corpus = CachedOnDiskCorpus::new(PathBuf::from("./corpus_discovered"), 64).unwrap();
|
||||||
|
corpus
|
||||||
|
.add(Testcase::new(input))
|
||||||
|
.expect("error in adding corpus");
|
||||||
|
let solutions = OnDiskCorpus::<BytesInput>::new(PathBuf::from("./crashes")).unwrap();
|
||||||
|
|
||||||
|
// libafl stuff
|
||||||
|
let mut feedback = MaxMapFeedback::new(&observer);
|
||||||
|
let mut objective = CrashFeedback::new();
|
||||||
|
let scheduler = RandScheduler::new();
|
||||||
|
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
|
||||||
|
|
||||||
|
// If not restarting, create a State from scratch
|
||||||
|
let mut state = state.unwrap_or_else(|| {
|
||||||
|
StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("We're a client, let's fuzz :)");
|
||||||
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
|
fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
match Launcher::builder()
|
||||||
|
.shmem_provider(shmem_provider)
|
||||||
|
.configuration(EventConfig::from_name("default"))
|
||||||
|
.monitor(monitor)
|
||||||
|
.run_client(&mut run_client)
|
||||||
|
.cores(&cores)
|
||||||
|
.broker_port(broker_port)
|
||||||
|
// .stdout_file(Some("/dev/null"))
|
||||||
|
.build()
|
||||||
|
.launch()
|
||||||
|
{
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(Error::ShuttingDown) => println!("Fuzzing stopped by user. Good bye."),
|
||||||
|
Err(err) => panic!("Failed to run launcher: {:?}", err),
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
}
|
15
fuzzers/nyx_libxml2_standalone/Cargo.toml
Normal file
15
fuzzers/nyx_libxml2_standalone/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "nyx_libxml2_standalone"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
default-run = "nyx_libxml2_standalone"
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = {path = "../../libafl"}
|
||||||
|
libafl_cc = {path = "../../libafl_cc"}
|
||||||
|
libafl_nyx = {path = "../../libafl_nyx"}
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
57
fuzzers/nyx_libxml2_standalone/Makefile.toml
Normal file
57
fuzzers/nyx_libxml2_standalone/Makefile.toml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
# Variables
|
||||||
|
[env]
|
||||||
|
FUZZER_NAME='nyx_libxml2_standalone'
|
||||||
|
PROJECT_DIR = { script = ["pwd"] }
|
||||||
|
|
||||||
|
[config]
|
||||||
|
skip_core_tasks = true # skip `cargo test` to avoid error
|
||||||
|
|
||||||
|
[tasks.unsupported]
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
echo "Cargo-make not integrated yet on this platform"
|
||||||
|
'''
|
||||||
|
|
||||||
|
[tasks.build]
|
||||||
|
dependencies = [ "libxml2" ]
|
||||||
|
|
||||||
|
[tasks.libxml2]
|
||||||
|
linux_alias = "libxml2_unix"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.libxml2_unix]
|
||||||
|
# condition = { files_not_exist = ["./libxml2"]}
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
./setup_libxml2.sh
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Run the fuzzer
|
||||||
|
[tasks.run]
|
||||||
|
linux_alias = "run_unix"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.run_unix]
|
||||||
|
script_runner = "@shell"
|
||||||
|
script='''
|
||||||
|
cargo run
|
||||||
|
'''
|
||||||
|
dependencies = [ "libxml2" ]
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
[tasks.clean]
|
||||||
|
linux_alias = "clean_unix"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.clean_unix]
|
||||||
|
# Disable default `clean` definition
|
||||||
|
clear = true
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
make -C ./libxml2 clean
|
||||||
|
cargo clean
|
||||||
|
'''
|
15
fuzzers/nyx_libxml2_standalone/README.md
Normal file
15
fuzzers/nyx_libxml2_standalone/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
this example shows to use `libafl_nyx` to fuzz `libxml2`
|
||||||
|
|
||||||
|
# requirement
|
||||||
|
the following command will:
|
||||||
|
1. run `cargo build --release` to generate `libafl_cc`,`libafl_cxx`
|
||||||
|
2. download and extract `libxml2`
|
||||||
|
3. instruct `libxml2` using `libafl_cc` and `libafl_cxx`
|
||||||
|
4. prepare nyx shared dir and config file at `/tmp/nyx_libxml2`
|
||||||
|
5. open kvm support
|
||||||
|
```
|
||||||
|
./setup_libxml2.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
# run the fuzzer
|
||||||
|
use `cargo make run` to run the fuzzer. If you have setup all environment, you can use `cargo run` directly.
|
29
fuzzers/nyx_libxml2_standalone/setup_libxml2.sh
Executable file
29
fuzzers/nyx_libxml2_standalone/setup_libxml2.sh
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# cargo build --release
|
||||||
|
# PWD=$(pwd)
|
||||||
|
# export CC="$PWD/target/release/libafl_cc"
|
||||||
|
# export CXX="$PWD/target/release/libafl_cxx"
|
||||||
|
|
||||||
|
export CC=afl-clang-fast
|
||||||
|
export CXX=afl-clang-fast++
|
||||||
|
curl -C - https://gitlab.gnome.org/GNOME/libxml2/-/archive/v2.9.14/libxml2-v2.9.14.tar.gz --output libxml2-v2.9.14.tar.gz
|
||||||
|
tar -xf ./libxml2-v2.9.14.tar.gz --transform s/libxml2-v2.9.14/libxml2/ || exit
|
||||||
|
cd ./libxml2/ || exit
|
||||||
|
./autogen.sh --enable-shared=no || exit
|
||||||
|
make -j || exit
|
||||||
|
cd - || exit
|
||||||
|
python3 "../../libafl_nyx/packer/packer/nyx_packer.py" \
|
||||||
|
./libxml2/xmllint \
|
||||||
|
/tmp/nyx_libxml2 \
|
||||||
|
afl \
|
||||||
|
instrumentation \
|
||||||
|
-args "/tmp/input" \
|
||||||
|
-file "/tmp/input" \
|
||||||
|
--fast_reload_mode \
|
||||||
|
--purge || exit
|
||||||
|
|
||||||
|
python3 ../../libafl_nyx/packer/packer/nyx_config_gen.py /tmp/nyx_libxml2/ Kernel || exit
|
||||||
|
sudo modprobe -r kvm-intel # or kvm-amd for AMD
|
||||||
|
sudo modprobe -r kvm
|
||||||
|
sudo modprobe kvm enable_vmware_backdoor=y
|
||||||
|
sudo modprobe kvm-intel
|
34
fuzzers/nyx_libxml2_standalone/src/bin/libafl_cc.rs
Normal file
34
fuzzers/nyx_libxml2_standalone/src/bin/libafl_cc.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() > 1 {
|
||||||
|
let mut dir = env::current_exe().unwrap();
|
||||||
|
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
|
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||||
|
"cc" => false,
|
||||||
|
"++" | "pp" | "xx" => true,
|
||||||
|
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||||
|
};
|
||||||
|
|
||||||
|
dir.pop();
|
||||||
|
|
||||||
|
let mut cc = ClangWrapper::new();
|
||||||
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
|
.parse_args(&args)
|
||||||
|
.expect("Failed to parse the command line")
|
||||||
|
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||||
|
.run()
|
||||||
|
.expect("Failed to run the wrapped compiler")
|
||||||
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("LibAFL CC: No Arguments given");
|
||||||
|
}
|
||||||
|
}
|
5
fuzzers/nyx_libxml2_standalone/src/bin/libafl_cxx.rs
Normal file
5
fuzzers/nyx_libxml2_standalone/src/bin/libafl_cxx.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod libafl_cc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
libafl_cc::main();
|
||||||
|
}
|
60
fuzzers/nyx_libxml2_standalone/src/main.rs
Normal file
60
fuzzers/nyx_libxml2_standalone/src/main.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
bolts::{
|
||||||
|
rands::{RandomSeed, StdRand},
|
||||||
|
tuples::tuple_list,
|
||||||
|
},
|
||||||
|
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus, Testcase},
|
||||||
|
events::SimpleEventManager,
|
||||||
|
feedbacks::{CrashFeedback, MaxMapFeedback},
|
||||||
|
inputs::BytesInput,
|
||||||
|
monitors::tui::TuiMonitor,
|
||||||
|
mutators::{havoc_mutations, StdScheduledMutator},
|
||||||
|
observers::StdMapObserver,
|
||||||
|
schedulers::RandScheduler,
|
||||||
|
stages::StdMutationalStage,
|
||||||
|
state::StdState,
|
||||||
|
Fuzzer, StdFuzzer,
|
||||||
|
};
|
||||||
|
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let share_dir = Path::new("/tmp/nyx_libxml2/");
|
||||||
|
let cpu_id = 0;
|
||||||
|
let parallel_mode = false;
|
||||||
|
|
||||||
|
// nyx stuff
|
||||||
|
let mut helper = NyxHelper::new(share_dir, cpu_id, true, parallel_mode, None).unwrap();
|
||||||
|
let trace_bits = unsafe { std::slice::from_raw_parts_mut(helper.trace_bits, helper.map_size) };
|
||||||
|
let observer = StdMapObserver::new("trace", trace_bits);
|
||||||
|
|
||||||
|
let input = BytesInput::new(b"22".to_vec());
|
||||||
|
let rand = StdRand::new();
|
||||||
|
let mut corpus = CachedOnDiskCorpus::new(PathBuf::from("./corpus_discovered"), 64).unwrap();
|
||||||
|
corpus
|
||||||
|
.add(Testcase::new(input))
|
||||||
|
.expect("error in adding corpus");
|
||||||
|
let solutions = OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap();
|
||||||
|
|
||||||
|
// libafl stuff
|
||||||
|
let mut feedback = MaxMapFeedback::new(&observer);
|
||||||
|
let mut objective = CrashFeedback::new();
|
||||||
|
let mut state = StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap();
|
||||||
|
let scheduler = RandScheduler::new();
|
||||||
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
|
// switch monitor if you want
|
||||||
|
// let monitor = SimpleMonitor::new(|x|-> () {println!("{}",x)});
|
||||||
|
let monitor = TuiMonitor::new("test_fuzz".to_string(), true);
|
||||||
|
|
||||||
|
let mut mgr: SimpleEventManager<BytesInput, _, _> = SimpleEventManager::new(monitor);
|
||||||
|
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
|
||||||
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
|
// start fuzz
|
||||||
|
fuzzer
|
||||||
|
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
|
||||||
|
.expect("error when fuzz");
|
||||||
|
}
|
2
libafl_nyx/.clang-format
Normal file
2
libafl_nyx/.clang-format
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
DisableFormat: true
|
||||||
|
SortIncludes: Never
|
19
libafl_nyx/Cargo.toml
Normal file
19
libafl_nyx/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "libafl_nyx"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["syheliel <syheliel@gmail.com>"]
|
||||||
|
description = "libafl using nyx, only avaliable on linux"
|
||||||
|
documentation = "https://docs.rs/libafl_nyx"
|
||||||
|
repository = "https://github.com/AFLplusplus/LibAFL/"
|
||||||
|
readme = "../README.md"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
keywords = ["fuzzing", "testing", "security"]
|
||||||
|
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
libnyx = {git = "https://github.com/nyx-fuzz/libnyx.git",rev = "acaf7f6"}
|
||||||
|
libafl = { path = "../libafl", version = "0.8.0", features = ["std", "libafl_derive", "frida_cli" ]}
|
||||||
|
libafl_targets = { path = "../libafl_targets", version = "0.8.0", features = ["std", "sancov_cmplog"] }
|
1
libafl_nyx/QEMU-Nyx
Submodule
1
libafl_nyx/QEMU-Nyx
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4df041cd8e886e5dee07a58bb3508860918ef908
|
5
libafl_nyx/README.md
Normal file
5
libafl_nyx/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
`libafl_nyx` is the `libafl`'s front-end for nyx fuzzer. This crate provides both the standalone mode and parallel mode:
|
||||||
|
- In standalone mode, no VM snapshot is serialized and stored in the working directory. That might be useful if you really want to run the fuzzer with only one process (meaning one VM).
|
||||||
|
- In parallel mode, the first fuzzer process (parent) has to create the VM snapshot while all other child processes will wait for the snapshot files to appear in the working directory.
|
||||||
|
|
||||||
|
In order to use this crate, you need to specify the shared directory and mode in `NyxHelper`, then use `NyxExecutor`. For more details, please see `./fuzzers/nyx_libxml2_standalone` and `./fuzzers/nyx_libxml2_parallel`.
|
18
libafl_nyx/build.rs
Normal file
18
libafl_nyx/build.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if cfg!(target_os = "linux") && cfg!(target_arch = "x86_64") {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
// let output = Command::new("./build_nyx_support.sh").output().expect("can't run ./build_nyx_support.sh");
|
||||||
|
let status = Command::new("./build_nyx_support.sh")
|
||||||
|
.status()
|
||||||
|
.expect("can't run ./build_nyx_support.sh");
|
||||||
|
if status.success() {
|
||||||
|
println!("success to run ./build_nyx_support.sh");
|
||||||
|
} else {
|
||||||
|
panic!("fail to run ./build_nyx_support.sh");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("cargo:warning=NYX node is only avaliable on x64 Linux");
|
||||||
|
}
|
||||||
|
}
|
39
libafl_nyx/build_nyx_support.sh
Executable file
39
libafl_nyx/build_nyx_support.sh
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "================================================="
|
||||||
|
echo " Nyx build script"
|
||||||
|
echo "================================================="
|
||||||
|
echo
|
||||||
|
|
||||||
|
|
||||||
|
echo "[*] Making sure all Nyx is checked out"
|
||||||
|
|
||||||
|
git status 1>/dev/null 2>/dev/null
|
||||||
|
|
||||||
|
git submodule init || exit 1
|
||||||
|
echo "[*] initializing QEMU-Nyx submodule"
|
||||||
|
git submodule update ./QEMU-Nyx 2>/dev/null # ignore errors
|
||||||
|
echo "[*] initializing packer submodule"
|
||||||
|
git submodule update ./packer 2>/dev/null # ignore errors
|
||||||
|
|
||||||
|
|
||||||
|
test -e packer/.git || { echo "[-] packer not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||||
|
test -e QEMU-Nyx/.git || { echo "[-] QEMU-Nyx not checked out, please install git or check your internet connection." ; exit 1 ; }
|
||||||
|
|
||||||
|
echo "[*] checking packer init.cpio.gz ..."
|
||||||
|
if [ ! -f "packer/linux_initramfs/init.cpio.gz" ]; then
|
||||||
|
cd packer/linux_initramfs/ || return
|
||||||
|
sh pack.sh || exit 1
|
||||||
|
cd ../../
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "[*] Checking QEMU-Nyx ..."
|
||||||
|
if [ ! -f "QEMU-Nyx/x86_64-softmmu/qemu-system-x86_64" ]; then
|
||||||
|
cd QEMU-Nyx/ || return
|
||||||
|
./compile_qemu_nyx.sh static || exit 1
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[+] All done for nyx_mode, enjoy!"
|
||||||
|
|
||||||
|
exit 0
|
1
libafl_nyx/packer
Submodule
1
libafl_nyx/packer
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 86b159bafc0b2ba8feeaa8761a45b6201d34084f
|
96
libafl_nyx/src/executor.rs
Normal file
96
libafl_nyx/src/executor.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use std::{fmt::Debug, marker::PhantomData};
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
|
inputs::{HasBytesVec, Input},
|
||||||
|
observers::ObserversTuple,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
use libnyx::NyxReturnValue;
|
||||||
|
|
||||||
|
use crate::helper::NyxHelper;
|
||||||
|
|
||||||
|
/// executor for nyx standalone mode
|
||||||
|
pub struct NyxExecutor<'a, I, S, OT> {
|
||||||
|
/// implement nyx function
|
||||||
|
pub helper: &'a mut NyxHelper,
|
||||||
|
/// observers
|
||||||
|
observers: OT,
|
||||||
|
/// phantom data to keep generic type <I,S>
|
||||||
|
phantom: PhantomData<(I, S)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, S, OT> Debug for NyxExecutor<'a, I, S, OT> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("NyxInprocessExecutor")
|
||||||
|
.field("helper", &self.helper)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, EM, I, S, Z, OT> Executor<EM, I, S, Z> for NyxExecutor<'a, I, S, OT>
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
{
|
||||||
|
fn run_target(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
) -> Result<libafl::executors::ExitKind, libafl::Error> {
|
||||||
|
let input = input.bytes();
|
||||||
|
self.helper.nyx_process.set_input(input, input.len() as u32);
|
||||||
|
|
||||||
|
// exec will take care of trace_bits, so no need to reset
|
||||||
|
let ret_val = self.helper.nyx_process.exec();
|
||||||
|
match ret_val {
|
||||||
|
NyxReturnValue::Normal => Ok(ExitKind::Ok),
|
||||||
|
NyxReturnValue::Crash | NyxReturnValue::Asan => Ok(ExitKind::Crash),
|
||||||
|
NyxReturnValue::Timeout => Ok(ExitKind::Timeout),
|
||||||
|
NyxReturnValue::InvalidWriteToPayload => Err(libafl::Error::illegal_state(
|
||||||
|
"FixMe: Nyx InvalidWriteToPayload handler is missing",
|
||||||
|
)),
|
||||||
|
NyxReturnValue::Error => Err(libafl::Error::illegal_state(
|
||||||
|
"Error: Nyx runtime error has occured...",
|
||||||
|
)),
|
||||||
|
NyxReturnValue::IoError => {
|
||||||
|
// todo! *stop_soon_p = 0
|
||||||
|
Err(libafl::Error::unknown("Error: QEMU-nyx died..."))
|
||||||
|
}
|
||||||
|
NyxReturnValue::Abort => {
|
||||||
|
self.helper.nyx_process.shutdown();
|
||||||
|
Err(libafl::Error::shutting_down())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, S, OT> NyxExecutor<'a, I, S, OT> {
|
||||||
|
pub fn new(helper: &'a mut NyxHelper, observers: OT) -> Result<Self, Error> {
|
||||||
|
Ok(Self {
|
||||||
|
helper,
|
||||||
|
observers,
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// convert `trace_bits` ptr into real trace map
|
||||||
|
pub fn trace_bits(self) -> &'static mut [u8] {
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(self.helper.trace_bits, self.helper.real_map_size) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, S, OT> HasObservers<I, OT, S> for NyxExecutor<'a, I, S, OT>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
{
|
||||||
|
fn observers(&self) -> &OT {
|
||||||
|
&self.observers
|
||||||
|
}
|
||||||
|
|
||||||
|
fn observers_mut(&mut self) -> &mut OT {
|
||||||
|
&mut self.observers
|
||||||
|
}
|
||||||
|
}
|
157
libafl_nyx/src/helper.rs
Normal file
157
libafl_nyx/src/helper.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/// [`NyxHelper`] is used to wrap `NyxProcess`
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Debug},
|
||||||
|
path::Path,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use libafl::Error;
|
||||||
|
use libnyx::{NyxProcess, NyxReturnValue};
|
||||||
|
|
||||||
|
const INIT_TIMEOUT: Duration = Duration::new(2, 0);
|
||||||
|
pub struct NyxHelper {
|
||||||
|
pub nyx_process: NyxProcess,
|
||||||
|
/// real size of trace_bits
|
||||||
|
pub real_map_size: usize,
|
||||||
|
// real size of the trace_bits
|
||||||
|
pub map_size: usize,
|
||||||
|
/// shared memory with instruction bitmaps
|
||||||
|
pub trace_bits: *mut u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_FILE: u32 = 1024 * 1024;
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum NyxProcessType {
|
||||||
|
/// stand alone mode
|
||||||
|
ALONE,
|
||||||
|
/// parallel mode's parent, used to create snapshot
|
||||||
|
PARENT,
|
||||||
|
/// parallel mode's child, consume snapshot and execute
|
||||||
|
CHILD,
|
||||||
|
}
|
||||||
|
impl NyxHelper {
|
||||||
|
/// create `NyxProcess` and do basic settings
|
||||||
|
/// It will convert instance to parent or child using `parent_cpu_id` when set`parallel_mode`
|
||||||
|
/// will fail if initial connection takes more than 2 seconds
|
||||||
|
pub fn new(
|
||||||
|
target_dir: &Path,
|
||||||
|
cpu_id: u32,
|
||||||
|
snap_mode: bool,
|
||||||
|
parallel_mode: bool,
|
||||||
|
parent_cpu_id: Option<u32>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
NyxHelper::new_with_initial_timeout(
|
||||||
|
target_dir,
|
||||||
|
cpu_id,
|
||||||
|
snap_mode,
|
||||||
|
parallel_mode,
|
||||||
|
parent_cpu_id,
|
||||||
|
INIT_TIMEOUT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/// create `NyxProcess` and do basic settings
|
||||||
|
/// It will convert instance to parent or child using `parent_cpu_id` when set`parallel_mode`
|
||||||
|
/// will fail if initial connection takes more than `initial_timeout` seconds
|
||||||
|
pub fn new_with_initial_timeout(
|
||||||
|
target_dir: &Path,
|
||||||
|
cpu_id: u32,
|
||||||
|
snap_mode: bool,
|
||||||
|
parallel_mode: bool,
|
||||||
|
parent_cpu_id: Option<u32>,
|
||||||
|
initial_timeout: Duration,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let sharedir = match target_dir.to_str() {
|
||||||
|
Some(x) => x,
|
||||||
|
None => return Err(Error::illegal_argument("can't convert sharedir to str")),
|
||||||
|
};
|
||||||
|
let work_dir = target_dir.join("workdir");
|
||||||
|
let work_dir = work_dir.to_str().expect("unable to convert workdir to str");
|
||||||
|
let nyx_type = if parallel_mode {
|
||||||
|
let parent_cpu_id = match parent_cpu_id {
|
||||||
|
None => {
|
||||||
|
return Err(Error::illegal_argument(
|
||||||
|
"please set parent_cpu_id in nyx parallel mode",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Some(x) => x,
|
||||||
|
};
|
||||||
|
if cpu_id == parent_cpu_id {
|
||||||
|
NyxProcessType::PARENT
|
||||||
|
} else {
|
||||||
|
NyxProcessType::CHILD
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NyxProcessType::ALONE
|
||||||
|
};
|
||||||
|
|
||||||
|
let nyx_process = match nyx_type {
|
||||||
|
NyxProcessType::ALONE => NyxProcess::new(sharedir, work_dir, cpu_id, MAX_FILE, true),
|
||||||
|
NyxProcessType::PARENT => {
|
||||||
|
NyxProcess::new_parent(sharedir, work_dir, cpu_id, MAX_FILE, true)
|
||||||
|
}
|
||||||
|
NyxProcessType::CHILD => NyxProcess::new_child(sharedir, work_dir, cpu_id, cpu_id),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut nyx_process =
|
||||||
|
nyx_process.map_err(|msg: String| -> Error { Error::illegal_argument(msg) })?;
|
||||||
|
|
||||||
|
let real_map_size = nyx_process.bitmap_buffer_size();
|
||||||
|
let map_size = ((real_map_size + 63) >> 6) << 6;
|
||||||
|
let trace_bits = nyx_process.bitmap_buffer_mut().as_mut_ptr();
|
||||||
|
nyx_process.option_set_reload_mode(snap_mode);
|
||||||
|
nyx_process.option_apply();
|
||||||
|
|
||||||
|
// default timeout for initial dry-run
|
||||||
|
let sec = initial_timeout
|
||||||
|
.as_secs()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| -> Error { Error::illegal_argument("can't cast time's sec to u8") })?;
|
||||||
|
|
||||||
|
let micro_sec: u32 = initial_timeout.subsec_micros();
|
||||||
|
nyx_process.option_set_timeout(sec, micro_sec);
|
||||||
|
nyx_process.option_apply();
|
||||||
|
|
||||||
|
// dry run to check if qemu is spawned
|
||||||
|
nyx_process.set_input(b"INIT", 4);
|
||||||
|
match nyx_process.exec() {
|
||||||
|
NyxReturnValue::Error => {
|
||||||
|
nyx_process.shutdown();
|
||||||
|
let msg = "Error: Nyx runtime error has occured...";
|
||||||
|
return Err(Error::illegal_state(msg));
|
||||||
|
}
|
||||||
|
NyxReturnValue::IoError => {
|
||||||
|
let msg = "Error: QEMU-nyx died...";
|
||||||
|
return Err(Error::illegal_state(msg));
|
||||||
|
}
|
||||||
|
NyxReturnValue::Abort => {
|
||||||
|
nyx_process.shutdown();
|
||||||
|
let msg = "Error: Nyx abort occured...";
|
||||||
|
return Err(Error::illegal_state(msg));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
nyx_process,
|
||||||
|
real_map_size,
|
||||||
|
map_size,
|
||||||
|
trace_bits,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set timeout
|
||||||
|
pub fn set_timeout(mut self, time: Duration) {
|
||||||
|
let sec: u8 = time
|
||||||
|
.as_secs()
|
||||||
|
.try_into()
|
||||||
|
.expect("can't cast time's sec to u8");
|
||||||
|
let micro_sec: u32 = time.subsec_micros();
|
||||||
|
self.nyx_process.option_set_timeout(sec, micro_sec);
|
||||||
|
self.nyx_process.option_apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for NyxHelper {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("NyxInprocessHelper").finish()
|
||||||
|
}
|
||||||
|
}
|
4
libafl_nyx/src/lib.rs
Normal file
4
libafl_nyx/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub mod executor;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub mod helper;
|
@ -28,6 +28,26 @@ declare -A time_record || (echo "declare -A not avaliable, please update your ba
|
|||||||
# shellcheck disable=SC2116
|
# shellcheck disable=SC2116
|
||||||
for fuzzer in $(echo "$fuzzers" "$backtrace_fuzzers");
|
for fuzzer in $(echo "$fuzzers" "$backtrace_fuzzers");
|
||||||
do
|
do
|
||||||
|
# for nyx examples
|
||||||
|
if [[ $fuzzer == *"nyx_"* ]]; then
|
||||||
|
|
||||||
|
# only test on linux
|
||||||
|
if [[ $(uname -s) == "Linux" ]]; then
|
||||||
|
cd "$fuzzer" || exit 1
|
||||||
|
if [ "$1" != "--no-fmt" ]; then
|
||||||
|
echo "[*] Checking fmt for $fuzzer"
|
||||||
|
cargo fmt --all -- --check || exit 1
|
||||||
|
echo "[*] Running clippy for $fuzzer"
|
||||||
|
cargo clippy || exit 1
|
||||||
|
else
|
||||||
|
echo "[+] Skipping fmt and clippy for $fuzzer (--no-fmt specified)"
|
||||||
|
fi
|
||||||
|
cargo make build
|
||||||
|
cd - || exit
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
cd "$fuzzer" || exit 1
|
cd "$fuzzer" || exit 1
|
||||||
start=$(date +%s)
|
start=$(date +%s)
|
||||||
# Clippy checks
|
# Clippy checks
|
||||||
|
Loading…
x
Reference in New Issue
Block a user