Skip to content

Commit b01b6ef

Browse files
authored
Merge pull request #46 from Evian-Zhang/c-binding-and-toml
Add C header and several improvements
2 parents 9185bc9 + f7b42a9 commit b01b6ef

File tree

7 files changed

+149
-43
lines changed

7 files changed

+149
-43
lines changed

.github/workflows/ci.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,19 @@ jobs:
9999
TOKEN: ${{ secrets.CRATES_IO_KEY }}
100100
run: |
101101
cargo login $TOKEN && cargo test && cargo publish
102+
103+
fmt-check:
104+
runs-on: ubuntu-latest
105+
steps:
106+
- uses: actions/checkout@v4
107+
- name: Cargo fmt
108+
run: cargo fmt --check
109+
110+
fmt-toml-check:
111+
runs-on: ubuntu-latest
112+
steps:
113+
- name: Install taplo
114+
run: cargo install taplo-cli --locked
115+
- uses: actions/checkout@v4
116+
- name: Run taplo
117+
run: taplo format --check

.github/workflows/py.yaml

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,14 @@ jobs:
1616
- {
1717
os: ubuntu-latest,
1818
arch: x64,
19-
python-ver: '3.8',
20-
name: 'manylinux2014_x86_64'
19+
python-version: 'cp38',
20+
name: 'manylinux_x86_64'
2121
}
2222
- {
2323
os: ubuntu-latest,
2424
arch: x32,
25-
python-ver: '3.8',
26-
name: 'manylinux2014_i686'
27-
}
28-
- {
29-
os: ubuntu-latest,
30-
arch: x64,
31-
python-ver: '3.8',
32-
name: 'sdist'
25+
python-version: 'cp38',
26+
name: 'manylinux_i686'
3327
}
3428
# - {
3529
# os: macos-latest,
@@ -38,6 +32,8 @@ jobs:
3832
# name: 'macos_x86_64'
3933
# }
4034
steps:
35+
- uses: actions/checkout@v4
36+
4137
- name: set up python
4238
uses: actions/setup-python@v4
4339
with:
@@ -51,19 +47,19 @@ jobs:
5147
- name: Setup Rust cache
5248
uses: Swatinem/rust-cache@v2
5349
with:
54-
key: ${{ matrix.alt_arch_name }}
50+
key: ${{ matrix.config.alt_arch_name }}
5551

5652
- name: Get pip cache dir
5753
id: pip-cache
58-
if: matrix.os != 'windows-latest'
54+
if: matrix.config.os != 'windows-latest'
5955
run: |
6056
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
6157
6258
- name: Cache python dependencies
6359
uses: actions/cache@v3
6460
with:
6561
path: ${{ steps.pip-cache.outputs.dir || steps.pip-cache-win.outputs.dir }}
66-
key: ${{ runner.os }}-pip-${{ matrix.python-version }}
62+
key: ${{ runner.os }}-pip-${{ matrix.config.python-version }}
6763

6864
- name: install python dependencies
6965
run: pip install -U setuptools wheel twine cibuildwheel platformdirs
@@ -82,34 +78,37 @@ jobs:
8278
uses: actions/cache@v3
8379
with:
8480
path: ${{ steps.cibuildwheel-cache.outputs.dir }}
85-
key: ${{ runner.os }}-cibuildwheel-${{ matrix.python-version }}
81+
key: ${{ runner.os }}-cibuildwheel-${{ matrix.config.python-version }}
8682

8783
- name: build sdist
88-
if: matrix.os == 'ubuntu' && matrix.python-version == 'cp310'
84+
if: matrix.config.os == 'ubuntu-latest' && matrix.config.python-version == 'cp38'
8985
run: |
9086
pip install maturin build
9187
python -m build --sdist -o wheelhouse
9288
93-
- name: build ${{ matrix.platform || matrix.os }} binaries
89+
- name: build ${{ matrix.config.platform || matrix.config.os }} binaries
9490
run: cibuildwheel --output-dir wheelhouse
9591
env:
96-
CIBW_BUILD: '${{ matrix.python-version }}-*'
92+
CIBW_BUILD: '${{ matrix.config.python-version }}-${{ matrix.config.name }}'
9793
# rust doesn't seem to be available for musl linux on i686
9894
CIBW_SKIP: '*-musllinux_i686'
9995
# we build for "alt_arch_name" if it exists, else 'auto'
100-
CIBW_ARCHS: ${{ matrix.alt_arch_name || 'auto' }}
96+
CIBW_ARCHS: ${{ matrix.config.alt_arch_name || 'auto' }}
10197
CIBW_ENVIRONMENT: 'PATH="$HOME/.cargo/bin:$PATH" CARGO_TERM_COLOR="always"'
10298
CIBW_ENVIRONMENT_WINDOWS: 'PATH="$UserProfile\.cargo\bin;$PATH"'
99+
# These are needed for Unicorn and cbindgen
100+
CIBW_BEFORE_ALL: >
101+
yum update -y && yum install -y llvm llvm-devel clang clang-devel libtool glib2-devel meson ninja-build bison flex
103102
CIBW_BEFORE_BUILD: rustup show
104103
CIBW_BEFORE_BUILD_LINUX: >
105104
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain=stable --profile=minimal -y &&
106105
rustup show
107-
CIBW_TEST_COMMAND: 'pytest {project}/test'
108-
CIBW_TEST_REQUIRES: pytest requests
109-
CIBW_TEST_SKIP: '*-macosx_arm64 *-macosx_universal2:arm64'
106+
# CIBW_TEST_COMMAND: 'pytest {project}/test'
107+
# CIBW_TEST_REQUIRES: pytest requests
108+
# CIBW_TEST_SKIP: '*-macosx_arm64 *-macosx_universal2:arm64'
110109
CIBW_BUILD_VERBOSITY: 1
111110

112-
- run: ${{ matrix.ls || 'ls -lh' }} wheelhouse/
111+
- run: ${{ matrix.config.ls || 'ls -lh' }} wheelhouse/
113112

114113
- name: '📤 Upload artifact'
115114
uses: actions/upload-artifact@v4
@@ -131,4 +130,4 @@ jobs:
131130
uses: pypa/gh-action-pypi-publish@master
132131
with:
133132
user: __token__
134-
password: ${{ secrets.pypi_pass }}
133+
password: ${{ secrets.pypi_pass }}

Cargo.toml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,35 @@ rust-version = "1.87"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
# Unreleased 0.15.3
10-
libafl_targets = { git = "https://github.com/AFLplusplus/LibAFL", features = [
11-
"pointer_maps", "forkserver", "cmplog", "cmplog_extended_instrumentation"], rev = "d5ecf7304dbd377df94d08aed658199eed2956af"}
12-
libafl = { git = "https://github.com/AFLplusplus/LibAFL", rev = "d5ecf7304dbd377df94d08aed658199eed2956af"}
13-
libafl_bolts = { git = "https://github.com/AFLplusplus/LibAFL", rev = "d5ecf7304dbd377df94d08aed658199eed2956af"}
9+
libafl_targets = { version = "0.15.3", features = [
10+
"pointer_maps",
11+
"forkserver",
12+
"cmplog",
13+
"cmplog_extended_instrumentation",
14+
] }
15+
libafl = "0.15.3"
16+
libafl_bolts = "0.15.3"
1417

15-
serde ={ version = "1.0", features = ["derive"] }
16-
unicorn-engine = { git = "https://github.com/unicorn-engine/unicorn", branch = "dev"}
18+
serde = { version = "1.0", features = ["derive"] }
19+
unicorn-engine = { git = "https://github.com/unicorn-engine/unicorn", branch = "dev" }
1720
log = "0.4"
1821
nix = { version = "0.29", features = ["signal"] }
1922
env_logger = { version = "0.11", optional = true }
20-
pyo3 = { version = "0.24.0", features = ["extension-module"], optional = true}
21-
pyo3-log = { version = "0.12.2", optional = true}
23+
pyo3 = { version = "0.24.0", features = ["extension-module"], optional = true }
24+
pyo3-log = { version = "0.12.2", optional = true }
2225

2326
[features]
2427
default = []
2528
bindings = ["unicorn-engine/dynamic_linkage", "pyo3", "pyo3-log", "env_logger"]
2629

2730
[lib]
2831
name = "unicornafl"
29-
crate-type = ["cdylib", "rlib"] # For python
32+
crate-type = ["cdylib", "staticlib", "rlib"] # For python
3033

3134
[[example]]
3235
name = "sample"
36+
37+
[profile.release]
38+
lto = true
39+
codegen-units = 1
40+
strip = true

examples/sample.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,5 @@ fn main() {
7575
};
7676

7777
let input_file = input_file.map(PathBuf::from);
78-
afl_fuzz(uc, input_file, place_input_cb, exits, false, Some(1)).expect("fail to fuzz?")
78+
afl_fuzz(uc, input_file, place_input_cb, exits, Some(1)).expect("fail to fuzz?")
7979
}

include/unicornafl.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#ifndef UNICORNAFL_H
2+
#define UNICORNAFL_H
3+
4+
#include "unicorn/unicorn.h"
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
#ifdef __GNUC__
11+
#define UNICORNAFL_EXPORT __attribute__((visibility("default")))
12+
#else
13+
#define UNICORNAFL_EXPORT
14+
#endif
15+
16+
#define MIN_UC_VERSION 0x02000100
17+
18+
typedef enum uc_afl_ret {
19+
UC_AFL_RET_OK = 0,
20+
UC_AFL_RET_ERROR,
21+
UC_AFL_RET_CHILD,
22+
UC_AFL_RET_NO_AFL,
23+
UC_AFL_RET_CALLED_TWICE,
24+
UC_AFL_RET_FINISHED,
25+
UC_AFL_RET_INVALID_UC,
26+
UC_AFL_RET_UC_ERR,
27+
UC_AFL_RET_LIBAFL,
28+
UC_AFL_RET_FFI,
29+
} uc_afl_ret;
30+
31+
typedef bool (*uc_afl_cb_place_input_t)(uc_engine* uc, char* input,
32+
size_t input_len,
33+
uint32_t persistent_round, void* data);
34+
35+
typedef bool (*uc_afl_cb_validate_crash_t)(uc_engine* uc, uc_err unicorn_result,
36+
char* input, int input_len,
37+
int persistent_round, void* data);
38+
39+
typedef uc_err (*uc_afl_fuzz_cb_t)(uc_engine *uc, void *data);
40+
41+
//
42+
// Start our fuzzer.
43+
//
44+
// If no afl-fuzz instance is found, this function is almost identical to uc_emu_start()
45+
//
46+
// @uc: The uc_engine return-ed from uc_open().
47+
// @input_file: This usually is the input file name provided by the command argument.
48+
// @place_input_callback: This callback is triggered every time a new child is generated. It returns
49+
// true if the input is accepted, or the input would be skipped.
50+
// @exits: All possible exits.
51+
// @exit_count: The count of the @exits array.
52+
// @validate_crash_callback: This callback is triggered every time to check if we are crashed.
53+
// @always_validate: If this is set to False, validate_crash_callback will be only triggered if
54+
// uc_emu_start (which is called internally by uc_afl_fuzz) returns an error. Or
55+
// the validate_crash_callback will be triggered every time.
56+
// @persistent_iters: Fuzz how many times before forking a new child.
57+
// @data: The extra data user provides.
58+
//
59+
// @uc_afl_ret: The error the fuzzer returns.
60+
UNICORNAFL_EXPORT
61+
uc_afl_ret uc_afl_fuzz(uc_engine* uc, char* input_file,
62+
uc_afl_cb_place_input_t place_input_callback,
63+
uint64_t* exits, size_t exit_count,
64+
uc_afl_cb_validate_crash_t validate_crash_callback,
65+
bool always_validate, uint32_t persistent_iters,
66+
void* data);
67+
68+
//
69+
// By default, uc_afl_fuzz internall calls uc_emu_start only once and if uc_emu_stop
70+
// is called, the child will stop fuzzing current test case.
71+
//
72+
// To implement more complex fuzzing logic, pass an extra fuzzing_callback with this API.
73+
//
74+
UNICORN_EXPORT
75+
uc_afl_ret uc_afl_fuzz_custom(uc_engine* uc, char* input_file,
76+
uc_afl_cb_place_input_t place_input_callback,
77+
uc_afl_fuzz_cb_t fuzz_callbck,
78+
uc_afl_cb_validate_crash_t validate_crash_callback,
79+
bool always_validate, uint32_t persistent_iters,
80+
void* data);
81+
82+
#ifdef __cplusplus
83+
}
84+
#endif
85+
86+
#endif

pyproject.toml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ build-backend = "maturin"
66
name = "unicornafl"
77
requires-python = ">=3.8"
88
classifiers = [
9-
"Programming Language :: Rust",
10-
"Programming Language :: Python :: Implementation :: CPython",
11-
"Programming Language :: Python :: Implementation :: PyPy",
9+
"Programming Language :: Rust",
10+
"Programming Language :: Python :: Implementation :: CPython",
11+
"Programming Language :: Python :: Implementation :: PyPy",
1212
]
1313
dynamic = ["version"]
14-
dependencies = [
15-
"unicorn>=2.1.3"
16-
]
14+
dependencies = ["unicorn>=2.1.3"]
1715

1816
[tool.maturin]
1917
bindings = "pyo3"
2018
manifest-path = "Cargo.toml"
2119
features = ["bindings"]
22-
python-source = "python"
20+
python-source = "python"

src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ pub fn afl_fuzz<'a, D: 'a>(
102102
input_file: Option<PathBuf>,
103103
place_input_cb: impl FnMut(&mut Unicorn<'a, UnicornFuzzData<D>>, &[u8], u64) -> bool + 'a,
104104
exits: Vec<u64>,
105-
always_validate: bool,
106105
persistent_iters: Option<u64>,
107106
) -> Result<(), uc_afl_ret> {
108107
afl_fuzz_custom(
@@ -114,7 +113,7 @@ pub fn afl_fuzz<'a, D: 'a>(
114113
target::dummy_uc_fuzz_callback,
115114
),
116115
exits,
117-
always_validate,
116+
false,
118117
persistent_iters,
119118
)
120119
}

0 commit comments

Comments
 (0)