Compare commits

...

893 Commits
0.3.0 ... fret

Author SHA1 Message Date
798aa2ceb9 remove dead code 2023-06-02 10:00:13 +02:00
183ff32beb igonre archives 2023-06-02 08:32:23 +02:00
89979b64d9 eval script wrangeling 2023-05-27 13:19:19 +02:00
35da9fdf24 HACK: interrupt limit for random fuzzing 2023-05-25 08:40:43 +02:00
1bca346b39 plot enpoints 2023-05-25 08:39:47 +02:00
8b90886299 paralellize plots 2023-05-23 12:06:14 +02:00
1bd7d853ac update plot script 2023-05-11 12:56:12 +02:00
253048e534 tweak time outputs 2023-05-10 09:25:22 +02:00
52cc00fedc add run_until_saturation 2023-05-08 18:23:32 +02:00
eec998c426 update snakefile 2023-05-04 11:47:56 +02:00
a328ddfd5f fix empty iterator crash, restart 2023-05-02 09:41:53 +02:00
6a042da5c1 set up configurations 2023-04-28 13:11:48 +02:00
2e20a22dc6 add missing use 2023-04-27 13:36:01 +02:00
bbc83ef6be randomize interrupts until wort 2023-04-24 15:33:03 +02:00
48466ac2d7 Test: remove pc from hash 2023-04-24 12:52:29 +02:00
ad8cecdba4 Test: hash notification states 2023-04-24 12:51:09 +02:00
c2afc0186e allow plotting from remote mount 2023-04-24 11:16:10 +02:00
4df67db479 update snakefile 2023-04-24 11:12:38 +02:00
402eff7b47 small fixes 2023-04-21 17:22:22 +02:00
a8a6c175c8 WIP: add simple interrupt time randomizer 2023-04-21 17:11:18 +02:00
8a79e12f91 update target_symbols 2023-04-21 14:12:04 +02:00
a3e38b6abb skip unchanged interrupts 2023-04-20 16:50:23 +02:00
eb04325f09 fix staeg setup 2023-04-20 16:32:19 +02:00
cfb8fa2b32 fix use 2023-04-20 16:04:45 +02:00
2889e9bf61 WIP: move interrupt mutation to new stage 2023-04-20 15:50:22 +02:00
960764cf85 wip: interrupt placement 2023-04-17 17:33:21 +02:00
e6816cc2de add interrupt mutator 2023-04-17 09:50:18 +02:00
f3180a35cc plot min and max lines 2023-03-23 13:20:23 +01:00
54312b2577 plot lines instead of points 2023-03-22 16:10:19 +01:00
6d920fd962 fixes 2023-03-21 16:58:44 +01:00
281979ecd8 revert changes 2023-03-21 16:39:21 +01:00
c628afaa81 add generation based genetic testing 2023-03-21 16:34:05 +01:00
c548c6bc09 snakefile: dump cases, fix random fuzzing 2023-03-17 11:15:55 +01:00
6e8769907d add a new scheduler for systemtraces 2023-03-16 16:13:16 +01:00
bf639e42fa fix snakefile, symbols 2023-03-14 17:08:05 +01:00
a05ff97d0c seed rng from SEED_RANDOM 2023-03-13 14:45:21 +01:00
f09034b7fe determinism fixes, scheduler precision, restarts 2023-03-13 14:43:58 +01:00
d118eeacbd switch to native breakpoints 2023-03-13 12:19:24 +01:00
57fc441118 fix interrupt config 2023-03-09 17:21:26 +01:00
10b5fe8a74 fix rng seed 2023-03-09 10:53:40 +01:00
7f987b037d configure restarting manager 2023-03-09 10:16:08 +01:00
58be280a62 add micro_longint 2023-03-03 12:30:36 +01:00
3c586f5047 fuzz multiple interrupts 2023-03-02 15:30:53 +01:00
9336b932d0 rework plotting 2023-02-28 17:01:04 +01:00
e0f73778e2 add interrupt fuzzing 2023-02-27 10:39:52 +01:00
e5ac5ba825 dump time for showmap 2023-02-24 12:25:08 +01:00
2acf3ef301 add plotting to snakefile 2023-02-24 12:07:53 +01:00
28bac2a850 add feed_longest to record random cases 2023-02-23 22:33:13 +01:00
41586dd8b1 plotting: respect types 2023-02-23 22:28:25 +01:00
7420aabeeb change feedback order 2023-02-20 12:28:39 +01:00
d118ff0056 fix build 2023-02-19 19:25:43 +01:00
dfe4f713b9 fix feedbacks 2023-02-19 18:38:31 +01:00
f7a05d2a7c benchmark using snakemake 2023-02-16 22:56:43 +01:00
2593bdf42f trace_abbs and dump path 2023-02-15 09:17:48 +01:00
8c8ab7c44e add graph feedback 2023-02-10 13:46:07 +01:00
9cadc5d61c update input sizes, dump worstcase, benchmarking 2023-02-07 14:59:21 +01:00
594554eca0 remove address translations, extend plots 2023-01-26 14:03:18 +01:00
267309b954 add hists to plot script 2023-01-26 09:47:12 +01:00
35435fbd97 speed up random generation 2023-01-25 16:14:17 +01:00
8fcc54bbdd write out times over time 2023-01-25 14:55:04 +01:00
1f538f9834 add sytemstate sceduler, fuzz until time 2023-01-25 12:59:17 +01:00
ba01f600ee re-add system state fuzzing 2023-01-24 09:11:45 +01:00
2cb479581d add virtual edge to longest runs 2023-01-19 10:33:13 +01:00
1fbf948478 do not force generated inputs 2023-01-17 10:26:27 +01:00
6e1d5695e3 debug stuff 2023-01-17 10:18:24 +01:00
8d31196614 random seeds, better plots 2023-01-17 10:01:15 +01:00
4c90144db5 add more benchmarks 2023-01-13 16:05:43 +01:00
eeaf7eb43f exectime increase feedback 2023-01-11 16:09:06 +01:00
68c4887dad rename bin, allow random fuzzing 2023-01-09 13:53:32 +01:00
7ca2d43f3d benchmark with duration 2023-01-09 12:39:51 +01:00
9f97852e4a add benchmark scripts 2023-01-09 12:39:35 +01:00
f4e1990387 add systemstate feature and dump times 2023-01-05 17:34:53 +01:00
d936234976 fix multicore build 2023-01-05 13:35:51 +01:00
795fbff61a ignore artifacts 2023-01-05 13:31:33 +01:00
6a9df35e28 minimal changes 2023-01-05 13:30:24 +01:00
9b9fbc3677 add interrupt injection 2023-01-03 20:09:45 +01:00
decae09931 input length and read input pointer 2022-12-23 15:32:20 +01:00
b812e994a6 draft: add graph feedback 2022-12-19 18:14:52 +01:00
4587f442d0 add TimeMaximizerCorpusScheduler 2022-12-19 17:44:58 +01:00
c748fecbe2 add last api callsite to system state 2022-12-19 13:13:38 +01:00
7595d25192 libafl_qemu: add jmp instrumentation 2022-12-19 13:12:37 +01:00
79bca99cc7 WIP: add systemstate tracking 2022-12-15 15:23:07 +01:00
b07f7ccbca add arguments 2022-12-12 17:41:33 +01:00
e3f38edd0a get time from ClockTimeFeedback 2022-12-12 15:30:05 +01:00
6ad55e3b29 fixup 2022-12-12 15:16:45 +01:00
f7ee38ebb2 WIP: port fret 2022-12-12 14:58:28 +01:00
Andrea Fioraldi
50708f4d9c
Fast device+mem QEMU snapshots (#930)
* Simple fast root snapshots

* clippy

* epd

* mips
2022-12-12 10:49:44 +01:00
radl97
4e2e4eb5c0
Fix typos (#935) 2022-12-11 00:59:59 +01:00
Max Ammann
2f9b279428
[Windows] Handle crashes without exception (#912)
* Handle that exception_pointers can be null

* Fix formatting

* windows: Handle crashes without exception
2022-12-10 09:29:27 +09:00
Langston Barrett
f9eac18542
libafl: Remove set_initial, initial_mut from MapObserver trait (#932)
These methods force a `MapObserver` to own an initial value, but
there's no reason for this to be the case - If you don't need to allow a
dynamically-changeable initial value, it might be nice to use `<<Self as
MapObserver>::Entry as Default>::default()` everywhere and have the compiler
statically propagate that value.

Not a lot of code used these methods (which seems like a good argument that
they aren't a fundamental part of the inteface).
2022-12-08 10:25:18 +01:00
Langston Barrett
61aa764dc4
Fix documentation typos (#933)
* libafl: Fix documentation typo in Push stage

* libafl: Fix documentation typo in PowerSchedule
2022-12-07 06:54:48 +01:00
omergreen
abfd834e98
Fix FridaInstrumentationHelper bugs caused by moving it after creation (#931)
* move Transformer out of FridaInstrumentationHelper's fields and create it dynamically instead; wrap CoverageRuntime in Pin<Arc<RefCell>>

* Update helper.rs

* run cargo fmt

* switch Arc for Rc
2022-12-06 17:46:59 +01:00
Dominik Maier
68fbfc8914
Fix Clippy (#926)
* Fix clippy

* undo comment fmt

* add unstracked nyx files to gitignore

* fix

* windows, no_std

* fix

* fix

* more

* macos

* remove doctest

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2022-12-06 00:05:42 +09:00
Dongjia "toka" Zhang
ee58375ac5
Revert fuzzbench changes (#927) 2022-12-05 05:59:55 +09:00
Dongjia "toka" Zhang
5d7fd8f914
TinyInst Binary-Only fuzzing for Windows (#854)
* step1 for tinyinst

* step2: minimal executor

* updated libafl

* Tinyinst Update (#853)

* Mac OS Autotokens (#723)

* mac_tokens

* more

* win fix

* fmt

* fmt c

* Use nightly fmt (#728)

* Fix compilation for aarch64 qemu (#731)

Typo lead to fail to compile for arm64

* Simd Fix (#729)

* simd fix

* fmt

* Fixing readme & docs (#730)

* fix

* fix

* add

* add

* fmt

* 0.8.1 (#732)

* New Pass Manager Arguments (#724)

* new pm arguments

* enable abgeana's code

* Fix tui with 1 client (#734)

* unbreak tui with 1 client

* clippy

* Add core affinity support for FreeBSD (#736)

* 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>

* Fix spelling error (#745)

* OSX force_load option (#743)

* Update clang.rs

* fmt

* Add continous JSON Logging monitor (#738)

* Add simple JSON Monitor

* Add documentation

* Log global state

* Fix formatting

* Save state depending on closure outcome, have file opened all the time

* Make OnDiskJSONMonitor cloneable

* Switch to FnMut to allow stateful closures

* Use &mut M: Monitor for the closure

* Fix documentation of Rand::below (#747)

* Netopenbsd build fix (#746)

* core affinity netbsd implementation.

* openbsd build fix

* Fix autotokens doc (#751)

* fix

* remove wrong doc

* Simplification for netbsd-specific code (#750)

the cpuset api is already present in libc...

* Add test case minimising stage (tmin) (#735)

* add test case minimising stage

* general purpose minimiser impl, with fuzzer example

* reorganise, document, and other cleanup

* correct python API return value

* correct some docs

* nit: versioning in fuzzers

* ise -> ize

* Implement a corpus minimiser (cmin) (#739)

* initial try

* correct case where cull attempts to fetch non-existent corpus entries

* various on_remove, on_replace implementations

* ise -> ize (consistency), use TestcaseScore instead of rolling our own

* oops, feature gate

* documentation!

* link c++

* doc-nit: correction in opt explanation

don't write documentation at 0300

* better linking

* Skippable stage, generator wrapper for Grimoire (#748)

* Skippable stage, generator wrapper for Grimoire

* more fancy wrapper

* MapFeedback: Adding support for with_name() (#752)

* Adding support for with_name()

* Adding with_name() function description

* dragonflybsd build fix for core affinity. (#753)

supporting most of linux sched api here.

* CI for FreeBSD (#754)

* CI for FreeBSD

* rustup -y?

* fixed path, switched to clippy

* bsd don't source

* added llvm

* clippy

* more yml

* ?

* testing ci

* llvm?

* llvm??

* more llvm, more tests

* fixed testcase'

* mem limits

* more sudo

* reenable all the CI

* Fixes for new Clippy (#755)

* New Clippy fixes for QEMU (#757)

* Core affinity for FreeBSD pinning task to the wanted cpu (#756)

* Do not zero-init struct in QEMU (#758)

* New Clippy fixes for QEMU

* no need to 0-initialize mem

* clippy

* Add doc for libafl_nyx (#759)

Co-authored-by: syheliel <syheliel@gmail.com>

* Adjust NyxExecutor trait bound to HasTargetBytes from HasBytesVec (#760)

* adjust NyxExecutor trait bound to HasTargetBytes from HasBytesVec

* oops actually use HasTargetBytes instead

* libafl_frida: ASan hook adding Apple's memset_pattern* api. (#761)

* Fix cargo doc on windows (#762)

* add doc cfg

* fix nostd docs

* ignore CommandConfigurator doc test execution on non-unix platform

* add cargo doc step pipeline on windows platform

* Enable memset_patter ASan hooks for Apple on libafl_frida (#763)

* Fix forkserver options (#771)

* Stability improve (#773)

* initial

* add

* fmt & fix

* dbg remove

* clp

* clp

* more

* clippy

* del

* fix

* remove unused

* fix

* doc

* Fix doc (#780)

* Add track_stability option to CalibrationStage  (#781)

* add

* Update gramatron.rs

* Update emu.rs

* try

* clp

* Dump registers on freebsd x86_64 (#779)

* Illumos support (#775)

implementing core affinity too.

* Reduce clang warnings for version output in libafl_cc. (#778)

* Extend gramatron recursive mutator (#783)

* Dump registers on NetBSD amd64 (#786)

* Add support for ARMBE8 (#768)

* Changes to build QEMU out-of-tree so that we don't need to clone the repo for each feature combination we build

* Add be support to libafl_qemu

* More config tweaks

Co-authored-by: Your Name <you@example.com>

* [AFLplusplus/LibAFL] dump registers on OpenBSD amd64 (PR #787)

* dump registers on openbsd

* write_crash implementations

* Windows gdiplus (#789)

* Initial steps

* Harness code cleanup

* don't panic on linux in order not to break the CI

* formatting once again

* restored cfg unix to unbreak linux build

* Remove clang download from windows CI (#791)

* Attempt to remove clang 12 setup

* frida_gdiplus added to CI

* Gdiplus comments (#792)

* Attempt to remove clang 12 setup

* frida_gdiplus added to CI

* Redundancy note

* formatting again :\

* mistake of directory name

* Fix len miscalculation in grimoire string replace (#794)

* Fix len miscalculation in grimoire string replace

* ok Rust i was writing JS these days

Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>

* Fix doc typos (#796)

* Fix CI  (#798)

* bump (#799)

* Support for write_crash on netbsd (#788)

* Support for bolts::cpu::read_time_counter on arm64 (#790)

* Add ability to use virtual dispatch to StagesTuple (#801)

* Add ability to use virtual dispatch to stagesTuple

* Fix lint

* Adding CPSR register for arm qemu (#800)

* trying to add in observer

* writing test

* got up to running with instrumentation but i still need to get the map

* fixing fuzzer code

* adding tinyinst fuzzer

* adding ffi to store all the map data into vec.

* adding some new things

* adding somewhat state of how i would like it should work

* fixing some things

* alot of false positives.

* fixing before adding args

* updated to use FileInput!

* adding build script to pull tinyinst

* fixing git issue

* writing instruction to run how to run tinyinst fuzzer

Co-authored-by: Dongjia Zhang <tokazerkje@outlook.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: Phan Thanh Duy <phanthanhduypr@gmail.com>
Co-authored-by: Nicholas Lang <97475577+nicklangsysdig@users.noreply.github.com>
Co-authored-by: David CARLIER <devnexen@gmail.com>
Co-authored-by: syheliel <45957390+syheliel@users.noreply.github.com>
Co-authored-by: syheliel <syheliel@gmail.com>
Co-authored-by: Aiden Hall <AidenRHall@users.noreply.github.com>
Co-authored-by: Sönke <eknoes@users.noreply.github.com>
Co-authored-by: Sirui Mu <msrlancern@gmail.com>
Co-authored-by: Addison Crump <me@addisoncrump.info>
Co-authored-by: Patrick Gersch <gersch.patrick@gmail.com>
Co-authored-by: Teddy Heinen <teddy@heinen.dev>
Co-authored-by: Vincent <space_white@yahoo.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com>
Co-authored-by: Your Name <you@example.com>
Co-authored-by: expend20 <36543551+expend20@users.noreply.github.com>
Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>
Co-authored-by: Ben Davis <ben@thebendavis.net>
Co-authored-by: radl97 <radl97@users.noreply.github.com>

* fix

* fmt

* Submodule

* Submodule?

* Tinyinst Update V2 (#905)

* updated to lastest libafl

* going to replace tinyinst to more like jackalope with tinyinstrumentation

* fixing clippy

* keep working on cpp ffi. sad

* updating litecov to tinyinst. also start making our own litecov

* revert to map instead of list. not sure why its not working

* making fuzzer listobserver

* working with listobserver!:

* cleaning up

* adding cargo make run

* updating cargo for tinyinst

* updating readme

* readme, clippy

* fmt

* fmt

* fix

* fix

* docker

* fix

* fmt

Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: biazo <eric.l.biazo@gmail.com>
Co-authored-by: Phan Thanh Duy <phanthanhduypr@gmail.com>
Co-authored-by: Nicholas Lang <97475577+nicklangsysdig@users.noreply.github.com>
Co-authored-by: David CARLIER <devnexen@gmail.com>
Co-authored-by: syheliel <45957390+syheliel@users.noreply.github.com>
Co-authored-by: syheliel <syheliel@gmail.com>
Co-authored-by: Aiden Hall <AidenRHall@users.noreply.github.com>
Co-authored-by: Sönke <eknoes@users.noreply.github.com>
Co-authored-by: Sirui Mu <msrlancern@gmail.com>
Co-authored-by: Addison Crump <me@addisoncrump.info>
Co-authored-by: Patrick Gersch <gersch.patrick@gmail.com>
Co-authored-by: Teddy Heinen <teddy@heinen.dev>
Co-authored-by: Vincent <space_white@yahoo.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com>
Co-authored-by: Your Name <you@example.com>
Co-authored-by: expend20 <36543551+expend20@users.noreply.github.com>
Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>
Co-authored-by: Ben Davis <ben@thebendavis.net>
Co-authored-by: radl97 <radl97@users.noreply.github.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-04 19:04:06 +01:00
Dongjia "toka" Zhang
93d99beecf
[Windows] Setup ASAN death callback (#908)
* step 1

* i forgot to change this

* add handler

* doc

* fmt

* move to libafl_targets

* fix

* windows

* clp

* fix

* clp

* cfg

* fix

* clp

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-04 18:56:56 +01:00
Dongjia "toka" Zhang
cd8367d3e9
SIGINT handlers, and Release StateRestorer shmem (#894)
* drop not working

* why drop_in_place works but drop does not

* stop shmem leak

* don't kill -9 fuzzer

* don't put fuzzer background

* no &

* nostd

* fix

* fix

* windows, clippy

* fix

* fmt

* windows
2022-12-04 18:56:19 +01:00
omergreen
3bad100cb7
Handle broker-to-broker connection interruptions more gracefully (#921)
* Handle broker-to-broker connection interruptions more gracefully

Exit gracefully instead of panicking or getting stuck in infinite loops

* Run cargo-fmt
2022-12-04 18:55:55 +01:00
omergreen
c879a0a8d3
Fix frida ASAN incompatibility with mac m1 (#917)
Add MAP_JIT, and extract the writable portion of generate_instrumentation_blobs into AsanRuntime
2022-12-04 18:55:45 +01:00
Langston Barrett
2a2e70a636
Add ValueObserver, an observer for a single value (#923)
* libafl: ValueObserver, a simple and safe observer of a single value

* libafl: Generalize ValueObserver, don't force it to be a RefCell

There are other types with interior mutability that may be more suitable.

Add a few more methods, too.

* libafl: Use OwnedRef in ValueObserver

The previous version had ValueObserver take ownership, but that doesn't
actually work for working with types with interior mutability: both the
observer and the target need to take immutable references.

* libafl: ValueObserver shouldn't reset the contained value

Otherwise, it is useless for containing a `RefCell`.

* libafl: Add doctests to ValueObserver

* libafl: Fix clippy lints

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-04 18:55:04 +01:00
Dongjia "toka" Zhang
8444cf7cc8
Fix libafl_qemu i386 build (#924)
* fix

* fmt

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-12-04 15:07:30 +01:00
Andrea Fioraldi
71dd58396c
libafl_qemu_sys and libafl_qemu_build to have bindgen with QEMU (#915)
* build and sys qemu crates

* working libafl_qemu_build

* libafl_qemu_sys

* switch libafl_qemu to use libafl_qemu_sys

* fix

* use sys

* fmt

* mmu lookup

* fix

* autofix

* clippy

* fix

* allow

* cl

* docker

* docker

* fix

* mem access info in mem hooks

* fmt

* fix

* kill libafl_page_size

* fix

* clippy

* default bindings for docs.rs

* macos

* fix arm build

* fix

* plugins

* fix

* fix fuzzer

* Correct PC on breakpoint

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-02 17:01:28 +01:00
Addison Crump
5252097819
Fix scores in minimizer when using on_replace (#920) 2022-11-30 14:32:26 +01:00
Andrea Fioraldi
c2776e117a
emu::current_cpu() is now the CPU that hitted the breakpoint in fullsystem (#910)
* emu::current_cpu() is now kept after vm stop and it is the CPU that hitted the breakpoint

* clippy

* uninit

* clippy

* clippy

* clippy

* clippy

* nightly override in CI

* nightly override in CI

* components

* components

* targets

* targets

* clippy

* clippy

* clippy

* clippy

* clippy (again)

* MaybeUninit

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-11-25 11:57:08 +01:00
Langston Barrett
bc85129cd9
libafl_frida: Point to the LibAFL book from API docs (#886)
Help users find the docs!
2022-11-25 01:48:21 +01:00
omergreen
889161e55e
Fix mac m1 incompatibility for cmplog in frida mode (#914)
For some reason, Apple's aarch64 processor throws a SIGILL when encountering LDP x5, x5 (or any other repeating register). STP works, but I changed both for symmetry.
2022-11-25 01:31:22 +01:00
Andrea Fioraldi
3f627aaf0b
Save and restore CPU state in libafl_qemu (#907)
* libafl_qemu: fix systemmode with slirp dependency

libslirp will be dropped from future QEMU releases (see https://wiki.qemu.org/ChangeLog/7.0).
This change adds the "slirp" feature,
which links with the host-systems libslirp.

* libafl_qemu: enable systemmode snapshots, vm_start

Re-enable snapshot functions.
Start the VM before qemu_main_loop.

* libafl_qemu: allow synchronous snapshotting

Add a flag to take snapshots synchronosly.
This should be used to take or load snapshots while the emulator is not
running.

* libafl_qemu: fallback cpu for read-/write_mem

In systemmode, current_cpu may not be set.
In such cases use the first cpus memory access methods.

* fuzzers: add example for libafl_qemu in systemmode

* libafl_qemu: update libafl-qemu-bridge revision

* libafl_qemu: add memory access by physcial address

* fix liabfl_qemu example

Use GuestAddr and physical memory access

* ci: install libslirp-dev for libafl_qemu

* fuzzers/qemu_systemmode: clean up example

* libafl_qemu: remove obsolete functions

emu::libafl_cpu_thread_fn
emu::libafl_start_vcpu
emu::start

* fuzzers/qemu_systemmode: simplify example

* improve build_linux.rs

* Update qemu_systemmode fuzzer

* upd

* clippy

* Save and restore CPU state in libafl_qemu

* clippy

* Clone

* upd

* upd

Co-authored-by: Alwin Berger <alwin.berger@tu-dortmund.de>
2022-11-22 16:29:43 +01:00
Andrea Fioraldi
7b0039606b
Forksrv adaptive map size and AFL++ CmpLog support (#896)
* AFL++ cmplog map

* map size opt in forkserver

* MapObserver::downsize_map and adaptive map size in forkserver

* fix fokserver_simple cmd opts

* clippy

* fuzzbench forkserver with cmplog

* delete makefile in fuzzbench forkserver

* fuzzbench_forkserver is persistent

* ForkserverExecutorBuilder::build_dynamic_map

* fix

* clippy

* fix

* fix macos

* fix compilation

* fix bugs

* fixes

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
2022-11-22 10:33:15 +01:00
Alwin Berger
b33839708e
Fix QEMU systemmode fuzzing (#883)
* libafl_qemu: fix systemmode with slirp dependency

libslirp will be dropped from future QEMU releases (see https://wiki.qemu.org/ChangeLog/7.0).
This change adds the "slirp" feature,
which links with the host-systems libslirp.

* libafl_qemu: enable systemmode snapshots, vm_start

Re-enable snapshot functions.
Start the VM before qemu_main_loop.

* libafl_qemu: allow synchronous snapshotting

Add a flag to take snapshots synchronosly.
This should be used to take or load snapshots while the emulator is not
running.

* libafl_qemu: fallback cpu for read-/write_mem

In systemmode, current_cpu may not be set.
In such cases use the first cpus memory access methods.

* fuzzers: add example for libafl_qemu in systemmode

* libafl_qemu: update libafl-qemu-bridge revision

* libafl_qemu: add memory access by physcial address

* fix liabfl_qemu example

Use GuestAddr and physical memory access

* ci: install libslirp-dev for libafl_qemu

* fuzzers/qemu_systemmode: clean up example

* libafl_qemu: remove obsolete functions

emu::libafl_cpu_thread_fn
emu::libafl_start_vcpu
emu::start

* fuzzers/qemu_systemmode: simplify example

* improve build_linux.rs

* Update qemu_systemmode fuzzer

* upd

* clippy

Co-authored-by: Alwin Berger <alwin.berger@tu-dortmund.de>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-11-21 17:57:06 +01:00
Addison Crump
0515eebbd2
Differential observers (#868)
* reduce diffexecutor constraints for new (so it may be used in a manager-less environment)

* add differential observers

* finish differential observeration

* requirement for observers (weak), default impl for time observer

* make the map swapper, revisit how differentialobserver is implemented

* semi-specialise multimap, add example

* improve example slightly

* fix clippy lints

* fix last clippy issue

* better docs + example flow

* improve example: correct map sizing + multimap vs split slice

* correct some comments

* fix tests + slight bit more docs

* fix bindings

* fixups for the CI

* typo fix

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
2022-11-20 23:56:23 +01:00
Patrick Gersch
556789dffa
Adding DrCov for qemu (#878)
* Adding DrCov for qemu

* Fixing cargo fmt

* Trying to fix maturin build

* Fixing clippy

* libafl_qemu --no-default-features fix

* Adding make module mapping a user input as suggested from @WorksButNotTested

* Switching from blocks_raw() -> blocks() and full_tracing as an option

* Avoiding get before get_mut

* HashSet to Vec

* Avoiding lazy_static

* Adding DrCov for example fuzzer qemu_arm_launcher

* Removing mut for globals in DrCov

* Using emu.mappings() for drcov module mappings

* Fixing clippy

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2022-11-20 14:28:30 +01:00
Jorgecmartins
bd62cebd7e
Fix typo in observer.md (#904) 2022-11-20 14:28:03 +01:00
David CARLIER
32dc796234
Extend autotokens pass support to other unixes (#900) 2022-11-20 09:24:30 +01:00
Mrmaxmeier
ff2971068f
mopt: seed from state rand instead of current_nanos (#902) 2022-11-20 09:21:16 +01:00
julihoh
948c94d695
Update and fix concolic support (#901)
* fix incorrect assert condition and document it

* update symcc

* adapt to changes in symcc API

* more fixes

* fix formatting

* more fixes

* speed up smoke test by building multiple crates in one command

* update symcc commit to latest main
2022-11-19 23:05:15 +01:00
David CARLIER
f7f6392a4b
forkserver support attempt on freebsd (#898)
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2022-11-18 07:14:15 +09:00
David CARLIER
d77769540a
fixing freebsd unused import warning in core affinity. (#897)
fixing clang wrapper test passing llvm pass api support when there are actual passes.

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2022-11-17 10:28:22 +01:00
Dongjia "toka" Zhang
ec38858b2d
Fix Makefile.toml (#893)
* don't use submodules

* fix

* add

* fix

* a

* fix

* doesn't work 😩

* fix

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml
2022-11-17 04:44:26 +09:00
Dominik Maier
a22c76e02e
Improve Apple support for libafl_cc dll_extensions (#892) 2022-11-15 18:28:52 +01:00
Dominik Maier
2011ed299b
Pthread introspection hook (extends #263) (#891)
* Add pthread_introspection_hook support on macos

See-also: #68

* Remove lazy_static

* all of apple are created equal

Co-authored-by: Fabian Freyer <fabian.freyer@physik.tu-berlin.de>
2022-11-15 18:27:48 +01:00
Dominik Maier
e5aaf85d3c
Tuneable Stage, Scheduler, ScheduledMutator (#874)
* Tuneable Stage, Scheduler, and Mutators

* rename

* fix build

* get rid of prelude

* fmt

* Reworked tunable, fixed stuff, add testcase

* clippy

* further fixes

* fix typo, fmt
2022-11-12 03:02:54 +01:00
Andrea Fioraldi
fe459f6fa5
DumpOnDiskStage in fuzzbench_text to dump the grimoire inputs as bytes for the fuzzbench measurers (#869)
* FuzzbenchDumpStage in fuzzbench_text

* fix

* DumpOnDiskStage

* clippy

* removed duplicated code from example fuzzer

* shorthand to move OwnedSlice into vec

* clippy

* fiz

* fix missing semicolon

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
2022-11-11 17:38:48 +01:00
Dominik Maier
e340d35674
Add standalone toolchain link to frida_libpng (#890) 2022-11-11 16:06:38 +01:00
Lukas Seidel
17a0d9e8f0
Forkserver: Add file input support (#880)
* make use of clap derive in forkserver_simple

* (re)introduce use_shmem_testcase flag to ForkserverExecutor

* set use_shmem_testcase flag automatically based on forkserver handshake

* remove illegal_state and just .unwrap instead as the None case is unreachable

* fix: removed pub method

* cargo fmt

* remove illegal_state #2 and just .unwrap instead as the None case is unreachable

* change shmem unwrap to unwrap_unchecked

* fix double mut

* removed @@ warning
2022-11-10 15:25:52 +01:00
Dominik Maier
977415cad2
Reworked Book, add missing files (#888)
* Added missing links to docs

* Reworked docs

* Remove empty file

* remove Launcher info (that moved to spawn_instances)

* ignore more
2022-11-10 13:08:35 +01:00
Langston Barrett
893f284482
Use bytes, not strings, for stdio observers (#885)
Previously, the `CommandExecutor` attempted to decode its child
process's stdout and stderr as UTF-8 `String`s. This could fail
if the output was not UTF-8. However, the `Std{Out,Err}Observer`s
should probably be able to be used in such a situation - Consider
fuzzing `echo` with a random `BytesInput`.

The fix is to not decode the output, but rather directly store and
provide the bytes of stdout/stderr in the observers.
2022-11-10 12:40:59 +01:00
Dominik Maier
1486c204eb
Remove unused stage stub (#882)
* GetDeps Stage

* removed getdeps stage
2022-11-10 09:39:29 +01:00
Dominik Maier
6b6570ae5f
Use Associated Types for Has* traits and AsSlice (#881)
* More Associated Types

* AsSlice associated-ified

* added script to find unused files

* fixes for python

* build all the things

* windows fixes
2022-11-10 09:31:04 +01:00
Peter Whiting
18f288e2d3
Monitor to export fuzzer metrics to Prometheus server (#875)
* add custom monitor prometheus as a baseline to build functionality

* working server, set up function to update metrics in the registry

* for a test

* metrics for corpus count, objective count, executions, execution rate are intermittently updated and exposed on /metrics

* add runtime metric, clean up some comments

* IP:PORT as argument instead of hardcoded

* add client # as label attached to fuzzer metrics for filtering by client. add clients_count as a tracked metric

* added support for custom metrics added to client_stats via feedbacks, such as edges count. cleaned up code

* cargo fmt

* clean up prometheus.rs

* ran autofix and fmt scripts, and put optional dependencies behind prometheus_monitor feature

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-11-07 19:01:59 +01:00
Mrmaxmeier
8e6eaf7002
check_for_blobs.sh: respect gitignore (#876) 2022-11-05 23:30:26 +01:00
David CARLIER
b9bd0dd6b7
sort of fix core affinity on mac arm64 (#873)
* sort of fix core affinity on mac arm64
we can t pin to a coreid however we can at least choose the performance
cores for our thread.

* using other cores as well

* Fix CI yml (#871)

* Fix CI again (#872)

* Fix CI yml

* Fix CI

* Add dump_register/write_crash for freebsd arm64 (#870)

Co-authored-by: Dominik Maier <domenukk@gmail.com>

* Remove QEMU-Nyx & packer submodules

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2022-11-05 21:52:43 +09:00
Dongjia "toka" Zhang
dddfaf3f55
Remove QEMU-Nyx & packer submodules 2022-11-05 12:43:36 +09:00
David CARLIER
79fc952f53
Add dump_register/write_crash for freebsd arm64 (#870)
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-10-29 09:40:25 +02:00
Dominik Maier
ff945d9657
Fix CI again (#872)
* Fix CI yml

* Fix CI
2022-10-29 00:05:28 +02:00
Dominik Maier
17d0795f0d
Fix CI yml (#871) 2022-10-28 23:50:38 +02:00
Andrea Fioraldi
40269a578b
Delete blob and add CI check (#867)
* Delete blob and add CI check

* fix

* shellcheck
2022-10-27 16:20:29 +02:00
Andrea Fioraldi
ebdab32b36
Fix clap in fuzzbench fuzzers (#866) 2022-10-26 14:06:14 +02:00
Andrea Fioraldi
5da5997b20
Remove fuzzbench_weighted and update fuzzbench (#865) 2022-10-26 11:24:34 +02:00
David CARLIER
3054a69cf6
Dump_registers update on netbsd x86_64 arch. (#863) 2022-10-26 09:51:45 +02:00
Andrea Fioraldi
31077765de
Fix CI (#862)
* Autofix with new clippy

* Clippy
2022-10-26 09:41:08 +02:00
Patrick Gersch
cf9c4188c0
Disabling qemu dependecies for qemu fullsystem (#737)
* Disabling qemu dependecies by default

* Adding full emulation_mode support

* Removing usermode from libafl_qemu default features

* Fixing refactoring

* Fixing typo in systemmode

* Fixing clippy:needless-borrow

* Mark libafl_load/save_qemu_snapshot as unused + cpu_reset

* Fixing clippy::needless-borrow

* Fixing needless-borrow yet again

* reset_cpu -> cpu_reset

* Fixing github workflow yet again

* Fixing clippy::uninlined-format-args

* Adding current libafl_qemu_bridge

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-10-25 14:16:11 +02:00
Andrea Fioraldi
5571a03641
Implement thread-safe AsanGiovese in Rust with snapshots support (#851)
* Purge C impl of asan-giovese

* Compiling

* reset asan

* Restore asan state in qemu

* clippy

* upd

* Asan snapshots

* fuzzbench_qemu

* fix snap mmap limit

* fix

* compiles again

* clippy

* update meminterval

* autofix

* fix 32 bit targets

* try to clean intermediate builds

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-10-25 09:48:59 +02:00
Sönke
332c2bc3f8
Fix launcher to work with returning run_client functions (#860) 2022-10-24 21:40:24 +02:00
Andrea Fioraldi
1eb738695f
Fix stdio observer refactor (#859) 2022-10-24 13:50:11 +02:00
Dominik Maier
de99ee1340
Doc fix (#857) 2022-10-24 03:32:16 +02:00
Dominik Maier
663a33168e
Associated types for Corpus, State (#767)
* Associated types for Corpus, State

* cleanup

* fix no_std

* drop unused clauses

* Corpus

* cleanup

* adding things

* fixed fuzzer

* remove phantom data

* python

* progress?

* more more

* oof

* wow it builds?

* python fixes, tests

* fix python fun

* black fmt for python

* clippy, added Nop things

* fixes

* fix merge

* make it compile (#836)

* doc-test fixes, prelude-b-gone for cargo-hack compat

* fixes for windows, concolic

* really fix windows, maybe

* imagine using windows

* ...

* elide I generic when used with S: State

* Elide many, many generics, but at what cost?

* progress on push

* Constraint HasCorpus, HasSolutions at trait definition

* remove unused feature

* remove unstable usage since we constrained HasCorpus at definition

* compiled, but still no type inference for MaxMapFeedback

* cleanup inprocess

* resolve some std conflicts

* simplify map

* undo unnecessary cfg specification

* fix breaking test case for CI on no-std

* fix concolic build failures

* fix macos build

* fixes for windows build

* timeout fixes for windows build

* fix pybindings issues

* fixup qemu

* fix outstanding local build issues

* maybe fix windows inprocess

* doc fixes

* unbridled fury

* de-associate State from Feedback, replace with generic as AT inference is not sufficient to derive specialisation for MapFeedback

* merge update

* refactor + speed up fuzzer builds by sharing build work

* cleanup lingering compiler errors

* lol missed one

* revert QEMU-Nyx change, not sure how I did that

* move HasInput to inputs

* HasInput => KnowsInput

* update bounds to enforce via associated types

* disentangle observers with fuzzer

* revert --target; update some fuzzers to match new API

* resolve outstanding fuzzer build blockers (that I can run on my system)

* fixes for non-linux unixes

* fix for windows

* Knows => Uses, final fixes for windows

* <guttural screaming>

* fixes for concolic

* loosen bound for frida executor so windows builds correctly

* cleanup generics for eventmanager/eventprocessor to drop observers requirement

* improve inference over fuzz_one and friends

* update migration notes

* fixes for python bindings

* fixes for generic counts in event managers

* finish migration notes

* post-merge fix

Co-authored-by: Addison Crump <addison.crump@cispa.de>
2022-10-24 03:22:26 +02:00
Dominik Maier
9695ce0029
Refactor Output Observers (#856)
* Refactor Output Observers

* Delete .gitmodules

* modules

* Drop need for OutputObserving list
2022-10-24 02:50:00 +02:00
Dongjia "toka" Zhang
5b75b6b8ac
Set persistent mode env variables. (#852)
* persistnt mode envs

* clp

* clpgit add -u!
2022-10-23 20:35:35 +02:00
Alessandro Mantovani
0307dadcd1
Allow two different observers for DiffExecutor (#843)
* DifferentialExecutor for CommandExecutor along with StdIO observer

* format

* fix CI issues

* fix format and unit test

* fix documentation

* allow three structs and doc only for linux

* resolve documentation test failure

* minor

* running fmt_all.sh

* into_executor() takes 4 params, not just 1

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-10-23 01:59:40 +02:00
Mrmaxmeier
64bc5d5bdb
CI: speedups and fixes (#855)
* scripts/clippy.sh: remove cargo clean step

Clippy used to only report warnings in code that was not part of the
incremental cache. This has changed since and I believe we can safely
drop the `cargo clean` step.

* Revert "ci: install z3 to avoid building from source"

This reverts commit 6ff1c4088811040dcfdbd12273f0baf507a4308b.
This doesn't do anything as we're using `static-link-z3` explicitly.

* refactor test_all_fuzzers

nyx tests were not included in `time_record` before this

* nyx fuzzer: move modprobe logic out of setup_libxml2.sh
2022-10-23 01:58:33 +02:00
Dominik Maier
b035b70f4e
Expose OUT_DIR for compiler passes to other components (#840)
* Expose OUT_DIR for compiler passes to other components

* not updating nyx
2022-10-21 09:36:22 +02:00
Dongjia "toka" Zhang
64ec5c30ae
Fix aarch64 read_time_counter() (#849)
* Revert #790 Changes

* fmt

* fix?
2022-10-21 16:23:30 +09:00
Mrmaxmeier
cedcee01c0
CI: Build fuzzers with shared cargo target dir (#845)
* build fuzzers with shared cargo target dir

* Make external build scripts aware of CARGO_TARGET_DIR

* fix libmozjpeg fuzzer with shared target dir

* fix cargo-make default value for CARGO_TARGET_DIR

* avoid ./ in cargo-make for windows compat

* CI: cargo-hack's --feature-powerset is too powerful

* fuzzer_concolic: support CARGO_TARGET_DIR

* ci: install z3 to avoid building from source

* ci: update actions

* ci: test nightly features with nightly rust

* test_all_fuzzers: try pruning more compilation artifacts

* ci: fix nightly feature check

* ci: apply rust-cache action after checkout (d'oh)

The rust-cache action populates the checkout directory, which is promply
deleted by the checkout action during checkout.. whoops!
2022-10-20 21:38:58 +02:00
Andrea Fioraldi
4ccd85f568
Refactor QEMU snapshot helper and add mmap memory limit (#844)
* waiting for an interval tree...

* Rework QEMU user memory snapshots

* Fix pcrel to 1

* clippy

* clippy
2022-10-19 18:46:37 +02:00
Dominik Maier
41cc717dfc
Install no_std nightly toolchain for CI (#847) 2022-10-19 18:19:27 +02:00
Dominik Maier
28ab5e224b
Fix baby_no_std (#846)
* Fixing baby_no_std

* Fixed warnings for no_std

* Fix aarch build, clippy

* oops nyx again

* Using CString from alloc
2022-10-19 14:14:10 +02:00
Dominik Maier
e8b3d33bf4
Update dependencies, removed unused deps, CI fixes (#839)
* update clap, remove unused deps

* update grammartek

* update pyo3

* update pyo3

* undid clap update

* not changing nyx

* updated deps

* Update more deps, fixes

* not needed clippy

* fix windows

* try to enable deprecated pyproto for pyo3

* unused

* moving some things to clap4 after all

* initial move to clap 4

* fix clap

* more clap4, removed accidental file

* fixes, fmt

* fix

* all fix no play

* fix
2022-10-18 20:36:43 +02:00
Khangaroo
d6d4fa506b
Fix memory leaks and module instrumentation in frida_gdiplus (#841)
* Fix memory leaks and module instrumentation in frida_gdiplus

* Run clang-format
2022-10-17 10:02:45 +09:00
Dongjia "toka" Zhang
dee3bc4492
Fix windows timeout 2022-10-17 10:00:59 +09:00
R. Elliott Childre
96221f28df
Bump Nyx-QEMU to resolve GTK configuration (#837)
[This commit][1] in `nyx-fuzz` resolves the ambiguity between gtk being
included in the build which as is currently is enabled. Mentioned in
[this issue here][2]

[1]: https://github.com/nyx-fuzz/QEMU-Nyx/commit/ab668227f97915c58d4413059a
[2]: https://github.com/nyx-fuzz/QEMU-Nyx/issues/23
2022-10-14 13:04:11 +02:00
Mrmaxmeier
f5cc354102
Token mutations: set MutationResult for CmpValues::Bytes (#838)
* token mutations: set MutationResult for CmpValues::Bytes

I haven't measured this and am not even sure if CmpValues::Bytes is
currently populated by any executor, but this seems like an oversight.

* replace dead zlib-1.2.12.tar.gz URL

See https://zlib.net/fossils/OBSOLETE
2022-10-14 13:03:57 +02:00
Andrea Fioraldi
fbff363842
Update qemu (#835) 2022-10-13 21:16:07 +02:00
expend20
bb3d6b3688
Frida Windows: calling original UnhandledExceptionFilter in the hook (#832) 2022-10-13 09:06:15 +02:00
Andrea Fioraldi
089bc49d55
Bump to 0.8.2 and update versions script (#828) 2022-10-12 14:57:08 +02:00
Andrea Fioraldi
bda63f82bf
Backport fix for AFL++ issue #1548 (#826) 2022-10-11 13:46:01 +02:00
Dominik Maier
94f0c7f56e
Moving to named parameters in format strings (#827)
* autofix

* you're just asking for a clamping

* autofmt on linux

* fix nits

* change back nit

* unfixing as u64 for GuestAddr

* fix

* ignoring clippy for GuestAddress
2022-10-11 13:45:01 +02:00
Dominik Maier
f3e8ed832b
Fix formatting (#822) 2022-10-07 02:15:23 +02:00
Dominik Maier
c61bb8cd5e
Fix formatting (#821)
* Format
2022-10-07 02:13:55 +02:00
Dominik Maier
d71e87c988
Added Hacking TMNF blogpost to Resources (#819) 2022-10-06 17:44:24 +02:00
Dominik Maier
8a4bbe3d0b
Fix FreeBSD CI (#820)
* Fix FreeBSD CI

* Fixed tests for freebsd
2022-10-06 17:43:59 +02:00
expend20
8fa4bca2d9
Hook IsProcessorFeaturePresent to crash with STATUS_STACK_BUFFER_OVERRUN exception (#804)
* First working attempt

* formatting issues

* Safety comment

* got rid of mutex

* Pass gum as a parameter

* removed debug println

* Review comments

* review: switched back to panic
2022-10-05 22:26:19 +02:00
Dongjia "toka" Zhang
00227e8058
Fix CI (#817)
* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml
2022-10-05 22:18:50 +02:00
Dongjia "toka" Zhang
57d1e4fba6
Fix Doc 2022-10-05 20:13:46 +02:00
Dongjia "toka" Zhang
fd24c49740
Format (#816)
* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* fmt

* Update build_and_test.yml

* Update build_and_test.yml

* rev

* rev
2022-10-05 18:05:03 +02:00
Patrick Gersch
c4a9b5f373
Changes for Linux without fork feature (#814)
* Minor changes for linux without fork feature

* cargo fmt
2022-10-04 20:32:33 +02:00
Eric Moss
d53bb344e8
Fixes typo and grammar in spawn_instances.md doc (#811) 2022-10-04 18:50:20 +02:00
Dongjia "toka" Zhang
e4f0e1df99
Fix CI (#810)
* fix

* fix

* fix

* removed allow(unused)

* removed feature from powerset

* fixing win

* tidying up

* cfg guards galore

* cfg for unused

* more cfg

* more fixes

* more cfgs

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-10-04 17:29:42 +02:00
Dongjia "toka" Zhang
caa560b7a0
TimeoutInprocessForkExecutor (#797)
* TimeoutInprocessForkExecutor

* no_std

* linux only

* OK

* crash -> timeout
2022-10-03 21:44:03 +02:00
Andrea Fioraldi
3489e9aeaa
Cite (#812) 2022-10-03 15:33:40 +02:00
Dominik Maier
b7d93a4bea
Hide prelude behind feature flag (#782)
* Hide prelude behind feature flag

* make prelude default
2022-09-30 20:30:28 +02:00
Patrick Gersch
02c962de45
Adding fork feature passing from libafl_qemu to libafl crate (#806)
* Adding fork feature passing from libafl_qemu to libafl crate

* Removing patches from a different PR

* Adding fork as a default feature for libafl_qemu

* Removing rand_trait feature from libafl_qemu
2022-09-30 20:29:54 +02:00
Dominik Maier
cc0c2f32ae
Additional errors only in test (#809) 2022-09-30 20:28:51 +02:00
Andrea Fioraldi
99a105d907
Disable ObserversOwnedMap due to new Rust error (#807)
Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>
2022-09-30 11:34:28 +02:00
Patrick Gersch
d2427fd8a6
Adding CPSR register for arm qemu (#800) 2022-09-29 16:06:33 +02:00
radl97
30f143cd3d
Add ability to use virtual dispatch to StagesTuple (#801)
* Add ability to use virtual dispatch to stagesTuple

* Fix lint
2022-09-29 02:32:24 +02:00
David CARLIER
279bb77f30
Support for bolts::cpu::read_time_counter on arm64 (#790) 2022-09-27 23:38:50 +02:00
David CARLIER
be0ae3a55e
Support for write_crash on netbsd (#788) 2022-09-27 23:37:50 +02:00
Dongjia "toka" Zhang
6dc7cc2f59
bump (#799) 2022-09-25 09:41:01 +02:00
Dongjia "toka" Zhang
08864f2d53
Fix CI (#798) 2022-09-24 19:57:03 +02:00
Ben Davis
db5473967c
Fix doc typos (#796) 2022-09-23 14:52:52 +02:00
Andrea Fioraldi
c0bb1bc1e6
Fix len miscalculation in grimoire string replace (#794)
* Fix len miscalculation in grimoire string replace

* ok Rust i was writing JS these days

Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>
2022-09-21 14:19:54 +02:00
expend20
f6bd99fc4d
Gdiplus comments (#792)
* Attempt to remove clang 12 setup

* frida_gdiplus added to CI

* Redundancy note

* formatting again :\

* mistake of directory name
2022-09-19 11:05:13 +02:00
expend20
ae400e5ce8
Remove clang download from windows CI (#791)
* Attempt to remove clang 12 setup

* frida_gdiplus added to CI
2022-09-19 09:20:33 +02:00
expend20
eebc412fb4
Windows gdiplus (#789)
* Initial steps

* Harness code cleanup

* don't panic on linux in order not to break the CI

* formatting once again

* restored cfg unix to unbreak linux build
2022-09-18 15:33:25 +02:00
David CARLIER
577f0be832
[AFLplusplus/LibAFL] dump registers on OpenBSD amd64 (PR #787)
* dump registers on openbsd

* write_crash implementations
2022-09-15 22:46:33 +02:00
WorksButNotTested
60a6c3f68b
Add support for ARMBE8 (#768)
* Changes to build QEMU out-of-tree so that we don't need to clone the repo for each feature combination we build

* Add be support to libafl_qemu

* More config tweaks

Co-authored-by: Your Name <you@example.com>
2022-09-15 20:25:56 +02:00
David CARLIER
100e4ad433
Dump registers on NetBSD amd64 (#786) 2022-09-15 16:23:16 +02:00
Andrea Fioraldi
74955d5376
Extend gramatron recursive mutator (#783) 2022-09-14 10:24:50 +02:00
David CARLIER
8cff2ce745
Reduce clang warnings for version output in libafl_cc. (#778) 2022-09-13 13:59:35 +02:00
David CARLIER
f5a5c08e5d
Illumos support (#775)
implementing core affinity too.
2022-09-13 13:50:20 +02:00
David CARLIER
23e655d7dd
Dump registers on freebsd x86_64 (#779) 2022-09-13 13:49:39 +02:00
Dongjia "toka" Zhang
7aadf31246
Add track_stability option to CalibrationStage (#781)
* add

* Update gramatron.rs

* Update emu.rs

* try

* clp
2022-09-13 09:39:17 +02:00
Dongjia "toka" Zhang
7f7e0ee6ac
Fix doc (#780) 2022-09-12 18:59:57 +02:00
Dongjia "toka" Zhang
d17269d3d5
Stability improve (#773)
* initial

* add

* fmt & fix

* dbg remove

* clp

* clp

* more

* clippy

* del

* fix

* remove unused

* fix

* doc
2022-09-12 18:08:07 +02:00
Dongjia "toka" Zhang
b863142829
Fix forkserver options (#771) 2022-09-09 02:42:16 +02:00
David CARLIER
0fe8192976
Enable memset_patter ASan hooks for Apple on libafl_frida (#763) 2022-09-05 01:39:17 +02:00
Vincent
10f5c0f07a
Fix cargo doc on windows (#762)
* add doc cfg

* fix nostd docs

* ignore CommandConfigurator doc test execution on non-unix platform

* add cargo doc step pipeline on windows platform
2022-09-04 09:34:26 +02:00
David CARLIER
d316591ba1
libafl_frida: ASan hook adding Apple's memset_pattern* api. (#761) 2022-09-04 03:09:05 +02:00
Teddy Heinen
47806df18b
Adjust NyxExecutor trait bound to HasTargetBytes from HasBytesVec (#760)
* adjust NyxExecutor trait bound to HasTargetBytes from HasBytesVec

* oops actually use HasTargetBytes instead
2022-09-04 02:51:11 +02:00
syheliel
bc96fc16bf
Add doc for libafl_nyx (#759)
Co-authored-by: syheliel <syheliel@gmail.com>
2022-09-03 10:35:18 +02:00
Dominik Maier
1f5189a6a6
Do not zero-init struct in QEMU (#758)
* New Clippy fixes for QEMU

* no need to 0-initialize mem

* clippy
2022-09-03 08:27:41 +02:00
David CARLIER
87fdd55125
Core affinity for FreeBSD pinning task to the wanted cpu (#756) 2022-09-02 18:50:15 +02:00
Dominik Maier
28194ac746
New Clippy fixes for QEMU (#757) 2022-09-02 18:49:41 +02:00
Dominik Maier
5823320206
Fixes for new Clippy (#755) 2022-09-02 16:21:06 +02:00
Dominik Maier
c4e0faabc2
CI for FreeBSD (#754)
* CI for FreeBSD

* rustup -y?

* fixed path, switched to clippy

* bsd don't source

* added llvm

* clippy

* more yml

* ?

* testing ci

* llvm?

* llvm??

* more llvm, more tests

* fixed testcase'

* mem limits

* more sudo

* reenable all the CI
2022-09-02 15:37:49 +02:00
David CARLIER
ebfe414a27
dragonflybsd build fix for core affinity. (#753)
supporting most of linux sched api here.
2022-08-30 03:37:17 +02:00
Patrick Gersch
ebae4d3ce8
MapFeedback: Adding support for with_name() (#752)
* Adding support for with_name()

* Adding with_name() function description
2022-08-29 14:43:00 +02:00
Dominik Maier
6c50f55cd2
Skippable stage, generator wrapper for Grimoire (#748)
* Skippable stage, generator wrapper for Grimoire

* more fancy wrapper
2022-08-29 13:44:22 +02:00
Addison Crump
0859c3ace2
Implement a corpus minimiser (cmin) (#739)
* initial try

* correct case where cull attempts to fetch non-existent corpus entries

* various on_remove, on_replace implementations

* ise -> ize (consistency), use TestcaseScore instead of rolling our own

* oops, feature gate

* documentation!

* link c++

* doc-nit: correction in opt explanation

don't write documentation at 0300

* better linking
2022-08-29 13:38:46 +02:00
Addison Crump
d6e72560dc
Add test case minimising stage (tmin) (#735)
* add test case minimising stage

* general purpose minimiser impl, with fuzzer example

* reorganise, document, and other cleanup

* correct python API return value

* correct some docs

* nit: versioning in fuzzers

* ise -> ize
2022-08-29 13:37:55 +02:00
David CARLIER
556bdc828c
Simplification for netbsd-specific code (#750)
the cpuset api is already present in libc...
2022-08-29 13:28:04 +02:00
Dongjia "toka" Zhang
7257631ed5
Fix autotokens doc (#751)
* fix

* remove wrong doc
2022-08-28 17:14:41 +02:00
David CARLIER
7760697579
Netopenbsd build fix (#746)
* core affinity netbsd implementation.

* openbsd build fix
2022-08-28 10:19:09 +02:00
Sirui Mu
af3ea172ab
Fix documentation of Rand::below (#747) 2022-08-28 09:54:01 +02:00
Sönke
eb7c8a1174
Add continous JSON Logging monitor (#738)
* Add simple JSON Monitor

* Add documentation

* Log global state

* Fix formatting

* Save state depending on closure outcome, have file opened all the time

* Make OnDiskJSONMonitor cloneable

* Switch to FnMut to allow stateful closures

* Use &mut M: Monitor for the closure
2022-08-27 10:05:38 -04:00
Dongjia "toka" Zhang
2389f677f4
OSX force_load option (#743)
* Update clang.rs

* fmt
2022-08-27 09:51:11 -04:00
Aiden Hall
fc349bb7b1
Fix spelling error (#745) 2022-08-26 16:48:32 +02:00
syheliel
758e49ac70
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>
2022-08-25 10:55:35 +02:00
David CARLIER
d377fce4f3
Add core affinity support for FreeBSD (#736) 2022-08-21 00:33:59 +02:00
Nicholas Lang
7b345fbba7
Fix tui with 1 client (#734)
* unbreak tui with 1 client

* clippy
2022-08-19 11:30:26 +02:00
Dongjia Zhang
93c361bcd9
New Pass Manager Arguments (#724)
* new pm arguments

* enable abgeana's code
2022-08-18 19:26:52 +02:00
Dongjia Zhang
eac7307c5a
0.8.1 (#732) 2022-08-18 10:23:57 +02:00
Dongjia Zhang
ce5ac3968d
Fixing readme & docs (#730)
* fix

* fix

* add

* add

* fmt
2022-08-15 02:12:35 +02:00
Dongjia Zhang
a87f99afb8
Simd Fix (#729)
* simd fix

* fmt
2022-08-14 20:39:34 +02:00
Phan Thanh Duy
ce12b98599
Fix compilation for aarch64 qemu (#731)
Typo lead to fail to compile for arm64
2022-08-14 12:56:21 +02:00
Dominik Maier
5ad6519456
Use nightly fmt (#728) 2022-08-14 11:00:02 +02:00
Dongjia Zhang
5d9a19f955
Mac OS Autotokens (#723)
* mac_tokens

* more

* win fix

* fmt

* fmt c
2022-08-13 02:58:22 +02:00
Alexandru Geană
c1aafe3e98
LLVM passes for Windows (#710)
* libafl_cc fixes for windows

* libafl_cc checks for llvm-config (again)

* libafl_cc clang-format

* libafl_cc fixes for macos

* maintain libafl_cc pass manager selection logic

* libafl_cc rustfmt
2022-08-12 20:25:59 +02:00
syheliel
2504b6dae3
Add rustfmt.toml (#722)
* add `rustfmt.toml`

* format fix

Co-authored-by: syheliel <syheliel@gmail.com>
2022-08-12 02:28:32 +02:00
z2_
faca7b9ac7
Deriving Clone for NopMonitor (#721) 2022-08-10 17:22:36 +02:00
Dominik Maier
7d7601204f
Fixes for new clippy (#719) 2022-08-05 13:34:27 +02:00
Dongjia Zhang
3dfdba2ddc
Resize MapFeedbackMetadata with observer.initial() (#718) 2022-08-05 09:05:15 +02:00
Dominik Maier
12052b5f1c
Remove num_cpus dependency (#717)
* Remove num_cpus dependency

* Fix build, remove more num_cpus
2022-08-03 07:49:32 +02:00
Patrick Gersch
b2a1e03703
Qemu arm launcher (#708)
* Adding qemu_arm_launcher crate

* Trying to fix qemu arm usermode

* Cargo fmt

* Adding CROSS_CC env

* Remove hardcoded arm-linux-gnueabi-gcc and replace by CROSS_CC

* Adding arm-linux-gnueabi-gcc to github workflows for ubuntu

* Fixing typo in apt install package

* Resetting LR after each fuzzing emulation

* Cargo fmt after merge conflict

* Using GuestAddr

* Compiling, running and running with artificial crash detection

* Adding dependencies for github workflow to cross compile for arm

* Fixing github workflow for ubuntu fuzzer

* arm-linux-binutils for mac in github workflows

* Qemu does not work for mac, no need to compile qemu_arm_launcher harness for it
2022-08-02 11:46:24 +02:00
Dongjia Zhang
376e3adfcd
Bump Frida, Capstone versions (#715)
* bump

* fix

* fix

* revert

* fix

* fmt

* fix
2022-08-01 16:53:39 +02:00
Dominik Maier
5a8bdae26f
Update requirements (#714)
* Update requirements

* more updates

* nits

* more updates

* update nix for fuzzers

* use any regex 1 instead of 1.6
2022-07-29 09:54:16 +02:00
Dominik Maier
8d5699a335
Add HitcountsIterableMapObserver, rename AsMutIter to AsIterMut (#713)
* Move HitcountsMapObserver back to iterators to make it usable with cargo-libafl

* clippy

* optimize the good-case

* safety info added

* mut_iter -> iter_mut

* split up map observer
2022-07-28 16:03:39 +02:00
Dongjia Zhang
a5248d0250
Change StdWeightedScheduler API (#712)
* change

* fmt
2022-07-27 14:17:45 +02:00
Andrea Fioraldi
1682ce6862
Fix SIGILL handling in libafl_qemu (#711) 2022-07-26 17:31:18 +02:00
Andrea Fioraldi
90f0f06ef5
Raw API for full-system libafl_qemu (#692)
* full system build

* start supporting more cpus

* first proto working

* more Emulator methods

* fix

* fix

* backdoor

* fix

* libvduse.a

* hash

* clippy

* debug

* working usermode

* Fix userspace arm

* clippy

* clippy

* clippy
2022-07-25 17:50:09 +02:00
Dongjia Zhang
0aba272a7d
Update fuzzbench_weighted to EXPLORE, fix linking (#707)
* Explore+weighted

* fix

* fmt

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-07-25 14:03:35 +02:00
Andrea Fioraldi
a6e4cac56b
prelude module (#709) 2022-07-25 10:35:53 +02:00
Dongjia Zhang
667adf97ec
Fix Autotokens (#706)
* fix

* del
2022-07-20 21:01:11 +02:00
Dongjia Zhang
8899a3b01c
Use clang-format-13 (#705) 2022-07-18 22:31:01 +02:00
Dongjia Zhang
999eaadc16
fix (#703) 2022-07-17 21:15:45 +02:00
Mrmaxmeier
321bcfeba1
Cleanup duplicate package warnings (#702)
* cleanup duplicate package warnings

* libmozjpeg fuzzer: disable png reading support

libmozjpeg's libpng support is not used by the fuzzing harness,
and the mozjpeg-4.0.3 release has a build system issue with
newish libpng versions.
2022-07-17 14:17:49 +02:00
s1341
c45b6be7e1
Bump rand version (#680)
* Bump rand version, dropping support for lain

* using lain version with fixed rand

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-07-16 01:46:32 +02:00
Patrick Gersch
3ae3dc7c62
Fixes to TUI monitor if main thread panics (#699)
* Trying to fix the tui if the main thread panics

* cargo fmt

* Prettifying code
2022-07-16 01:45:53 +02:00
Dongjia Zhang
3c0c95e382
upd (#697) 2022-07-12 10:31:56 +02:00
Dongjia Zhang
ffe8dbf6af
Bump to 0.8.0 (#696)
* upd

* more
2022-07-11 21:59:11 +02:00
syheliel
253c6b5bdc
Use SHMEM_FUZZ_HDR_SIZE constant (#695)
* Fix misuse of SHMEM_FUZZ_HDR_SIZE

* fix `cargo fmt`

Co-authored-by: syheliel <syheliel@gmail.com>
2022-07-08 09:45:56 +02:00
Dongjia Zhang
7870a6e699
Fix #675 (#691)
* fix

* wrapping
2022-07-04 20:11:28 +02:00
Tobias Scharnowski
be3d1d588f
Make ByteNegMutator negate, not flip (#675)
Change the ByteNegMutator to negate a byte, not flip it. Flipping a byte is already implemented in ByteFlipMutator.

See issue: https://github.com/AFLplusplus/LibAFL/issues/674
2022-07-04 16:37:36 +02:00
Dongjia Zhang
d9a0948377
Fix score calculation (#689) 2022-07-01 16:54:14 +02:00
z2_
fbcfc9fe20
Removed unused trait bounds from BytesSwapMutator (#688) 2022-07-01 07:58:58 +02:00
Dongjia Zhang
66b5fe8678
Extend weighted scheduler (#685)
* extend

* fix

* fmt

* more fix
2022-06-29 09:43:42 +09:00
Dongjia Zhang
405a1919b8
Still fixing ci (#683)
* fix

* fix

* more

* cargo fixed??

* fixed??

* clp

* fix
2022-06-28 16:56:28 +09:00
Dongjia Zhang
fd9d126124
Fix CI (#681)
* Update test_all_fuzzers.sh

* --

* fix ui.rs

* fix

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-06-27 23:19:15 +09:00
Dongjia Zhang
49de0046e8
Fix AFLCoverage Pass & small fixes (#678)
* fix

* more

* declare LIBAFL_CC_LLVM_VERSION at least when no llvm-config found

* More llvm14 fixes
2022-06-23 17:55:06 +02:00
Dongjia Zhang
5fd63c0076
Fix QAsan (#677)
* fix

* more
2022-06-23 17:54:50 +02:00
Dongjia Zhang
397507f5b1
Fix feedback from #665 & Fmt (#676)
* revert

* fmt

* fmt back
2022-06-23 17:54:39 +02:00
Andrea Fioraldi
7147170240
New hooks for libafl_qemu (#673)
* new block and edge hooks

* Wrking new hooks

* no Pin, just box

* working call tracing

* invalidate_block flag

* working call stack tracking helper

* callstack push

* fixes

* py

* fixes

* clippy

* clippy

* gdb api

* kill introspection

* fix

* upd qemu

* upd qemu
2022-06-16 11:09:07 +02:00
Andrea Fioraldi
93048f6270
Add custom GDB commands to libafl_qemu (#671)
* Add custom GDB commands

* clippy

* statically linked QEMU

* fix Calibrate

* clippy
2022-06-14 11:45:14 +02:00
Dominik Maier
f7c997ec65
CustomBuf Events to exchange any data between fuzzers (#672)
* custom buf events

* clippy, nits

* nostd

* testcase

* maturin build

* fmt

* pybind imports cleanup

* remove unneded lifetime annotation

* docs
2022-06-14 11:10:08 +02:00
Andrea Fioraldi
a2388d4400
Remove Hash bound in Input trait (#670) 2022-06-10 15:24:31 +02:00
Dongjia Zhang
c9f802a3b8
Improve map feedback/observer (#665)
* improve

* a

* fix it back

* more

* NO

* try

* fix python

* more

* specialize map map feedback with u8

* more

* fmt

* usable_count = len

* clp

* restore iterator based map feedback

* simd specialization

* optimize hitcounts

* fix hitcounts

* no_std

* moar unsafe

* fix

* clippy

* clippy

* opt non-specialized is_interesting

* fmt

* op post_exec

* cleanup

* even more

* allow

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-06-10 10:14:12 +02:00
Sergio Paganoni
986030732a
Generating core ids based on the actual count of logical cores (#669)
* generating core ids based on the actual count of logical cores

* make clippy happy

* make fmt happy
2022-06-09 20:45:27 +02:00
Andrea Fioraldi
395b616718
Fix #662 (#667) 2022-06-08 17:33:34 +02:00
Andrea Fioraldi
323b8e23ee
LIBAFL_DEBUG_OUTPUT in Launcher and OnDiskTOMLMonitor to create fuzzer_stats (#666)
* LIBAFL_DEBUG_OUTPUT in launcher on unix

* OnDiskTOMLMonitor

* fix

* clp

* clippy

* fix

* fix

* allow all

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2022-06-08 17:32:58 +02:00
Dominik Maier
2e746bf439
Apple aarch64 fixes (#660)
* Apple aarch64 fixes

* added shmem provider testcase

* added method to not ignore cores, removed deprecated core_affinity api

* cleaned up set_affinity tests

* fixes

* fixes

* more aarch

* apple needs serial tests

* disable testcase for now
2022-06-04 16:02:11 +02:00
Andrea Fioraldi
e7e82af52c
C forkserver logic in libafl_targets (#650)
* C forkserver logic in libafl_targets

* fix, enabled apple

* disable apple

* fixes

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-05-31 14:56:59 +02:00
Dongjia Zhang
400292968a
Check syscall result in set_for_current (#659)
* set_for_current error

* type

* more

* debug

* debug

* fmt

* clp
2022-05-30 23:06:58 +02:00
Dongjia Zhang
bc6a032843
Windows CI for frida (#658)
* harness & makefile.toml

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* rename

* no stdout

* Update harness_win.cpp

* Update harness_win.cpp

* Update Makefile.toml

* Update build_and_test.yml

* Update Makefile.toml

* Update Makefile.toml

* fix
2022-05-30 23:06:37 +02:00
Dominik Maier
3a5118fc02
Moved core_affinity to bolts (#655)
* moved core_affinity to bolts crate

* clippy

* fixes

* ubuntu

* ubuntu++

* moved core_affinity to os

* fixed more imports

* fixed imports

* fixed test

* moved core_affinity out of os

* added affinity

* moved to windows crate

* fmt

* some tiny fixes

* more win

* refactoring

* win?

* win?

* clp

* upd

* more

* copy & paste & fix

* clp

* try

* fix

* more

* fix

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2022-05-30 10:02:46 +02:00
Dongjia Zhang
dd78210335
Windows-rs update (#657)
* upd

* more
2022-05-29 13:04:21 +02:00
Dominik Maier
bfe69aea09
Format C/Cpp code in ./scripts/fmt_all.sh (#653)
* format all (clang format 13)

* added clang-format check

* re-add missing newline

* cargo doc was missing

* more brackets

* fixed fmt workflow

* clang format

* shellcheck

* install clang-format-13

* update ubuntu for maximum clang-formattability

* yml whitespaces

* fmt

* shellcheck only for .sh

* oops path

* ignored shellcheck warning
2022-05-29 03:23:02 +02:00
Dominik Maier
e4447364c2
SymCC update (#656) 2022-05-28 01:41:43 +02:00
Dominik Maier
c16738fd10
Make OutFile auto-remove refcounted on drop (#654)
* Make OutFile auto-remove refcounted on drop

* clippy, windows

* remove debug print

* streamlined tmp files names

* outfile -> inputfile
2022-05-27 18:01:44 +02:00
Andrea Fioraldi
a544bc042d
Move build_id to bolts (#649)
* Drop the build_id depedency and move to bolts

* tabs->spaces

* clippy build_id fixes

* frida clippy

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-05-27 01:05:03 +02:00
Dominik Maier
763ed9a3e5
Moved to no_std preamble (#643)
* Moved to no_std preamble

* fixed use

* no_std targets

* derive no_std

* fix yml

* ci

* alf

* gitignore

* fix python build

* import cleanup

* nostd

* linux fix
2022-05-27 01:04:29 +02:00
Dongjia Zhang
5887d1a7b7
Delete frida_libpng/Makefile (#652) 2022-05-27 01:04:09 +02:00
Dominik Maier
8b8b58ffa7
Doc fixes (#651) 2022-05-27 01:03:34 +02:00
syheliel
7d5fd74a5d
Improve doc (#648)
* Improve doc

* Fix

* Fix

* Fix

* Typo

Co-authored-by: syheliel <syheliel@gmail.com>
2022-05-26 11:44:05 +02:00
Andrea Fioraldi
28edbad618
Refactor libafl Python bindings (#632)
* SerdeAny MapFeedbackState

* Fix macro syntax

* alloc

* fix

* Metadata calibrate and map feedback

* metadata feedback states

* compile

* fmt

* Register common generic types

* tests

* sugar

* no_std

* fix book

* alloc

* fix fuzzers

* fix

* fmt

* disable python bindings for libafl

* clippy

* fmt

* fixes

* fmt

* compiling python bindings

* no uaf in python observer

* working python observer, feedback and executor

* mutators

* fmt

* nits

* added autofix script

* clippy

* clippy

* more clippy

* fix

* ignore clippy for deserialization

* newlines

* nits

* fmt

* feedbacks

* generators

* methods

* feedbacks

* pyerr

* fix

* fix

* fmt

* python bindings in CI

* fix

* fix

* fix

* autofix

* clippy

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-05-25 16:56:06 +02:00
Andrea Fioraldi
da537aae83
FeedbackState as metadata (#627)
* SerdeAny MapFeedbackState

* Fix macro syntax

* alloc

* fix

* Metadata calibrate and map feedback

* metadata feedback states

* compile

* fmt

* Register common generic types

* tests

* sugar

* no_std

* fix book

* alloc

* fix fuzzers

* fix

* fmt

* disable python bindings for libafl

* clippy

* fmt

* fixes

* fmt

* fix

* fix

* fix

* fix

* fix

* release autofix

* fix

* fix

* fix

* fmt

* fix

* fix

* name

* fix

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-05-24 16:05:22 +02:00
Dominik Maier
fa839bb08d
More docs and less pub types (#646)
* more docs

* nits

* fixes

* win fix

* fmt
2022-05-23 13:42:51 +02:00
Dominik Maier
b7650f7683
Added missing Eq (#645) 2022-05-22 23:36:18 +02:00
Dominik Maier
f3fd6caf0b
No break, only fix (#644) 2022-05-22 18:54:14 +02:00
Dominik Maier
7d2892a42f
Fix Windows import (#642) 2022-05-22 13:07:45 +02:00
Dominik Maier
c404825fb8
More clippy (#641)
* Even more libafl_frida clippy

* Eq

* addr_of_mut cleanup

* fmt
2022-05-22 13:01:55 +02:00
Dominik Maier
828ebcff39
Clippy nits & fixes (#640)
* release autofix

* fix unused backtrace

* clippy fixes

* clippy

* more clippy

* more autofix

* clippy for frida

* more clippy
2022-05-22 02:43:25 +02:00
Dominik Maier
50ddbf6a78
Added autofix script (#639) 2022-05-21 15:06:11 +02:00
peamaeq
ffaad561cb
Reduced scope of unsafe block (#637)
* '0517'

* 0517
2022-05-20 19:37:22 +02:00
Dongjia Zhang
5570601fea
Small refactoring of nits in #635 (#636)
* fix

* more

* fmt

* fix

* fix

* fix

* fix

* fmt

* fmt

* fix
2022-05-20 07:26:28 +02:00
Dongjia Zhang
4eba9323c5
Fix overflow in Frida mode (#635) 2022-05-17 15:06:38 +02:00
Dongjia Zhang
afb32fb351
Cmplog New Pass Manager & LLVM 14 Fixes (#626)
* wip

* more

* match aflpp

* llvm14

* fix

* more llvm14

* check llvm version in libafl_cc

* safe access

* more

* fmt

* no windows

* no windows
2022-05-17 08:45:48 +02:00
syheliel
2ead2c398e
Speed up CI (#630)
* Add ccache

* Update codecov.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update test_all_fuzzers.sh

Add fuzzer timer

* Fix `./test_all_fuzzers.sh` on macos

* Fix CI

* Fix CI

* Update build_and_test.yml

* Fix typo

* Set mold linker as default linker

* Fix CI

* Update build_and_test.yml

* Add profile arguments

* Fix CI

* Update test_all_fuzzers.sh

Co-authored-by: syheliel <syheliel@gmail.com>
2022-05-15 21:25:29 +02:00
syheliel
aa101c396a
Merge ubuntu and macos fuzzer && Record time for ./test_all_fuzzers.sh (#629)
* Add ccache

* Update codecov.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update test_all_fuzzers.sh

Add fuzzer timer

* Fix `./test_all_fuzzers.sh` on macos

* Fix CI

* Fix CI

* Update build_and_test.yml

* Fix typo
2022-05-14 00:57:26 +02:00
biazo
d61612c94c
Adding equivalent arm32 syscall for qemu snapshot (#628) 2022-05-14 00:49:39 +02:00
Dongjia Zhang
62484b12f4
Call post_exec_all() in calibrate.rs (#603)
* fix

* fix

* fix

* post_exec

* fix
2022-05-12 11:14:21 +02:00
Ao Li
9e382c4177
Fix gnf_converter.py script (#616) 2022-05-10 19:48:48 +02:00
Dongjia Zhang
a02b90be44
Autotokens New PM (#605)
* autotokens newpm

* typo

* fmt

* clp

* fix

* fix

* include &fmt

* include

* fmt

* llvm14 & clippy fix

* fix
2022-05-09 18:41:53 +09:00
Dongjia Zhang
283ceaac9b
Make weigthed scheduler independent of powersheduler stage (#599)
* rename & add metadata in scheduler, not stage

* Update testcase_score

* rename

* fix

* update handicap in scheduler

* fmt

* update fuzzers

* doc

* fmt

* fix

* fmt

* more

* fix

* fix

* fix

* fmt
2022-05-08 16:43:02 +02:00
WilliamParks
92196cc9be
Fixes forkersever_simple issue on Macs (#623)
* Fixes forkersever_simple issue on Macs

* fixes formatting issue

* Fixes formatting issue
2022-05-08 11:17:55 +09:00
Dominik Maier
eb70c8025b
Clippy nightly fixes (#624) 2022-05-07 15:35:37 +02:00
Dominik Maier
196569577f
Clippy nightly fixes (#622)
* removed unused errors

* Fixes
2022-05-06 19:11:09 +02:00
Shengtuo Hu
1c97a5fd2b
Remove PrimInt in map feedback and observer (#606)
* Remove PrimInt

* Use core instead of std

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-05-06 10:29:07 +02:00
Dongjia Zhang
2ba32c0173
Update Clap dependency (#621) 2022-05-06 01:12:25 +02:00
Dominik Maier
9092076ce2
removed unused errors (#620) 2022-05-05 22:24:18 +02:00
Andrea Fioraldi
e513b86df0
Backtrace in libafl::Error (#617)
* backtrace errors

* qemu

* remove mopt-specific error

* fixes

* fixes

* duh

* clap

* clippy

* clippy

* clippy

Co-authored-by: Dominik Maier <dmnk@google.com>
2022-05-05 15:52:37 +02:00
Andrea Fioraldi
bb773a74d1
Update QEMU version (fix #575) (#619) 2022-05-05 13:24:44 +02:00
Dongjia Zhang
80b85f99ff
Clippy fixes (#618) 2022-05-05 01:23:51 +02:00
Dongjia Zhang
6b76e53bfa
C(pp) formatting & autotokens fix (#614)
* fix

* a

* format

* .clang-format
2022-05-04 03:42:43 +09:00
Lukas Seidel
b0dd25ee95
use ucontext definition from bolts::os::unix_signals (#612) 2022-04-21 18:03:12 +02:00
Dominik Maier
1690dbb2cc
Sender id fix (#610)
* Starting to fix id issues

* add crashing testcase

* remove debug flags
2022-04-15 19:25:51 +02:00
Andrea Fioraldi
a99d0b2967
Fix clang linking without --libafl arg (#608)
* Fix clang linking without --libafl arg

* clippy
2022-04-12 20:34:38 +02:00
Andrea Fioraldi
e8f5949aec
Fix linking with -z defs (#601)
* Always link no-link-rt when not linking a fuzzer

* Handle dynamic

* fuzzbench

* Handle -z defs

* fix

* clippy

* clippy

* windowa

* fix
2022-04-08 18:06:27 +02:00
Andrea Fioraldi
bd23f7c916
Fix cmplog (#600) 2022-04-08 14:35:32 +02:00
Dongjia Zhang
0b94647219
fmt (#597) 2022-04-07 21:08:08 +09:00
Dongjia Zhang
fa69b9eff9
Powerschedule::RAND (#596) 2022-04-07 21:00:59 +09:00
Dongjia Zhang
e7a06fb30c
Fix unsafe bracket (#594) 2022-04-05 14:24:58 +02:00
Dongjia Zhang
eaa46075cc
COE Fix (#593)
* fix

* clp
2022-04-04 18:07:19 +02:00
syheliel
d4cdf02512
Add codecov in CI (#586)
Co-authored-by: syheliel <syheliel>
2022-04-04 18:05:36 +02:00
Dongjia Zhang
f732b76115
Make calibration stage independent of powerschedules (#589)
* fix

* clippy
2022-04-04 18:02:16 +02:00
Dongjia Zhang
e77e147a74
Update Clap (#591)
* upd

* fix
2022-04-04 17:59:34 +02:00
Dongjia Zhang
034a4870e2
Set the number of stacked mutations in MOpt mutator (#587)
* max_stack_pow

* fix

* fix

* fmt

* rename
2022-04-03 09:25:59 +09:00
Toka
1167389149
Fix metadata loss across state-restore. (#582)
* bug fix

* fix

* fix

* remove getter
2022-03-30 12:00:49 +09:00
Dominik Maier
c88e38d9f4
Ignore build artefacts (#585) 2022-03-29 19:48:08 +02:00
Toka
c1b8107060
Rename fuzzbench_selected (#581)
* rename

* rename
2022-03-29 14:59:27 +02:00
Dominik Maier
5df130188a
Fixing CI from #559 (#580)
* updated ref

* update symcc

* updated symcc

* CI for symcc

* updated symcc

* enabling git

* add runtime deps to makefile

* only linux

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2022-03-29 14:57:38 +02:00
Andrea Fioraldi
88a14cbbd2
Fix GeneralizedInput::wrapped_as_testcase (#584) 2022-03-29 14:56:48 +02:00
Toka
abf1a66028
Rename FavFactor to TestcaseScore; More TestcaseScores (#574)
* rework aflfast

* more

* move fuzz_Mu

* weighted

* fix

* borrow checker fix

* compute_weight

* alias_table

* fmt

* fix & rename

* fix & less mut

* no_std

* no_std

* clippy

* 32bit clippy fix

* top_rated for compute_weight

* fix

* clippy & metadata Init

* fix

* fix

* fix

* clippy & fmt

* change fuzzers

* fuzzbench_selected

* fmt

* compute() has state

* use favfactor for powerschedules also

* fix merge

* rename

* fmt & clippy

* no_std

* fmt

* clippy

* rename

* fmt

* rename

* fmt

* fix

* fix

* fmt

* fix

* fix
2022-03-27 04:04:46 +09:00
Chaofan Shou
e20d345d99
Fix concolic fuzzer and add related CI tests (#559)
* fix concolic fuzzer & add related CI tests

* More cargo fmt

* More cargo fmt

* order matters
2022-03-26 13:51:14 +01:00
bitwave
fee100715c
Remove wrongly linked file in README (#577) 2022-03-26 13:49:35 +01:00
Dongjia Zhang
f906201dcb
Calibration fix (#578)
* fix

* fix

* fix

* fix

* fmt
2022-03-26 13:49:17 +01:00
Dongjia Zhang
acba89b92a
Makefile.toml for frida fuzzer (#566)
* frida makefile.toml

* makefile.toml
2022-03-23 11:30:20 +01:00
Dongjia Zhang
c72f773ca0
Weighted corpus entry selection (#570)
* rework aflfast

* more

* move fuzz_Mu

* weighted

* fix

* borrow checker fix

* compute_weight

* alias_table

* fmt

* fix & rename

* fix & less mut

* no_std

* no_std

* clippy

* 32bit clippy fix

* top_rated for compute_weight

* fix

* clippy & metadata Init

* fix

* fix

* fix

* clippy & fmt

* change fuzzers

* fuzzbench_selected

* fmt
2022-03-23 02:01:00 +09:00
Dongjia Zhang
c3d3c93bc0
CI Fix (#572)
* clippy

* doc

* refactor
2022-03-21 07:54:46 +01:00
Andrea Fioraldi
e36522cf21
Fix find_gaps_in_closures (#568) 2022-03-16 11:07:36 +01:00
syheliel
6b95361123
Add doc for example baby_fuzzer_* (#564)
* Add doc for example `baby_fuzzer_*`

* Fix `mdbook build`

Co-authored-by: syheliel <syheliel>
2022-03-14 19:14:46 +01:00
Andrea Fioraldi
8eab7d6063
Fix fuzzers (#563)
* fix libfuzzer_libpng_ctx

* fix

* fix

* Fix stb

* fix

* fix
2022-03-07 08:59:01 +01:00
Andrea Fioraldi
09cf136c63
Fix CI (#562)
* fix libfuzzer_libpng_ctx

* fix

* fix
2022-03-04 15:51:54 +01:00
Andrea Fioraldi
e6bc89555f
Fix GeneralizationStage (#561)
* fmt

* Fix generalization
2022-03-03 15:20:37 +01:00
Andrea Fioraldi
a56f4af7da
CorpusScheduler -> Scheduler and move them to the schedulers folder (#560)
* CorpusScheduler -> Scheduler

* fix book

* update fuzzers

* fix tests

* fix sugar

* fix

* fix tutorial

* fix tutorial

* fmt

* fix

* fmt

* fmt
2022-03-03 14:27:37 +01:00
Chaofan Shou
4e3091eace
Dump Control Flow Graph in AFLCoverage LLVM Pass (#557)
* Allow dumping CFG in AFLCoverage pass

* Consider cases of edges from zeros to entry basic block.

* Expose public structs and traits

* linting

* fix doc

* clippy

* Remove unnecessary dependency

* add missing derive
2022-03-02 11:19:19 +01:00
Andrea Fioraldi
8cb41366ac
Snapshot QEMU mmap_next_start (#558) 2022-03-01 16:04:20 +01:00
s1341
f4c4d9044f
Use the new bolts::cli with the frida_libpng sample (#541)
* Use the new bolts::cli with the frida_libpng sample

* Fix comment and add must_use

* Fix windows

* Fix windows more

* Fix windows more, more

* Fix windows more, more, more

* Remove comma

* fmt
2022-03-01 11:25:11 +01:00
Andrea Fioraldi
bf9d2b4c57
Fix snapshots in libafl_qemu (#556)
* afl_exec_sec feature, disabled by default

* Fix snapshots in libafl_qemu

* working memory snapshots
2022-02-28 21:23:20 +01:00
Chaofan Shou
c4fb92a1a4
Add probabilistic sampling corpus scheduler (#544)
* Add probabilistic sampling corpus scheduler

* Linting

* Fix ToOwned error

* Move if-stmt of checking `ProbabilityMetadata` existence and revert powersched removal

* Use `Error::IllegalState` instead of `Error::DivByZero`
2022-02-24 10:19:38 +01:00
Evan Richter
679eadcc50
Prevent dropping variables in closure hooks (#549) 2022-02-24 10:18:46 +01:00
Chaofan Shou
df84d39242
Add function call level granularity for coverage accounting (#552)
* Add func call level granularity for coverage accounting

* code linting
2022-02-24 10:16:12 +01:00
Andrea Fioraldi
04c8e96923
afl_exec_sec feature, disabled by default (#555) 2022-02-23 16:06:22 +01:00
Andrea Fioraldi
05b10ad56d
Fix no_std after #553 (#554)
* Fix no_std after #553

* clippy
2022-02-23 11:32:25 +01:00
Andrea Fioraldi
5ffddcfd4a
List observer and feedback (#553) 2022-02-23 10:26:46 +01:00
Dongjia Zhang
ef01009f30
List dependencies in readme.md (#547)
* readme dependencies

* upd
2022-02-22 00:20:15 +01:00
Andrea Fioraldi
95d3de0f4b
Closure hooks and on thread create hook (#542)
* Closure hooks and on thread create hook

* on thread once hook

* clippy

* fix

* fix
2022-02-21 18:30:02 +01:00
Tamas K Lengyel
b3d68e8f40
Add signal option to forkserver_simple (#548) 2022-02-21 16:49:04 +01:00
Dongjia Zhang
ba4cca0e15
Delete redundant makefiles (#546)
We switched to cargo make
2022-02-20 18:50:29 +01:00
Dongjia Zhang
fc89f2944b
Makefile.toml fix (#545) 2022-02-20 04:21:43 +01:00
Dongjia Zhang
936e2221d1
Cargo-make (#537)
* timeout utility

* example build.toml

* upd

* ci

* Update build_and_test.yml

* Update build_and_test.yml

* rename, qemu_launcher

* libpngs

* fix

* upd

* del

* do_nothing -> unsupported

* rename

* use command

* non qemu fuzzbench

* script.sh

* mroe

* qemu

* fix

* generic

* fix

* fix

* allow 124

* quotes

* fix

* fix

* fix

* stderr to devnull

* chg
2022-02-20 03:32:43 +01:00
Evan Richter
7150ffc5e6
[libafl_qemu] EasyElf::resolve_symbol return GuestAddr (#540)
Also enforce Linux support at the crate level instead of item by item
2022-02-16 21:34:56 +01:00
Andrea Fioraldi
a03d733cf9
libafl_qemu decouple hooks from the executor and QemuForkExecutor (#528)
* QemuHooks

* option state hooks

* QemuForkExecutor

* enforce no side effects in QemuForkExecutor

* child hooks fixes

* fixes

* qemu_launcher

* examples and fixes

* fix sugar

* clippy

* fmt

* no timeout for fuzzbench_fork_qemu

* Update libafl_qemu/src/hooks.rs

Co-authored-by: Alwin Berger <50980804+alwinber@users.noreply.github.com>

* clippy

Co-authored-by: Alwin Berger <50980804+alwinber@users.noreply.github.com>
2022-02-15 22:11:24 +01:00
Dongjia Zhang
86b4ff9c2f
Set default connect address to IP (#539) 2022-02-15 17:44:58 +01:00
Andrea Fioraldi
479f9471ff
Walk the map observer using as_ref_iter() in the map feedback (#535)
* Walk the map observer using into_iter() in the map feedback

* fmt

* map observers as iterators

* perf

* IntoMutIterator and IntoRefIterator

* Clone

* clippy
2022-02-14 18:12:19 +01:00
Farouk Faiz
2dcdaaa89f
Intial support to Python bindings for the libafl crate (#429)
* Add libafl py module

* Hardcoded baby_fuzzer

* Trait abstraction: MapObserver
Send type name as a param as it's needed for extracting the rust struct from the PyObject

* Fix merge

* Impl traits for python wrappers

* Add PythonExecutor
Not buildable version

* Executor trait bindings

* Monitor trait bindings

* EventManager trait bindings

* Fix warnings

* Add corpus trait bindings

* Use corpus trait bindings

* Rand trait bindings

* Remove python feature from default

* Add cfg attribute

* Fix fmt

* No std box

* Fix clippy

* turn OwnedInProcessExecutor in a simple type alias

* remove crate-type from libafl's Cargo.toml

* Add python baby_fuzzer

* Fix doc

* Maturin doc

* multiple map observer

* fmt

* build pylibafl with nightly

* macro for map element type

* Update py baby_fuzzer & fmt

* Mutator bindings

* fmt

* merge conflicts

* StdMutationalStage bindings
Not working: Cannot pass mutator to new method because not clonable

* Stage bindings

* StagesOwnedList bindings
Not working: Stage not clonable

* Unsafe transmute copy fix

* Use Stage bindings in baby_fuzzer

* fmt

* fmt

* Fix doc

* fix merge

* Remove x86_64 feature from pylibafl

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-02-14 11:41:39 +01:00
Dongjia Zhang
393afa56c8
Github workflows frida build on windows (#536)
* Update build_and_test.yml

* Update build_and_test.yml

* clippy

* clippy

* clippy
2022-02-13 05:10:17 +01:00
Dominik Maier
7dad2153e2
Clippy for Cargo (#532)
* Clippy for Cargo

* clippy fixes

* clippy fixes

* edition

* fix

* wrong self hidden

* fix

* more clippy
2022-02-11 14:34:01 +01:00
Andrea Fioraldi
a4c9d2d19e
Fix ASAN backtrace (#534) 2022-02-11 14:31:18 +01:00
Dongjia Zhang
d676363c64
Fix Forkserver Example (#533)
* fix

* fix

* fix

* update

* change
2022-02-11 10:41:07 +01:00
Dongjia Zhang
53bc6e2318
test_all_fuzzers.sh fix (#531)
* fix

* fix

* fix
2022-02-11 10:04:04 +01:00
Dongjia Zhang
42cab49f3e
Forkserver builder fix (#529)
* fix

* fix

* fmt

* no @@

* fuzzer change

* parse_afl_cmdline

* comma
2022-02-11 09:38:26 +01:00
Andrea Fioraldi
eb668384bb
Fix hardcoded BacktraceObserver (#530)
* refactor BacktraceObserver and InProcessForkExecutor

* cleanup

* fix improcess

* fix

* mormanti

* win fix

* clippy

* fix backtrace_baby_fuzzers/command_executor

* win fix

* clippy
2022-02-10 21:45:20 +01:00
Dongjia Zhang
9d38fff662
Autodict forkserver (#525)
* Builder for ForkserverExecutor

* add

* clippy warnings

* comment

* stash

* tmp

* change

* revert

* use_shmem_feature field

* change the harness back

* wip

* wip

* revert

* works

* clippy

* Makefile fix

* doc

* clippy

* rename to program

* rename, fix, envs

* lifetime

* arg_input_file

* stash

* read autodict from forkserver

* works

* clippy & fmt

* fmt

* fix

* fix

* fmt

* better harness

* arg_input_file_std

* rename

* fix
2022-02-10 10:27:51 +01:00
Dongjia Zhang
9482433e54
Forkserver builder (#523)
* Builder for ForkserverExecutor

* add

* clippy warnings

* comment

* stash

* tmp

* change

* revert

* use_shmem_feature field

* change the harness back

* wip

* wip

* revert

* works

* clippy

* Makefile fix

* doc

* clippy

* rename to program

* rename, fix, envs

* lifetime

* arg_input_file

* bug fix

* arg_input_file

* builder()

* doc

* clippy & fmt

* clippy & fmt
2022-02-09 22:07:15 +01:00
Andrea Fioraldi
63d89463a3
Improve libafl_qemu snapshots (#484)
* mprotect

* expose EnumIter

* thread safe mem snapshot

* update qemu hash

* clippy

* child helpers

* fixes

* fix build

* fix dep
2022-02-09 09:40:59 +01:00
Dominik Maier
6bfbdd6318
Add sdk linker flag for broken MacOS systems (#527) 2022-02-08 18:29:48 +01:00
Dominik Maier
a3345902c2
Shorthand for differential fuzzing results (#526)
* Shorthand for differential fuzzing results

* must_use
2022-02-08 04:07:42 +01:00
Dongjia Zhang
914bcd5c47
Frida Doc (#515)
* draft

* add

* more newlines
2022-02-07 23:39:53 +01:00
Dominik Maier
98fbe83c15
Differential executor, diff feedback, stdio observers for command executor (#521)
* started diff fuzzer

* finished DifferentialExecutor

* adapt builder, more diff fuzz infra

* diff eq feedback

* stdout observer started:

* stdio observers

* stdio observers

* no_std, fixes

* no_std tests
2022-02-06 18:20:57 +01:00
Andrea Fioraldi
1fca710813
llvm-config --libs only for apple (#522)
* Fuck apple

* fix fuzzbench_text
2022-02-04 11:49:02 +01:00
Sagittarius-a
2bb60fb756
Fix documentation typos (#514)
* Fix typos in LibAFL doc comments

* Fix doc comment for ProgressReporter trait

* Remove unused comment

* Link ShMem by name in doc comment
2022-02-03 16:31:19 +01:00
epi
3dcb191baf
Removed subcommands from FuzzerOptions (#516)
* updated code that removes subcommands from FuzzerOptions

* updated docs, added headings

* updated test to reflect new api

* repeat requires replay

* removed global; removed Option where appropriate; housekeeping; tests

* removed unnecessary cfg check from tests
2022-02-03 16:29:54 +01:00
Andrea Fioraldi
c561182f07
Set map observers initial value to T::default() on creation (#520) 2022-02-03 14:25:25 +01:00
Andrea Fioraldi
f527aab15e
Non weak default sanitizers options functions (#519) 2022-02-03 10:44:23 +01:00
Andrea Fioraldi
0062bab412
libafl_cc: -fsanitize=fuzzer is an alias to --libafl (#518)
* libafl_cc: -fsanitize=fuzzer is an alias to --libafl

* no link runtime
2022-02-02 21:47:23 +01:00
Andrea Fioraldi
465275aecb
Allow incomplete feature (#517)
suppress the specialization feature warning
2022-02-02 17:55:46 +01:00
Dongjia Zhang
3c4ec38d83
Win Fix (#513)
* win_fix

* fmt

* another fmt
2022-02-02 00:26:10 +01:00
s1341
e41b76fe31
Throw an exception on a failed new in frida ASan, instead of just returning null (#512) 2022-02-01 15:28:44 +01:00
Dongjia Zhang
fb21c4ff82
Frida Runtime Tuples (#457)
* an attempt to make runtimes into tuples

* wip

* wip

* wipp

* getter

* refactor

* fmt

* fix

* compiles

* fuzzer change

* coverage working

* asan & less unwrap() & fixes

* inst size, fmt

* build & coverage works on asan

* amd64 fix
2022-02-01 14:34:53 +01:00
Andrea Fioraldi
dd002a081b
Implement coverage accounting (BB metric atm) (#507)
* bb accounting llvm pass

* bb metric

* accoutning corpus scheduler

* fix warnings

* alloc

* clippy

* fix dockerfile

* clippy

* coverage accounting example

* finish CoverageAccountingCorpusScheduler

* fmt

* --libs in llvm-config

* merge
2022-02-01 14:08:38 +01:00
Dominik Maier
6810e6085b
Builder for CommandExecutor & Tokens Refactoring (#508)
* builder for CommandExecutor

* tokens api cleanup, clippy

* fix doctest

* cleanup

* added testcase, remodelled

* command executor builder fix

* fix fuzzer(?)

* implemented From for configurator

* nits

* clippy

* unused

* autotokens

* cleanup

* nits

* Err instead of empty tokens

* fix tokens fn

* fix err

* more error fixing

* tokens remodelling

* typo

* recoverable fail on missing autotokens

* clippy, nostd

* asslice, into_iter, etc. for tokens

* adapt fuzzers

* iter

* fixes, clippy

* fix

* more clippy

* no_std

* more fix

* fixed typo

* cmd_executor builds again

* bring back ASAN stuff to Command Executor

* forkserver speedup

* no need to static

* back to earlier
2022-02-01 10:10:47 +01:00
Dongjia Zhang
c61fed6ca9
Use Unix timer_* API instead of setitimer (#510)
* fix linter errors for armv7 (docs)

* introduce HasOnCrashReset trait; use timer_* API instead of setitimer for unix TimeoutExecutor

* fixes: PR #469 annotations and CI issues

* reintroduce setitimer for apple as macOS does not feature the POSIX timer API

* more macos and windows CI fixes

* more macos and windows CI fixes cont.

* HasOnCrashReset -> HasPostRunReset

* remove drop impl for Windows TimeoutExecutor

* adjust target cfgs for timeout stuff (android also did not work)

* add call to inner post_run_reset

* remove HasPostRunReset in favor of making it a trait fn of Executor

* add post_run_reset's to CombinedExecutor

* clippy: addr_of! instead of raw pointer casts

* link librt in libafl_cc (required by timer_* API)

* minor fixes and cleanup

* remove unused import for targets other than linux

* fix win

* merge

* fix

Co-authored-by: pr0me <g33sus@gmail.com>
2022-02-01 04:48:03 +01:00
Dominik Maier
9dfc6aa404
CI and fixes for arm32 no_std build (#511)
* arm32 no_std fixes and clippy

* moved criterion to benches crate

* benches no longer live here
2022-02-01 00:57:58 +01:00
Youssef
e307dfb16f
Implement backtrace observers for crash dedupe (#379)
* create stacktrace observer

* create stacktrace feedback

* post-merge fixes

* address comments

* update Cargo.toml

* fix CI issue + dynamic naming

* duplicate baby_fizzer

* update stacktrace baby_fuzzer

* force unwinding tables

* ignore test dumps

* fix stacktrace baby_fuzzer logic

* upgrade Backtrace version

* trigger observers.post_exec in crash_handler

* implement NewHashFeedbackState and update logic

* digest symbols pointers

* cleanup

* minimal output

* fix backdated EventFirer generic param

* add baby_fuzzer example with a fork executor

* duplicate baby_fuzzer_stacktrace with forkexecutor

* backtrace collection implemented

* add c app fuzzer example with a fork executor

* group backtrace baby fuzzers

* added c code baby fuzzer with inprocess executor

* remove need for static COLLECT_BACKTRACE

* moved code to stacktrace.rs + fixed bug

* add comment

* add command executor fuzzer example

* post merge cleanup

* add missing doc

* address comment

* fix nit

* clean duplicate variable in timeout handler

* fix command executor bt collection

* clean code and use StdShMem

* cleanup

* add ObserverWithHashField + rename StacktraceObserver

* rename + refactor some code

* add CommandBacktraceObserver

* update command executor

* update baby fuzzers

* simplify BacktraceSharedMemoryWrapper

* use better names + static methods

* use std feature macro on BacktraceObserver + fix bug

* use Box in HashValueWrapper to minimize variants size diff

* use copy_from_slice

* std conditional backtrace collection

* fix std import

* fix comment

* add exit_kind to observer.post_exec

* added hash trait to Input

* collect backtrace in post_exec

* add crash handlers to InProcessForkExecutor

* fix panic message

* duplicate forkserver fuzzer example

minimal example

update

* proto bt collection working

* rename CommandBacktraceExecutor to ASANBacktraceExecutor

* refactor ASANBacktraceObserver

* support for forkserver working

* update fuzzer example

* less verbosity

* Post merge fixes

* implement hash for GeneralizedInput

* update forkserver example after merge

* clippy fixes

* fix inproc test

* fixes for cargo hack --feature-powerset

* fix baby_no_std

* implement Hash for NautilusInput

* update fork executor baby fuzzer

* fix doc

* implement Hash for PacketData

* fix windows build

* fix windows no_std

* fix backtrace baby fuzzers README

* add comments

* move setup_bt_panic to constructor

* pre/post child exec hooks in Observer

* setup_child_panic_hook

* fix ObserversOwnedMap on nightly

* add backtrace fuzzers to CI checks

* fix typo

* fix relative paths in test_all_fuzzers.sh

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-01-31 15:58:15 +01:00
epi
62e514e61d
Make harness-args available to all subcommands in opt parser (#509) 2022-01-31 12:53:59 +01:00
epi
4862928e1e
[READY] Add options parser (#493)
* added parser to workspace

* added parser to utils

* added must_use/docstring

* added qemu_args/removed mod names

* implemented subcommands, added example

* added crate docs

* updated based on StdFuzzer options

* added frida optiosn

* added qemu parser example

* added repeat option

* added custom subcommands

* comments and nitpickery

* pedantic fixes

* updated per review

* additional doc-comment over attribute fixes

* moved everything to bolts::cli; updated docs and things

* removed utils/fuzzer-options from cargo.toml

* forgot std flag; added

* fmt
2022-01-28 18:10:09 +01:00
epi
2a8efa7d6d
extended inmemory; added exit to qemu (#506) 2022-01-28 18:09:04 +01:00
Andrea Fioraldi
95ba7d61ce
remvoe fprintf from autotokens pass (#505) 2022-01-28 13:51:55 +01:00
Dongjia Zhang
93f28b41be
Update frida README.md (#503) 2022-01-28 10:11:06 +01:00
epi
78bbe034a1
extend python forkserver api (#500)
* initial attempt at api extension; untested

* updated/tested on forkserver_simple
2022-01-28 09:43:21 +01:00
Evan Richter
4e3e31df4e
[libafl_qemu] GuestAddr type (#501)
Guest addresses now represented by correct sized integers.

Previously u64 was used to represent guest addresses. This is great for
64-bit targets, but clunky for other architectures. This introduces a
GuestAddr type alias that is defined based on the selected emulation
architecture.

Note: This changes only the user-facing Rust interface. Before
traversing the FFI boundary, all GuestAddrs are sized back to u64.

Another Note: Guest addresses _from_ the FFI boundary are completely
trusted. Values that are too large are truncated to fit into a GuestAddr
using the `as GuestAddr` cast. This may not be ideal, as errors could be
masked. If desired and the performance is ok, a non-breaking update
could change all `as` casts to `.try_into().unwrap()` so that critical
failures in FFI are always checked.
2022-01-28 09:42:23 +01:00
Dongjia Zhang
efb5e25411
Fix shadow bit for libafl_frida on Linux (#502) 2022-01-28 09:26:24 +01:00
epi
21668b094b
Expose more options to python qemu sugar (#492)
* registered forkserver sugar, if unix

* exposed multiple options to python sugar constructor

* pedantic clippy is pedantic

* fixes from review/shortened attribute
2022-01-27 09:27:25 +01:00
Evan Richter
4a6616bdfe
[libafl_qemu] simplify emu::{read,write}_mem (#496)
Methods read_mem and write_mem now operate on &[u8], not &[T]

The generic T slice interface was prone to various footguns:
* i32 is the default Rust integer type, but buffers are often expected
  to hold u8. This means the following code writes 16 bytes to the
  guest, not 4:

      let buf = [0; 4];
      emu.write_mem(addr, &buf);

* If a buffer of 16-bit or larger integers (&[u64] for example) is
  needed to read/write, the user will need to consider host/guest
  endianness. The byte array methods in std are a good, explicit
  alternative.

  Perhaps libafl_qemu could expose/define "to/from guest endianness"
  helper functions or extension traits using the established cfg flags,
  so that guest endianness is always right by default.

* emu::read_mem causes insta-UB if a user did something like:

      let mut my_bool = false;
      emu.read_mem(addr, &mut my_bool);

  It's less surprising for users to just operate on plain-ol' bytes,
  which they can explicitly transmute if they wish.
2022-01-27 09:05:33 +01:00
Andrea Fioraldi
408431ba5c
Fix libafl import features in libafl_targets (#495)
* fix

* fix
2022-01-26 22:29:25 +01:00
Dongjia Zhang
62614ce101
LLVM AutoTokens (#470)
* posix dict2file llvm pass

* new PM

* working

* clean up

* fmt

* fix

* silence clippy

* bring the println back

* early return

* rename

* weak symbols

* linux onky

* fuzzbench change

* only linux

* linux only

* cfg

* cfg

* fix

* fix

* fix

* why

* fix

* bug fix

* rename

* rename

* macros & rename

* add_from_autotokens

* fix fuzzbench

* std -> core

* builder pattern?

* clippy

* wrong cfg

* cfgstd

* fuzzbench fmt

* no unsafe

* update fuzzbench_text

* use TokenSectiopn

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-01-26 19:23:04 +01:00
Andrea Fioraldi
0223d8a0c6
Implement Grimoire (#487)
* GeneralizedInput

* GeneralizationStage

* generalization finished

* GrimoireExtensionMutator

* grimoire_mutated flag and propore HasTargetBytes

* use alloc

* working baby fuzzer for grimoire

* fmt

* GrimoireRecursiveReplacementMutator

* extend_with_random_generalized

* extend_with_random_generalized

* GrimoireStringReplacementMutator

* GrimoireRandomDeleteMutator

* clippy

* fuzzbench_text

* fix fuzzbench_text
2022-01-25 21:34:10 +01:00
Andrea Fioraldi
b459933d29
AnyMap and owned collections of Observers and Stages (#491)
* AnyMap and owned observers

* owned stages

* alloc

* panic on (de)serializing ObserversOwnedMap

* clippy
2022-01-24 20:59:37 +01:00
Dongjia Zhang
2730515c46
Asan Fix (#490)
* fix

* fmt
2022-01-24 09:17:19 +01:00
Sagittarius-a
14959c7f9c
Fix debug_child arg in forkserver_simple example (#489)
The `debug_child` command line argument presence was not properly checked,
so it couldn't be set to true. Hence it was not possible to print out
the content of the buffer sent to the harness while fuzzing.
2022-01-22 09:42:05 +01:00
Sagittarius-a
68ab473c85
Fix typo in documentation of libafl::state::StdState (#488) 2022-01-22 00:27:42 +01:00
Dongjia Zhang
03c020f4bd
Asan fix (#485) 2022-01-21 09:08:21 +01:00
Andrea Fioraldi
cc0880e784
Monitor with UI based on tui-rs (#480)
* first working version

* full gui

* remove warnings

* remove errors in release

* allow missing_docs in tui

* tui_monitor flag

* working graphs

* disable tui on windows

* clippy

* clippy

* tui module only under std

* use tui from git

* fmt

* tui from crates
2022-01-20 23:55:48 +01:00
Evan Richter
ab7d16347f
[libafl_qemu] map_fixed and mprotect target memory (#483) 2022-01-20 22:06:26 +01:00
Dongjia Zhang
5e1c0b96ea
Various Fixes (windows timeout race & frida options) (#482)
* race fix

* oops

* no backtrace
2022-01-20 01:32:04 +01:00
Dominik Maier
77e5965e97
Add AsSlice, AsMutSlice traits, refactor MapObservers to be iterable, and have associated types (#477)
* from warning

* fix latest clippy

* clippy fixes++

* renamed shmem parameters

* renamed map to shmem

* make forkserver executor work for any (non-system) shmem

* Mem -> ShMem

* rework windows

* fix nit

* fix symbolic

* refacctor map observers

* iterator for map observers

* removed unused ownedptr, added asslice trait to most functions

* make map entry type an associated type

* fix fuzzers

* fix docs

* typo fix

* fix windows, add try_from_slice to shmid

* missing import

* fix fuzzbench

* cleanup

* fmt

* more asslice

* fmt

* added doc link about token-level fuzzing

* cods
2022-01-19 00:02:33 +01:00
Dominik Maier
b67a7f5b60
[libafl_frida] Enabled ASan for Apple (#478) 2022-01-18 18:37:19 +01:00
Andrea Fioraldi
929f687676
Repro arguments libfuzzer-like for fuzzbench (#475) 2022-01-18 16:31:44 +01:00
Dominik Maier
4f6f76e857
Streamline ShMem API (#472)
* from warning

* fix latest clippy

* clippy fixes++

* renamed shmem parameters

* renamed map to shmem

* make forkserver executor work for any (non-system) shmem

* Mem -> ShMem

* rework windows

* fix nit

* fix symbolic
2022-01-17 18:28:26 +01:00
Dominik Maier
ac43997950
Fixed additional new clippy lints for libafl_qemu, libafl_frida (#473)
* clippy for qemu

* getrlimit clippy
2022-01-17 16:24:40 +01:00
Dominik Maier
2dd88998bd
Clippy fixes for latest toolchain (#471)
* from warning

* fix latest clippy

* clippy fixes++

* more nits
2022-01-17 11:02:42 +01:00
Andrea Fioraldi
aebd85f041
Bump libafl_sugar to 0.7.1 (#468) 2022-01-13 15:57:24 +01:00
Andrea Fioraldi
bbd11bc4a7
Bump libafl_frida to 0.7.1 (#467) 2022-01-13 15:48:51 +01:00
Andrea Fioraldi
9b3a435778
Add --libafl arg in libafl_cc and enable it for fuzzbench (#466) 2022-01-13 15:40:39 +01:00
Andrea Fioraldi
bca1f392a7
Bump to 0.7.1 (#465)
* bump to 0.7.1

* bump libafl_qemu
2022-01-13 11:32:57 +01:00
Dongjia Zhang
b70833f26b
Libafl_frida ASan shadow bit (#455)
* add

* debugging

* remove debug code

* fmt

* why

* writable or executable ranges

* for

* fmt

* fix
2022-01-13 10:45:15 +01:00
Andrea Fioraldi
906bb4e653
--libaf-no-link (#464) 2022-01-13 10:03:02 +01:00
Andrea Fioraldi
de5264efad Clippy 2022-01-10 13:34:24 +01:00
Andrea Fioraldi
180883acb7 Panic when using nautilus with stable Rust 2022-01-10 12:17:32 +01:00
Andrea Fioraldi
d7dbd021a4 Specialization feature in nightly 2022-01-10 11:49:13 +01:00
Andrea Fioraldi
8870c50ff5 Do not build QEMU when generating docs 2022-01-10 11:27:53 +01:00
Andrea Fioraldi
eed864eb36 switch to rustversion 2022-01-10 10:12:26 +01:00
Dongjia Zhang
327ff98ea1
Asan fix (#460)
* fix

* fix

* bump

* fmt
2022-01-09 21:00:04 +01:00
Dongjia Zhang
82194c5fe5
Fix windows build (#462)
* fix

* fmt
2022-01-09 20:57:43 +01:00
buherator
5ac3cd6b5a
Optional signal value for kill on timeouts in TimeoutForkserverExecutor (#461)
* Optional signal value to kill forked processes on timeout

* Cargo format

* Properly initialize TimeoutForkserverExecutor

* Added with_signal constructor

* Removed duplicate code
2022-01-09 14:31:14 +01:00
Andrea Fioraldi
e6f2f2d0b2 Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2022-01-07 11:53:54 +01:00
Andrea Fioraldi
181160d80b Clone only one specific commit on libafl_qemu build.rs 2022-01-07 11:53:34 +01:00
Dongjia Zhang
87cd44b762
Use UserStats for Stability (#451)
* stability:serstats

* tostring

* fix no_std

* fix

* fmt

* clippy
2022-01-07 11:07:39 +01:00
Evan Richter
250ec8d1e0
Reduce generics for various Has* traits (#456)
Specifically for Has{Rand,Corpus,Solutions,FeedbackStates}

The Has* family of traits offer getters and get-mut-ers. The previous
implementation had a fully generic return type:

    trait HasX<X: TraitX> {
        get_x(&self) -> &Self::X;
        get_mut_x(&mut self) -> &mut Self::X;
    }

meaning a single type could implement both `HasRand<Romu>` and
`HasRand<XorShift>`. The advantage of having multiple implementations is
not clear at this time, so it vastly simplifies the trait (and its
impls) to bring the return type in the body as an associated type:

    trait HasX {
        type X: TraitX;
        get_x(&self) -> &Self::X;
        get_mut_x(&mut self) -> &mut Self::X;
    }

This comes with the limitation that any type that impls these traits can
only do so once, choosing only one associated type.

* HasRand's only generic parameter (Rand) is now an associated type
* HasCorpus and HasSolutions are now only generic over the Input type
  they store
* HasFeedbackStates generic parameter now associated type
2022-01-06 10:41:02 +01:00
Dominik Maier
30eb1508de
Add OwnedSlice::RefRaw to keep track of raw pointers (#448)
* add OwnedSlice::RefRaw to keep track of raw pointers

* clippy

* fmt

* new from ownedref

* clippy

* OwnedSliceInner

* fix,From

* as_slice()

* fmt

* fix doc

* OwnedSliceMut

* fixes

* clippy

* fix

* ownedmut -> owned

* to owned

* to_owned -> clone

* removed comment

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2022-01-05 01:15:23 +01:00
Dominik Maier
6d9763c51f
Move to clap 3.0 (#447)
* move to clap 3.0

* fix cargo.toml

* update symcc to use clap3
2022-01-04 23:53:12 +01:00
Dominik Maier
a1a6d5f478
Disable pita 🥙 compiler in debug mode (#454) 2022-01-04 16:20:52 +01:00
Dongjia Zhang
674005fa61
Reorder type parameters in the correct order (#449)
* alphabetical order

* revert

* revert

* fix
2022-01-04 00:20:29 +01:00
Yerkebulan Tulibergenov
2de729a779
Fix a typo in TODO.md (#450) 2022-01-04 00:14:46 +01:00
s1341
1608294d0b
Various fixes related to frida mode (#445)
* Fix lint errors

* Fix incorrect address for unfreed allocations when reseting

* Use hash for edge ids

* Fmt
2022-01-03 10:41:52 +01:00
Evan Richter
9f6872ac68
[libafl_qemu] fix i386 Regs values (#444)
The `Regs` enum was defined out of order, leading to incorrect results from `emu.read_reg`. I found the correct ordering defined here: https://github.com/AFLplusplus/qemu-libafl-bridge/blob/master/target/i386/cpu.h#L46-L54
2022-01-03 10:41:29 +01:00
Dominik Maier
b9acac46d9
Cpu atomics for LLMP (#438)
* atomic read for unmap

* send and recv

* switching to Atomics

* atomics

* bring back compiler_fence (maybe needed for signals?)

* only acquire mem if new msg is available

* unused compiler fence

* caching for msg ids to not have to read atomics as much

* fix build

* speed++

* only in a spinloop for the second try

* cleanup logs

* docu, error log
2022-01-03 00:47:31 +01:00
Dominik Maier
af3d321213
Derive debug for all structs in LibAFL (#442)
* documentation, warnings

* fixed docs

* docs

* no_std

* test

* windows

* nautilus docs

* more fixes

* more docs

* nits

* windows clippy

* docs, windows

* nits

* debug all the things

* derive debug for all core library components

* Docu for libafl_targets

* nits

* reordered generics

* add docs to frida, debug

* nits

* fixes

* more docu for frida, nits

* more docu

* more docu

* Sugar docs

* debug for qemu

* more debug

* import debug

* fmt

* debug

* anyap_debug feature no longer needed

* tidy up unused fn

* indicate if we left out values for struct debug

* implement Debug for sugar

* debug allthethings

* ci
2022-01-03 00:47:17 +01:00
Dominik Maier
efc804fe7d
Updated dependencies (#443)
* updated dependencies

* updated info in toml

* Windows fixes

* fixed immport

* u32 -> i32

* ignore i32 overflows in constants

* removed unused double allow
2022-01-02 17:52:44 +01:00
Evan Richter
9f76386668
[libafl_qemu] prevent unneeded build.rs runs (#441)
`libqasan/libqasan.so` never exists during a normal `cargo build` because the .so is built in the target_dir, not in the source directory. This was triggering cargo to rerun the build script every time a user of this library made an incremental change to their code.

pointing `rerun-if-changed` to a directory will make cargo rerun build.rs if any file in that directory changes.
2022-01-02 01:03:35 +01:00
Dominik Maier
cb3662da54
Enable errors for missing docs, add documentation (#440)
* documentation, warnings

* fixed docs

* docs

* no_std

* test

* windows

* nautilus docs

* more fixes

* more docs

* nits

* windows clippy

* docs, windows

* nits
2022-01-01 19:51:27 +01:00
Dominik Maier
d669b063f4 clippy 2021-12-30 18:38:28 +01:00
Dongjia Zhang
b537539b54
Use MiMalloc for in-process fuzzers (#439)
* MiMalloc

* docu

* other fuzzers

* mention asan
2021-12-30 16:33:23 +01:00
s1341
b5153cc525
Frida various fixes (#436)
* Make drcov post_exec dependent on whether drcov is enabled

* Fix find_smallest_fit algorithm

* Fix missing ?

* fix warnings

* fix

* todo for non-linux/android shadow, clippy

* typo

* removed unsupposted eq

* cleanup, docu

* libafl::Error

* fixed import

Co-authored-by: tokatoka <tokazerkje@outlook.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-12-29 18:47:33 +01:00
Evan Richter
e47c3be3fd
[libafl_qemu] fix build.rs (#435)
I noticed qemu was only building on one core, so I debugged the jobs environment variable. Evidently cargo passes `CARGO_BUILD_JOBS` is passed to build.rs scripts as `NUM_JOBS`. Other env vars for build.rs can be found [here](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts)
2021-12-29 01:30:14 +01:00
s1341
eeac0f4f06
Fix strncmp hook to only check the length of the string (#434) 2021-12-28 10:00:44 +01:00
s1341
6384f1da95
Merge pull request #433 from AFLplusplus/frida_asan_max_total_allocation
Implement max total allocation size for frida asan
2021-12-27 11:49:40 +02:00
s1341
129cd0fe66
Merge pull request #432 from AFLplusplus/drcov_runtime
DrCov Runtime
2021-12-26 16:21:15 +02:00
s1341
2e92a34494 Reset total allocations on reset 2021-12-26 11:17:27 +02:00
s1341
11ae49b7cd Implement max total allocation size for frida asan 2021-12-26 10:44:25 +02:00
tokatoka
97c169fe63 init ranges later 2021-12-24 16:34:53 +09:00
tokatoka
e6434d2ec2 fmt 2021-12-24 15:46:27 +09:00
tokatoka
9cd0d2228c drcov runtime 2021-12-24 15:45:08 +09:00
Dominik Maier
6b5181250c
Drcov remodelling (#415)
* drcov remodelling

* fmt

* fix

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2021-12-23 17:13:18 +01:00
Andrea Fioraldi
6274ad4594
Refactor libafl_qemu creating the Emulator struct and post syscall hooks (#430)
* working without asan.rs

* working asan

* update fuzzers

* mremap in snapshot

* sugar

* python

* fix python

* clippy

* fmt

* fuck you loader
2021-12-23 09:10:13 +01:00
Dongjia Zhang
d697554810
Other/User defined WIndows Exceptions (#402)
* other exceptions

* add

* 46th

* fix

* fmt
2021-12-21 19:18:58 +01:00
s1341
b0019ae4a9
Fix frida-mode for debug builds, ensure it will continue to work on release builds (#427)
* Fix cfg directives so that we actually build on all combinations of release/debug x86_64/aarch64

* Include fuzzer for stalker purposes

* Get rid of cfg on use
2021-12-21 14:30:47 +01:00
Andrea Fioraldi
785cddc1f0 Fix meson.build issue updating QEMU git hash 2021-12-21 12:42:41 +01:00
Andrea Fioraldi
208d69342d Update QEMU git hash 2021-12-21 11:35:06 +01:00
Andrea Fioraldi
d2bc09a31b Format 2021-12-21 11:28:08 +01:00
Andrea Fioraldi
0cce1e2b91 Update fuzzbench and fuzzbench_qemu, delete fuzzbench_gsoc 2021-12-21 11:26:04 +01:00
Dongjia Zhang
2aa0ca5ef1
Frida shadow fix (#425)
* map_to_shadow

* fix map_to_shadow

* aarch64 change?

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* use

* revert

* s1341's change

* Fix shadow calculation in instrumented code

* Fix asan error output to be more accurate

Co-authored-by: s1341 <github@shmarya.net>
2021-12-20 10:51:45 +01:00
van Hauser
1f24ad0b65
Implement AflMap (#416)
* aflmap

* nits

* nits

* switch implementation

* clippy

* set fuzzbench fuzzer to afl map

* fix monitor display

* Remove MapFindFilter and fix names

* AndReducer

* fixed testcase

* always inline

* remove inline(always)

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-12-16 14:19:39 +01:00
Dongjia Zhang
6e59e5bdc7
Frida Refactor: Separate Frida other helper functions into each Runtime (#418)
* separate asan

* fmt

* move asan out of helper.rs

* fmt

* move cmplog out of helper.rs

* fmt

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* final fix & fmt

* Fix unused imports

* Fmt

* rename files

* fix Makefile

* fmt

* clippy

Co-authored-by: s1341 <github@shmarya.net>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-12-16 14:16:01 +01:00
Dongjia Zhang
79f9bcd3e0
Use AddVectoredExceptionHandler to register exception handlers (#403)
* add

* unix fix

* unsafe positions

* another unsafe!

* ignore

* ignore

* make changes back

* fix

* fix

* fmt

* exception fix

* fix

* bug fix

* fmt

* fix things messed up during merge

* stack overflow fix

* fix

* fix

* fix

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-12-16 11:15:24 +01:00
s1341
d93f97309a
Open the stdout-file once (#419)
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-12-16 11:12:40 +01:00
Dominik Maier
abfdb619a8 Remove cpp from CodeQL 2021-12-15 23:43:56 +01:00
Dominik Maier
d1eaf07423
Create codeql-analysis.yml 2021-12-15 23:38:27 +01:00
Dominik Maier
88e07a8d37 CI galore 2021-12-15 23:34:42 +01:00
Dominik Maier
d3245de5bd Even more CI 2021-12-15 21:37:22 +01:00
Dominik Maier
e72c579ebc more CI fixes 2021-12-15 19:07:43 +01:00
Dominik Maier
304eda724f
Various fixes for CI (#423)
* Various fixes

* fix try_from for cores

* no_std
2021-12-15 18:11:40 +01:00
Dominik Maier
a8845ccbe7
Fix makefile for frida_libpng (#422)
* fix Makefile

* revert unfinished changes from #418

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2021-12-15 12:30:33 +01:00
Dominik Maier
217a7dee1d
Use Structopt instead of yaml for example fuzzers, introduce Cores API (#420)
* reworked generic_inmemory to structopt

* moved core parsing to a struct

* added Cores

* added structopt to libpng_ctx

* improved libafl, added structopt to libpng launcher

* fix deexit ub

* move more to structopt

* improve llvm-config detection

* move construct_automata to structopt

* clippy, fixes, ...

* no_std

* clippy

* frida core parsing

* fixed no-fork cores

* updated clap

* added missing import

* missing borrow

* reworked frida to structopt

* fixed build

* using Cores api for atheris

Co-authored-by: Dominik Maier <d.maier@avm.de>
2021-12-15 03:58:35 +01:00
Andrea Fioraldi
b4c2551544
Debug output for forkserver (#413)
* usability fixes for forkserver

* don't call target_bytes twice in TimeoutForkserverExecutor

* don't call target_bytes twice in ForkserverExecutor
2021-12-10 14:52:23 +01:00
Dongjia Zhang
4aa6550bf2
Clap: use help instead of about (#417) 2021-12-10 05:04:32 +01:00
Dongjia Zhang
a96e01fda5
Fix forkserver_simple clap issue (#412) 2021-12-10 03:38:42 +01:00
Dongjia Zhang
3fbe1be189
Fix timeout value type for Windows (#414) 2021-12-09 20:08:44 +01:00
Dominik Maier
98859fbf69
Symcc submodule referencing a path (#411) 2021-12-09 16:43:03 +01:00
Dongjia Zhang
fc0881194d
Windows timeout fix with critical sections (#391)
* add

* unix fix

* unsafe positions

* another unsafe!

* ignore

* ignore

* make changes back

* fix

* fix

* fmt

* bug fix

* fmt

* compiler fence

* import

* typo

* add another critical section

* fix

* fix

* exclude windows book test

* typo

* fence

* why

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-12-09 13:55:20 +01:00
Andrea Fioraldi
c6553c5351 Use grammartec on crates 2021-12-09 09:58:19 +01:00
Andrea Fioraldi
7c7c7e679f Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-12-08 16:32:36 +01:00
Andrea Fioraldi
5af2b4580e Update pyo3 to 0.15 2021-12-08 16:32:32 +01:00
van Hauser
4a23489acb
Implement unstable edge detection+ignore in calibration stage (#398)
* step 1 for unstable calibration

* fmt

* fixed build

* done unstable implementation

* clippy

* finishing touches for unstable

* no_std

* fmt

* event mgr stablity

* fixed stability value

* displaying

* no_std

* fixed critical whitespace

* send msg only after calibration

* clippy

* Added log to mgr

* moved stability to state

* fix introspection

* space

* fixed docs

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-12-08 09:54:47 +01:00
Dominik Maier
83583a867f
QEMU target arch selector via feature flag (#405)
* QEMU target arch selector via feature flag

* fix ci

* fixing ci some mmore

* more ci fixes, defaulting to x86_64 always

* more ci

* i368 -> i386 typo fix

* revert forkserver changes

* trying to fix clippy

* docs

* fixed warnings

* more clippy action

* qemu example arch

* bring back deprecated function I don't know how to replace

* get rid of deprecated feature again'

* builds?i
2021-12-06 20:06:47 +01:00
Lukas Seidel
0d0fe9eaca
Add fn for TimeoutExecutor to change desired timeout (#408) 2021-12-06 17:44:24 +01:00
Dongjia Zhang
bfcb86a2e4
Forkserver example updated (#404) 2021-12-06 13:48:41 +01:00
Andrea Fioraldi
c3ea7a042c Update QEMU bridge revision hash 2021-12-06 10:04:59 +01:00
Dongjia Zhang
0c50406af6
forkserver docus (#400)
* forkserver docus

* typo

* Update forkserver_and_inprocessforkserver.md

* Update forkserver_and_inprocessforkserver.md

* Update forkserver_and_inprocessforkserver.md
2021-12-05 21:48:15 +01:00
Dongjia Zhang
62291654bd
Frida_libpng document change (#401)
* change

* change
2021-12-04 16:19:41 +01:00
Dongjia Zhang
30f8fd44ef
Better forkserver example (#399)
* better example

* fmt
2021-12-04 16:17:38 +01:00
Andrea Fioraldi
96ef72e682 Fix grammartec rev 2021-12-02 16:43:48 +01:00
Andrea Fioraldi
e1349463db Fix grammartec version to 0.1.0 2021-12-02 16:41:01 +01:00
Dominik Maier
a0ce4cfd68
Ignored qemu fuzzer for non-linux (#397)
* ignored qemu fuzzer for non-linux

* fixed cfg

* ignore rm -rf errors in make short_test (fuck you macos)

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-12-02 11:48:35 +01:00
Dominik Maier
ca767752d0
make map debuggable (#396) 2021-12-02 10:29:24 +01:00
Lukas Seidel
8a57361e84
dump_registers and write_crash for armv7 (#393)
* dump_registers and write_crash for armv7

* fmt
2021-12-02 10:28:17 +01:00
Andrea Fioraldi
d24989e6ae Bump pylibafl to 0.7 2021-12-01 17:27:04 +01:00
Andrea Fioraldi
37b8cb0d2f Bump to 0.7 2021-12-01 17:22:09 +01:00
Andrea Fioraldi
2fb1c3520a
More LLVM passes from AFL++ (#394)
* afl coverage pass

* working ctx coverage

* MAYBE_THREAD_LOCAL

* doh

* fix for msvc

* ci

* clippy

* atheris

* thread_local
2021-12-01 13:27:39 +01:00
Andrea Fioraldi
cf5b4dfb18 OnDiskMetadata 2021-11-29 14:28:55 +01:00
Andrea Fioraldi
6dd107c4ef Executions field in Testcase 2021-11-29 14:22:27 +01:00
Toka
6cd2d69bfc
fix (#388) 2021-11-23 17:01:08 +01:00
Andrea Fioraldi
3ccf884d86 Hook cmp on arm/aarch64 in libafl_qemu 2021-11-19 14:37:59 +01:00
Andrea Fioraldi
2a780652e1 Fix HasTimeoutHandler 2021-11-18 09:42:35 +01:00
Andrea Fioraldi
d2fbc1040e
Qemu fixes and syscalls for every supported arch (#386)
* cpu_target

* report

* track mmap in x64 snapshots

* fixes in libafl_qemu and qemu bridge

* clippy

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-11-18 09:33:26 +01:00
Dominik Maier
01bb599759 fixed ms 2021-11-17 20:18:50 +01:00
Andrea Fioraldi
5605f233fc
InProcessHandlers (#387)
* InProcessHandlers

* clippy
2021-11-17 18:32:26 +01:00
OB
751330e8ee
Cmplog instrumentation (#382)
* add support for cbz/tbz

* remove unecessary print

* implemented support for tbz

* add support for tbnz

* fix an error in the emitted code for both tbz/tbnz

* add support for cbnz

* fix error in logic

* add special handling to "subs"

* add restoration for X5 for tbz/tbnz

* add "adds" support

* add special handling for different opcodes

* add support for cbz/tbz

* remove unecessary print

* implemented support for tbz

* add support for tbnz

* fix an error in the emitted code for both tbz/tbnz

* add support for cbnz

* fix error in logic

* add special handling to "subs"

* add restoration for X5 for tbz/tbnz

* add "adds" support

* add special handling for different opcodes

* add adcs to cmplog commands

* get rid of irrelevant allocations

* add flag restoration to cmplog instrumentation emitted code

* add restoration for x24

* save and restore all registers
2021-11-17 18:22:37 +01:00
Dominik Maier
e978b4f281 fmt 2021-11-17 18:14:15 +01:00
Toka
fd869ba1cd
Frida Refactor: Frida executor (#374)
* frida executor

* add files

* fmt & clippy

* fmt

* fix

* fmt

* fix & fmt
2021-11-17 12:51:39 +01:00
Dominik Maier
ba969108e3
Push stage trait (#380)
* rpush mutational trait

* tiny changes

* started PushStageAdapter

* fmt

* refactoring

* fix docs

* no_std

* formatted more
2021-11-17 12:51:14 +01:00
Toka
8b9f298674
remove print from lib internals (#384) 2021-11-17 12:50:47 +01:00
Andrea Fioraldi
fd5e793e57
libafl_qemu cpu_target cfg (#383)
* cpu_target

* report

* track mmap in x64 snapshots
2021-11-17 12:50:10 +01:00
Dominik Maier
4d24012245
Clippy fixes (#385)
* clippy fixes

* added missing use, switched to hashbrown

* fix

* more clippy
2021-11-17 12:49:58 +01:00
Andrea Fioraldi
00d38dc535
AddressSanitizer for libafl_qemu (#378)
* build libqasan

* asan runtime

* working simple asan

* init_with_asan

* fmt

* incomplete instr filter

* harden dealloc

* clippy
2021-11-16 13:53:28 +01:00
Toka
c7512fceec
Frida Refactor: Split FridaHelper into each Runtime (#368)
* dynasm maybe_log

* create coverage_rt, trim helper

* add

* amd64 working

* aarch64 instrumentation, untested

* asan dir

* Revert "asan dir"

This reverts commit c7afc784819072d9fa7b8ce23adb7c9f07a21b10.

* non x86_64 fix

* clippy

* change

* change

* fix

* Fix aarch64-linux-android build

* Fix aarch64 execution

* Fix fmt

Co-authored-by: s1341 <github@shmarya.net>
2021-11-16 12:30:34 +01:00
Andrea Fioraldi
56e05d0ff0 Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-11-15 14:10:36 +01:00
Andrea Fioraldi
87677be11d Update QEMU commit in libafl_qemu 2021-11-15 14:10:29 +01:00
Dominik Maier
ad1793bc4b Removed unused variable from pushstage 2021-11-14 10:41:35 +01:00
Dominik Maier
83271a7d42 More verbose restarting error msg 2021-11-14 10:26:14 +01:00
Andrea Fioraldi
c6dd2e7d0a Fix clippy 2021-11-13 19:54:40 +01:00
Andrea Fioraldi
1b77f014fe Remove unused time crate from libafl deps 2021-11-13 18:50:23 +01:00
Andrea Fioraldi
23b55eae6a Proper run time format for Monitors 2021-11-13 18:49:11 +01:00
Toka
23f02dae12
Fix api (#376)
* Fix api

* change fuzzers
2021-11-12 19:10:53 +01:00
Toka
c96474e0b9
Reachability fuzzer fix (#346)
* fix

* env var

* readme
2021-11-12 18:13:38 +01:00
Andrea Fioraldi
cb1216e6c1
Disk sync (#377)
* sync from disk stage

* finish SyncFromDiskStage

* clippy
2021-11-12 14:57:11 +01:00
Andrea Fioraldi
20e5500d93 ClosureStage 2021-11-12 14:50:50 +01:00
Toka
3b30ce3c20
fix staterestore (#375) 2021-11-12 11:55:00 +01:00
Dominik Maier
62afed61e2
Renamed Stats to Monitors (#373)
* renamed stats to monitors

* added depreciation notices

* resorted generics alphaabetically

* added monitors

* fmt fuzzers

* added depreciation note for usermonitor

* fmt all fuzzers script

* more fmt

* renamed some monitor things back to stats

* fixed rename
2021-11-12 11:01:08 +01:00
Dominik Maier
9ab8663366 more todos done 2021-11-11 02:26:35 +01:00
Dominik Maier
fff7cbd90f
implemented MapMaxPow2Feedback (#371)
* implemented MapMaxPow2Feedback

* using num-traits for qemu as well

* moved back to Num for float fun

* OneOrFilled Feedback
2021-11-11 01:49:46 +01:00
Dominik Maier
3e85cf22de
Mutational Push Stage (#356)
* initial commit for push stage

* cleanup, no_std, clippy

* clippy

* fuzzes

* readme

* fmt
2021-11-11 01:49:38 +01:00
Andrea Fioraldi
e914cc9c14 add ForkserverBytesCoverageSugar 2021-11-10 16:00:15 +01:00
Andrea Fioraldi
18b36843c7 CmpLog option in QemuBytesCoverageSugar 2021-11-10 11:09:56 +01:00
s1341
a42a3a9ccf
Support suppression of hooked functions (#369) 2021-11-08 07:51:58 +01:00
s1341
eecfdbbbe0
Support different names for the libc++ shared object when hooking (#370) 2021-11-08 07:50:20 +01:00
Dominik Maier
8ec8be1ce5
make dump_registers method public (#367)
* make dump_registers method public

* be smart about getting the ucontext

* more docu
2021-11-08 02:53:53 +01:00
s1341
a80126681e
Fix cfg directives for frida-asan (#365)
* Fix cfg directives for frida-asan

* drop unneeded line

* clippy

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-11-07 18:17:47 +01:00
s1341
bd7ce8d0ca
Launch every 100ms (#364) 2021-11-07 17:56:16 +01:00
OB
3ffcfde9a3
Frida Cmplog improvements for aarch64 (#363)
* add support for cbz/tbz

* remove unecessary print

* implemented support for tbz

* add support for tbnz

* fix an error in the emitted code for both tbz/tbnz

* add support for cbnz

* fix error in logic

* add special handling to "subs"

* add restoration for X5 for tbz/tbnz

* add "adds" support

* add special handling for different opcodes

* add support for cbz/tbz

* remove unecessary print

* implemented support for tbz

* add support for tbnz

* fix an error in the emitted code for both tbz/tbnz

* add support for cbnz

* fix error in logic

* add special handling to "subs"

* add restoration for X5 for tbz/tbnz

* add "adds" support

* add special handling for different opcodes

* add adcs to cmplog commands

* get rid of irrelevant allocations
2021-11-07 15:39:34 +01:00
s1341
dd0b5fa74f
Add minibsod (#362)
* Add minibsod

* fmt'

* clippy

* nostd/mac fixes

* windows fix

* woops. Mac fixes

* Get rid of unneccesary sleep

* Fix missing unsafe

* clippy fixes

* make ucontext,siginfo not a reference

* fmt

* fix _context

* Add stubs for non-apple, non-linux, non-android; add a todo

* Fmt

* macos x64, testcase, cleanup

* no_std

* added fault address to minibsod for apple x64

* added err, hexlified values (as per mac panic)

* informing user about lack of registers

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-11-07 15:32:43 +01:00
Dominik Maier
32b8f838ae
Fixed potential unsoundness due to Rc threading for ShMemProvider (#355)
* Fixed potential unsoundness due to Rc threading for ShMemProvider

* tidy
2021-11-06 18:23:25 +01:00
Dominik Maier
72d22ee5e5
remove unused const hashing mode (#358) 2021-11-06 18:23:10 +01:00
Sönke
5878129d22
Fix MaxReducer docstring (#357) 2021-11-06 13:39:20 +01:00
Andrea Fioraldi
b4e15fe9f3
Bridge grammartec from Nautilus to libafl (#342)
* nautilus dep

* nautilus generation

* fix mutator

* start new mutator for nautilus

* other mutators

* baby

* ci

* NautilusFeedback

* fix unparse

* ci

* ci

* ci

* ci

* nigghtly clippy

* ci

* fix

* ci

* ci

* update construct automatata

* fix

* ci

* clippy

* clippy

* nightly clippy

* more clippy

* minor clippy

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-11-06 02:21:53 +01:00
Dominik Maier
ea820a1694
Fork feature flag to disable fork in Launcher (#351)
* Fork feature flag to disable fork in launcher

* FnOnce instead of FnMut

* cleanup

* fix no_std

* doc/warning fix

* useless clippy fix
2021-11-05 17:26:49 +01:00
Toka
380196cf41
Fix cfgs for frida asan (#353)
* fix

* fmt
2021-11-05 17:15:59 +01:00
expend20
1ea95e73f4
(#354)
Co-authored-by: expy <expy@>
2021-11-05 14:50:44 +01:00
expend20
5000558f71
Readme impromevent in frida_libpng fuzzer. (#350)
Co-authored-by: expy <expy@>
2021-11-05 13:46:19 +01:00
Toka
9f9cab6d72
Fix the number of clients spawned by Launcher (#349) 2021-11-05 12:31:31 +01:00
Andrea Fioraldi
d1700f8775
Refcnt for MapIndexesMetadata (#348)
* refcnt for MapIndexesMetadata

* fix clippy
2021-11-05 12:14:57 +01:00
Toka
bf67b6ca76
Frida Address Sanitizer for x86_64 (#331)
* remove libafl_tests

* fmt

* fix

* fix

* fix

* first

* width

* start working on runtime side

* experimental c code for generate_shadow_check_function

* generate shadow_check_blob

* add

* debuggin

* fix

* passes assert tests

* cargo fmt

* generate_shadow_check_blob, untested

* save flags

* add

* make registers numbers a const

* register frames?

* comment

* debugging memcpy

* fix a bug, more to come

* finally error removed

* finally working function hooking & clean up

* fix for arm & update stub

* fix

* blob

* blob_check_mem works? (at least no errors) & fmt

* add an link to show how the asm code are generated

* put probe code for aarch64 back & clippy

* fmt

* still blob emitting errors

* fmt

* now that blob works?

* stack alignment

* testing speed with hook_function only

* comment some printlns out

* small fix: ignore rep, jmp to current_report_impl iff blob_check_mems are emitted

* make rip accessible by pc()

* Program counter accessors for both arch

* fmt

* fix

* fix offset

* retrieve accessed memory addr, r/w rip

* inspect the fault triggering instruction

* AsanError Classification

* clippy fixes

* pass basereg/indexreg/disp to AsanErros

* update asanerrors for amd64

* clippy

* fmt

* use frida/frida-rust

* just use 44

* fix debug build

* fix

* fix

* crate.io

* change

* fmt
2021-11-05 06:37:28 +01:00
Andrea Fioraldi
f0daeb377e
Fix double borrow mut in CachedOnDiskCorpus (#347) 2021-11-04 17:49:07 +01:00
Andrea Fioraldi
28c5e59fb2 Fix Rust 2021 clippy 2021-11-04 10:55:54 +01:00
Andrea Fioraldi
eca605bf01
MultiMapObserver and sancov 8bit-counters instrumentation (#343)
* MultiMapObserver and 8bit instrumentation

* fix test

* clippy

* fix

* fix tutorial

* sancov_8bit targets feature
2021-11-04 10:08:50 +01:00
Andrea Fioraldi
e46bb8643a Fix try_into in PyAny::cast_as in libafl_qemu 2021-11-04 10:01:13 +01:00
Jordan McLeod
3d436b7519
Upgrade to Rust 2021 Edition (#340)
* Enable missing const_xxh3 feature

* Move to Rust 2021 Edition

* Fix clippy complaints

* Remove imports made unecessary in 2021 edition
2021-11-04 09:59:49 +01:00
Toka
43a32f9e2b
fix (#345) 2021-11-03 18:57:54 +01:00
Toka
1ecef5598e
fix warnings on windows (#344) 2021-11-03 18:15:24 +01:00
Dominik Maier
12c470a707
Atheris example to fuzz Python Code (#300)
* initial atheris libfuzzer harness

* cmplog, kinda

* added makefile to generic_inmemory

* Makefile for atheris fuzzer

* moved away from clap yaml

* fixed arg parsing

* fuzzing

* ldpreload lib to replace exit with abort

* fixed docker, docs

* fix docker some more

* better documentation

* less commented out important things

* Make makefile less crashy
2021-11-03 10:13:05 +01:00
Andrea Fioraldi
2055eabede
Port gramatron preprocessing to Rust (#341)
* grammatron random mut

* import String from alloc

* gramatron

* grammar preprocess scripts

* clippy

* fix construct_automata.py

* splice mutator

* fix

* clippy

* recursion mutator

* recursion mut in example

* clippy

* fix

* clippy

* grammars

* fix gramatron

* fmt
2021-10-28 10:37:31 +02:00
Farouk Faiz
7eb293e087
Minor doc fixes (#339) 2021-10-26 01:10:58 +02:00
Alexandru Geană
f5bed190e7
add support for aarch64 in libafl_qemu (#335) 2021-10-25 22:38:26 +02:00
julihoh
52580c6c14
fix concolic nofloat filter (#333)
* fix concolic nofloat filter

* fmt

* whoops

* fix warnings
2021-10-25 13:57:49 +02:00
Dominik Maier
3f1130a8a4
fixes for frida mode for win and checks in rust 1.56 (#334)
* fixes for frida mode for win

* missing bracket

* fix docs

* fix docs, add windows ci

* disable breaking ci
2021-10-25 11:49:34 +02:00
Andrea Fioraldi
77e0be218a
Gramatron (#332)
* grammatron random mut

* import String from alloc

* gramatron

* grammar preprocess scripts

* clippy

* fix construct_automata.py

* splice mutator

* fix

* clippy

* recursion mutator

* recursion mut in example

* clippy

* fix

* clippy

* grammars
2021-10-21 16:33:40 +02:00
Andrea Fioraldi
23edffd4c1 Ooops, fmt 2021-10-18 10:57:33 +02:00
Andrea Fioraldi
0ed9dc6d80 Panic message in the map feedback 2021-10-18 10:56:39 +02:00
Andrea Fioraldi
bc4770fb82 Revert "Error message in most likely case of using NONASAN and ASAN fuzzers using the same Fuzzer config (#329)"
This reverts commit d71f0cf5bf4fc449585a4087e5fcf4a8eb443e38.
2021-10-18 10:46:08 +02:00
Marcin Kozlowski
d71f0cf5bf
Error message in most likely case of using NONASAN and ASAN fuzzers using the same Fuzzer config (#329)
* Error message in most likely case of using NONASAN and ASAN fuzzers using the same Fuzzer config

* Typo

* Changed to panic. Executed cargo fmt
2021-10-15 09:56:26 +02:00
intrigus-lgtm
0a1e8be256
Fix Typo. (#330) 2021-10-14 18:57:39 +02:00
Andrea Fioraldi
a782e8faaa CmpValuesMetadata empty serialization 2021-10-14 17:04:03 +02:00
Andrea Fioraldi
279fb3f213 Launcher: restore fs::File but open just before dup2 2021-10-14 16:10:07 +02:00
Andrea Fioraldi
ab7672c8d1 Launcher: use libc::open instead of fs::File 2021-10-14 15:57:32 +02:00
julihoh
2e55d24f5a
update deps (#327)
* experimental update deps

* Reverted to rand-core 0.5.1 for Lain compatibility

* updated nix

* less strict libc dep

* remove deprecated errno conversion

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-10-12 10:32:21 +02:00
Dominik Maier
44d844e1e2
32 bit arm regs (#315)
* aarch and arm regs

* fix arm, remove aarch64

* remove aarch64 mod
2021-10-11 22:20:19 +02:00
julihoh
7930d42948
update packages related to concolic (#325)
* update packages related to concolic

* install z3 on CI macOS

I have no clue how this worked before...

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-10-11 21:24:37 +02:00
julihoh
6e2aa47285
add ability to trace location information in concolic tracer (#322)
* add ability to trace location information in concolic tracer

* fix formatting

* introduce location new-type

* fix conolic smoke test

* impl From instead of custom into_inner function

* fmt

* change to use usize instead of NonZeroUsize

in order to no over-constrain the implementation
2021-10-11 13:31:16 +02:00
Dominik Maier
721286da86
delayed checkout in ci (#326) 2021-10-11 11:45:35 +02:00
julihoh
b778f22c0c
don't include all of libafl for symcc_runtime by default, as it's not necessary (#320) 2021-10-11 09:53:15 +02:00
julihoh
8a20d26ea6
init git sumbolude for symcc for symcc_runtime crate when publishing (#321) 2021-10-10 21:19:58 +02:00
julihoh
6c5f7366ce
concolic optional runtime (#319) 2021-10-10 21:17:40 +02:00
Toka
c0d40a43e1
remove libafl_tests (#324)
* remove libafl_tests

* fmt

* fix

* fix

* fix
2021-10-10 20:44:49 +02:00
julihoh
7231a66104
fix tutorial fuzzer (#323) 2021-10-10 16:13:01 +02:00
David CARLIER
939784d512
dumping process address maps on netbsd (#316) 2021-10-06 00:18:40 +02:00
Andrea Fioraldi
131483410f Update QEMU git hash 2021-10-04 10:44:55 +02:00
Andrea Fioraldi
91ce28deac
Python generic qemu hook (#314)
* python generic hook and value

* python generic hook
2021-10-01 17:10:35 +02:00
Andrea Fioraldi
a420eb0513
Qemu generic hooks (#313)
* generic hooks

* Fix generic hooks
2021-10-01 16:27:26 +02:00
Andrea Fioraldi
7e176ff292
Qemu partial instr fix (#312)
* fix edges hashtable query bug in hook

* fmt

* clippy
2021-10-01 14:31:19 +02:00
Andrea Fioraldi
f2929b8253
Allowlist and denylist for QEMU edges and cmps (#311)
* fix edges hashtable query bug in hook

* fmt
2021-10-01 14:28:24 +02:00
Andrea Fioraldi
90928d3d97
Qemu Helpers and basic snapshotting (#310)
* store executor_ptr

* QemuHelpers

* working hooks and snapshot helper

* walk only the list of dirty pages on restore()

* mem hooks for snpashot

* brk snapshot

* snapshot method

* macos shit

* sugar and clippy
2021-10-01 12:17:28 +02:00
Toka
f63b862160
Frida for Windows (#287)
* harness.cc for win

* no backtrace for frida_gum

* build.rs message

* cfg guards

* at least libafl_frida builds with cfg guards

* fuzzer.rs builds on win

* clean up

* build instructions

* ps

* fix

* clang

* fix

* article

* static option to make it run on powershell

* vscode build instructions

* dllexport!

* fix

* build.rs

* fix & fmt

* message

* msys not necessary anymore

* Update README.md

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-09-29 22:10:15 +02:00
Andrea Fioraldi
5a246175cf Fix pyo3 cfg_attr+new nosense 2021-09-29 18:07:57 +02:00
Dominik Maier
5a722994ac
Still fixing CI (#305)
* clippy

* clippy on windows

* clippy fixes on windows

* clippy, fmt

* fixed testcases for windows

* fixing workspace.yml

* testcase no longer fails without clang

* fix github dependencies to specific revisions

* fix qemu without python

* cleanup HookResult
2021-09-29 17:58:09 +02:00
Andrea Fioraldi
a1bf21465f Fix missing cfg_attr in libafl_qemu 2021-09-29 17:33:49 +02:00
Andrea Fioraldi
9004add503 Clippy fixes 2021-09-29 16:44:39 +02:00
Andrea Fioraldi
c6f7c3b3a8
Qemu new syscall hook and more python API (#306)
* new syscall hook

* expose more qemu to pylibafl

* hook syscalls from python

* update python example

* clippy

* clippy
2021-09-29 16:36:40 +02:00
Andrea Fioraldi
05aeb677cf
Fix default UBSan options and avoid timeouts in crash handler (#304)
* exit

* ignore timeouts outside the targets

* do not store timeouts

* block sigalarm in handlers

* __ubsan_default_options
2021-09-29 09:28:55 +02:00
Dominik Maier
2c51c4abf4 fmt 2021-09-28 21:01:35 +02:00
Dominik Maier
9d669bbc63
Fixed CI by ignoring python, resolved multiple warnings (#303)
* fixing ci

* ignoring dev deps

* fmt

* trying to fix dockerfile

* fix cargo build

* can't build sancov edges and hitcounts together

* fixed warnings

* fixed more warnings
2021-09-28 01:56:07 +02:00
Andrea Fioraldi
a0cdaf71ff Fix not NUL-terminated argv in libfuzzer_initialize 2021-09-27 17:48:06 +02:00
Andrea Fioraldi
54ac57b6f7 Default ASan options from AFL++ in libafl_targets 2021-09-27 15:24:35 +02:00
Andrea Fioraldi
96bbe37cc1 Remove unused files from old libafl_qemu 2021-09-27 14:51:04 +02:00
Andrea Fioraldi
ed228147a0 Python QEMU example fuzzer 2021-09-27 14:48:44 +02:00
Andrea Fioraldi
21f88b58b5 Pylibafl 2021-09-27 14:09:15 +02:00
Andrea Fioraldi
171c85fc4f Book: optional linkcheck 2021-09-27 09:53:15 +02:00
Andrea Fioraldi
40b73d4b1b
Book refactoring and update (#280)
* llmp docs skeleton

* llmp documentation

* more llmp docu

* llmp

* some core concepts

* start working on tutorial

* adapted rng_core to lain

* fix tutorial build

* warnings, format

* add explanation

* No need to own the types

* metadata

* writing

* fmt

* tutorial folder

* lain needs nightly

* added mdbook test to ci

* fix ci, add linkcheck

* more book

* baby

* tutorial target

* fix mdbook build

* fix mdbook test

* more book

* fixed typo

* fixed build

* spawn instances'

* 'finish' book

* added sugar crate information

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-09-27 09:39:32 +02:00
Andrea Fioraldi
2f2634db02
Python basic bindings for sugar and qemu (#302)
* InMemoryBytesCoverageSugar python binding

* InMemoryBytesCoverageSugar python binding

* python mod for qemu in libafl_sugar

* libafl_qemu python

* fix

* clippy fixes

* clippy

* added pyo3-build-config for MacOS builds

* gitignor

* python is not default

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-09-27 09:39:21 +02:00
Dominik Maier
01a98bf8fd
Example how to build baby-fuzzer as push instead of pull, using Klo-routines (#227)
* iyielding fuzzer

* fixed klo example

* docu, naming

* more readme
2021-09-25 22:54:46 +02:00
bitwave
e17f4b846f
Added documentation for no_std build and fuzzing (#282)
* added unfinished no_std docs

* docs: added missing example

* Update no_std.md

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-09-24 20:26:45 +02:00
Andrea Fioraldi
1fde608145
Qemu as lib (#301)
* linking problems

* use shared lib

* ci

* clippy, ci fixegit pushs

* ingoring distclean result

* clippy

* clippy

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-09-24 13:22:33 +02:00
Andrea Fioraldi
8f5df699fe fuzzbench_gsoc: set swarm num to 5 2021-09-24 13:20:50 +02:00
Andrea Fioraldi
fd39938ac7 Add fuzzbench gsoc to fuzzers/ 2021-09-24 11:23:26 +02:00
Dominik Maier
3fe8c2c044
cbz, tbz, tbnz support for aarch64 cmplog (#298)
* add support for cbz/tbz

* remove unecessary print

* implemented support for tbz

* add support for tbnz

* fix an error in the emitted code for both tbz/tbnz

Co-authored-by: Omree <Omree10@gmail.com>
2021-09-17 03:03:27 +02:00
Lukas Seidel
f0d5c2f708
armv7 support: add ucontext struct definition (#297)
* add uncontext and mcontext struct defs for armv7

* formatting

* merge import lines
2021-09-14 13:58:03 +02:00
Dominik Maier
55c4b0c778
added write_file_atomic against ondisk corpus races (#294)
* fix ondisk corpus race condition

* move metadata name to be a dotfile

* note ExitKind for crashes and timeouts in inprocess executor

* potential fix for windows

* added write_file_atomic

* no_std fixes

* no_std testcase fix

* typo fix, windows

* clippy

* more no_std testing
2021-09-13 15:38:28 +02:00
Toka
b9edb29d8b
PowerSchedule::COE fix (#295) 2021-09-13 14:24:31 +02:00
Dominik Maier
9eba674467 implement Debug for EventManagerId 2021-09-12 12:26:08 +02:00
s1341
b4aa22458d
Add core_id to launcher run_client closure signature (#290)
* Add core_id to launcher run_client closure signature

* Format

* Attempt to fix windows build

* windows

* Sleep for index seconds instead of id seconds when launching cores (#292)
2021-09-12 09:49:36 +02:00
Dominik Maier
b71704b14d
ShMem server race-condition fix for #276 (#278)
* This fixes a potential race condition when the parent dies before the child connects after a fork (#276)

* fix docs

* trying to fix shmem server forking

* removed bug where decreasing map count to 0 would not be reallocatable

* ignored clippy warning, refactoring
2021-09-07 00:03:37 +02:00
bitwave
e7ed5be9a2
Use external, custom time function for no_std environments (#281)
* Use external, custom time function for no_std environments

* fixup! Use external, custom time function for no_std environments

* fixup! Use external, custom time function for no_std environments
2021-09-06 19:13:45 +02:00
Dominik Maier
d8ef1dd90a fix Android build on MacOS 2021-09-06 12:53:58 +02:00
Dominik Maier
9cd34865a8 removed unused import 2021-09-06 12:07:21 +02:00
Andrea Fioraldi
42d213737d
Build id configuration in std (#286)
* Build id configuration in std

* uuid only on std
2021-09-06 10:25:32 +02:00
Andrea Fioraldi
231caf0797 reset() method for FeedbackState 2021-09-06 10:00:26 +02:00
Toka
d136ee7427
Fix _LLMP_BIND_ADDR for Windows (#285)
* ipv6

* client connects to localhost

* v4 when v6 not available

* remove v6 addr
2021-09-03 12:36:49 +02:00
David CARLIER
774cfb685e
openbsd port (#279)
with libc update, ucontext data is finally available on this platform too.
2021-08-27 11:41:06 +02:00
Andrea Fioraldi
14d1f63e56
Token level fuzzing (#274)
* EncodedInput

* some encoded mutations

* Encoded parse using comments and strings regexes

* working js example

* better mutator

* clippy
2021-08-27 09:32:22 +02:00
Dominik Maier
45dd940532 autocomplete... 2021-08-26 20:48:33 +02:00
Dominik Maier
c9642ec275 ignored warnings 2021-08-26 20:30:11 +02:00
Dominik Maier
985af28c58 less clippy 2021-08-26 19:55:38 +02:00
Dominik Maier
3db1765537 cleanup 2021-08-26 19:25:48 +02:00
Andrea Fioraldi
6ae36ce658
Refactor configurations with EventConfig (#277)
* switch to EventConfig

* adapt fuzzers

* fix tests

* fix sugar

* clippy

* ahash
2021-08-26 13:25:03 +02:00
Andrea Fioraldi
7d249dd306 Update libafl-qemu-bridge commit && libafl_qemu 2021-08-24 16:03:33 +02:00
Dominik Maier
7c086f1877
Build LibAFL Android in CI (#275)
* trying to fix android ci

* fix?

* still trying to fix android ci

* we don't produce a cdylib, so let's not output the target
2021-08-24 11:39:57 +02:00
Andrea Fioraldi
2301335bf7 Bump symcc_runtime to 0.1.2 2021-08-23 11:32:03 +02:00
Andrea Fioraldi
951b6fef36 Bump 0.6.1 2021-08-23 10:01:22 +02:00
julihoh
bdd1412fc4
Symcc runtime docsrs fix (#270)
* add symcc as submodule

* make build script docs.rs aware

* bump version of symcc_runtime
2021-08-23 09:55:13 +02:00
s1341
fccb9a1c55
Fix shmem on android (#272)
* Fix shmem on android

* Switch back to ulong
2021-08-23 09:46:54 +02:00
Dominik Maier
5caeb46b67
renamed target_os macos to target_vendor apple (#273)
* renamed target_os macos to target_vendor apple

* fix yaml
2021-08-23 09:45:25 +02:00
julihoh
d1021c7a9a
initial book entry for concolic (#257)
* initial book entry for concolic

* update links to still work with fixed version of symcc_runtime

* spelling
2021-08-23 09:28:10 +02:00
David CARLIER
8f03d20200
process crash handler, dump registers on apple arm64 (#271) 2021-08-21 14:47:55 +02:00
Andrea Fioraldi
65b5051c7c Update libafl_sugar Cargo.toml for publication 2021-08-20 09:47:01 +02:00
Andrea Fioraldi
753d1e5381 Fix publish.sh 2021-08-20 09:39:57 +02:00
Toka
b6d22a2fbb
Drop for TimeoutExecutor on win10 (#269)
* small fixes

* update .gitignore
2021-08-19 09:11:16 +02:00
Andrea Fioraldi
7ca7b3c9f6 Update publish script 2021-08-18 11:34:44 +02:00
julihoh
dcf107a30a
symcc_runtime dependency fix for next libafl version & bump to 0.6.0 (#268)
* symcc_runtime dependency fix for next libafl version

* bump to 0.6.0

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-08-18 10:57:55 +02:00
Andrea Fioraldi
83f413f8b1 Default weak fns impl on MSVC 2021-08-18 10:45:50 +02:00
Andrea Fioraldi
cc52e20256 Weak libafl_main in libfuzzer_compatibility.c 2021-08-18 10:36:54 +02:00
Toka
688182fd1e
Timeout for Inprocess Executor on Windows (#267)
* start working on windows timeout

* salvage Input in timeout handler

* this time inproc_timeout_handler (need clean up later)

* cleaup

* more in inproc_timeout_handler

* fix for linux build

* more fixes for unix, fmt

* revert timeoutexecutor api

* revert baby_fuzzer/src/main.rs

* various fixes

* no unsafe

* remove timer in crash_handler
2021-08-18 09:11:34 +02:00
Toka
d7ec395010
Forkserver Shared Memory Testcase (#265)
* working on shmem testcase fuzzing

* fmt & clippy

* write_to_testcase

* write input size

* max os fixes

* RcShMemProvider?

* ServedShMemProvider?

* revert changes

* RcShMem<ServedShMemProvider<MmapShMemProvider>>?

* ShMem change for android? (not tested at all)

* harness

* shmem testcase fuzzing for timeoutforkserver

* update harness

* remove .o

* pselect instead of select

* clippy
2021-08-17 01:44:17 +02:00
Fabian Freyer
15c6e6b73b
libafl_frida: remove non-gnu hooks on macos (#262)
The following functions are GNU extensions and therefore
not available on superior systems:
- explicit_bzero
- malloc_usable_size
- memalign
- mempcpy
- memrchr
2021-08-15 08:51:47 +02:00
Fabian Freyer
6435af3419
bolts::cpu: fix docs link (#264) 2021-08-15 07:08:37 +02:00
Toka
511237ce9e
Windows dependency update (#261)
* win018

* fuzzer fmt

* reorder

* comment

* does
2021-08-14 23:04:13 +02:00
David CARLIER
1418e836a0
shmem code simplification using more libc crate which fixes couple of wrong C fn signatures (#259) 2021-08-12 09:49:26 +02:00
Dominik Maier
cb8efd3abf
shmem service speedup env (#256)
* shmem service speedup env

* typos, cleanup

* fmt
2021-08-09 09:23:12 +02:00
Dominik Maier
ee33faa881
Bring back libpng CI on MacOS (#255)
* Makefile fix for libpng on MacOS (#252)

* clean exit for libpng_launcher
2021-08-09 02:59:39 +02:00
Dominik Maier
bb21ab7a63
Autolaunch ShMemService, add MacOS fuzzers to CI, various fixes (#246)
* starting to fix macos linker bugs

* mdetailed error prints

* start shmem service manually

* not a doc comment

* Some fixes

* only send exit msg to shmemservice when start was successful

* incorporated shmem service into provider

* removed unused imports

* trying to fix fuzzers

* fixed build

* check if join_handle is_some

* more debug prints

* fixed shmem service autolaunch

* fixed macos linker

* ignoring broken libpng testcase on macos for now (see #252)

* fmt

* try to fix missing llvm_config (see #253)

* empty issue template added

* Mmanually look for llvm-config on MacOS

* fixing CI

* fixed docs

* ignoring libmozjpg for CI, see #254
2021-08-09 01:10:29 +02:00
julihoh
ac8bbdbd0a
add vscode development container configuration (#249)
* add development container configuration

* Change name of devconfigurationn

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-08-08 11:13:07 +02:00
Toka
7f4e341741
inprocessfork executor (#237)
* inprocessfork executor

* fmt

* cfg

* no_std

* no volatile rw

* wrapping_add

* fix

* mutable pointer

* ptr initialization in __sanitizer_cov_trace_pc_guard_init

* features

* more cfg

* fmt

* fix

* fmt

* post_fork

* fmt

* pre_fork

* test

* cfg
2021-08-07 12:09:54 +02:00
julihoh
18abf8f78a
fix libafl_concolic in docker image (#248) 2021-08-06 17:51:53 +02:00
julihoh
7581885d52
prepare concolic support crates for publishing to crates.io (#250)
* prepare concolic support crates for publishing to crates.io

* provide some bare-bones READMEs
2021-08-06 17:49:57 +02:00
julihoh
e971f240da
Concolic example fuzzer fixes (#251)
* fix compilation of runtime of concolic example fuzzer

* fix compilation of example fuzzer

* fix incorrect traced target configuration

this would lead to the runtime never tracing any expressions.
failed to specifiy the input file name for the runtime to know what to symbolize

* add ability to specify whether a node should do concolic or traditional

* slightly more realistic concolic solving by using solver timeout

* enable expression pruning
2021-08-06 17:47:50 +02:00
julihoh
2282b09ef5
fix warnings hopefully (#245) 2021-08-05 21:57:47 +02:00
julihoh
1dddf7e677
Separate symcc crate (#244)
* create a separate crate for symcc url and commit hash

also contains functions to checkout and build symcc from a build script

* fix dockerfile

* clippy
2021-08-05 21:57:39 +02:00
Dominik Maier
16c3a07be7
ShMem Server for MacOS (#238)
* generalized ashmem server

* fixed macos testcases

* added StdShMemService

* no_st

* fmt

* added testcase, fixed some bugs (not all)

* solidified unix shmem

* initial impl for MmapShMem

* Added shmem service start to more testcases

* clippy

* fixed tetcases

* added frida_libpng makefile for easy use

* trying to fix build on ubuntu

* fixed ubuntu build for libpng

* no_std

* fixed testcase
2021-08-05 17:08:01 +02:00
julihoh
704830a501
Documentation and Refactors for Concolic (#243)
* document symcc_runtime

* rename serialization format expressions to be more concise

* authorship notes

* document dump_constraints

* document smoke test

* tests for serialization format and refactoring

* remove unused bswap message

* remove obselete SymExpr::End

* document and refactor serialization format

* fmt

* more missing docs

* typos

* clippy
2021-08-05 15:01:14 +02:00
julihoh
3d98d31712
Concolic Tracing (#160)
* add stub runtime that links with symcc common runtime code

* implement tracing runtime to generate message file

* move ShMemCursor to libafl proper

* qualify enum imports to make clippy happy

* fix warnings

* formatting

* update symcc submodule to point to AFL++ org repo

* fix naming of ShMemCursor and remove std requirement

* ensure runtime is named correctly after compilation

* add devcontainer files for easier development

(will be removed later)

* move rust nightly install into devcontainer.json

this makes it run after the container has been built

* dev container: install recommended packages

* switch to building rust runtime from SymCC cmake

* install corrosion in dev container for cmake-cargo integration

* add smoke test for symcc-runtime integration

* update symcc submodule

* add rustfmt to devcontainer

* properly mark the end of a constraint trace

Using a special "End" message

* small tool to dump constraints from a traced process

* extend smoke test to include parsing & printing of constraints

* update symcc submodule

* first draft of expression filters for concolic

* fix type in runtime method name

* update symcc submodule

* implement extensions to serdeany map:

* remove -> Option<T>
* insert_boxed(Box<T>) (avoids allocation if value is already boxed)

* implement std::io::Seek for ShMemCursor

* implement framing for in-memory traces

this allows to efficiently get the length of trace.
this is important for efficiently copying the trace out of the shared
memory region.

* fix for serdeany map

* fuzzer that associates concolic traces with test
case

* ensure runtime can handle 0-expressions

* move metadata, observer and feedback into separate files

* convert executor to command executor and move to separate file

* refactoring and streamlining

* move panic mode configuration to cmake script

* compile cmake from source, because debians version is too old.........

* use separate stage for tracing

* fix dockerfile

* move runtime into the workspace

using prior work on compilation flags from cmake

* actually make use of selective symbolication filter

* update to support latest symcc changes

* implement hitmap for concolic runtime

* clippy

* implement selective symbolization and coverage map for dump_constraints tool

* use concolic runtime coverage for concolic fuzzer feedback

* actually kill process on timeout

* be extra careful after killing process

* increase command executor busy wait to 5ms

* implement concolic tracing stage

* address naming issue

* implement floating point expression filter for runtime

* rename expression filters to be less verbose

* implement expression pruning

* implement ConcolicMutationalStage

* refactor command executor and remove busy loop

* implement generic command executor

* remove debug prints

* refactor + documentation

* refactor

* add stub runtime that links with symcc common runtime code

* implement tracing runtime to generate message file

* move ShMemCursor to libafl proper

* qualify enum imports to make clippy happy

* fix warnings

* formatting

* update symcc submodule to point to AFL++ org repo

* fix naming of ShMemCursor and remove std requirement

* ensure runtime is named correctly after compilation

* add devcontainer files for easier development

(will be removed later)

* move rust nightly install into devcontainer.json

this makes it run after the container has been built

* dev container: install recommended packages

* switch to building rust runtime from SymCC cmake

* install corrosion in dev container for cmake-cargo integration

* add smoke test for symcc-runtime integration

* update symcc submodule

* add rustfmt to devcontainer

* properly mark the end of a constraint trace

Using a special "End" message

* small tool to dump constraints from a traced process

* extend smoke test to include parsing & printing of constraints

* update symcc submodule

* first draft of expression filters for concolic

* fix type in runtime method name

* update symcc submodule

* implement extensions to serdeany map:

* remove -> Option<T>
* insert_boxed(Box<T>) (avoids allocation if value is already boxed)

* implement std::io::Seek for ShMemCursor

* implement framing for in-memory traces

this allows to efficiently get the length of trace.
this is important for efficiently copying the trace out of the shared
memory region.

* fix for serdeany map

* fuzzer that associates concolic traces with test
case

* ensure runtime can handle 0-expressions

* move metadata, observer and feedback into separate files

* convert executor to command executor and move to separate file

* refactoring and streamlining

* move panic mode configuration to cmake script

* compile cmake from source, because debians version is too old.........

* use separate stage for tracing

* fix dockerfile

* move runtime into the workspace

using prior work on compilation flags from cmake

* actually make use of selective symbolication filter

* update to support latest symcc changes

* implement hitmap for concolic runtime

* clippy

* implement selective symbolization and coverage map for dump_constraints tool

* use concolic runtime coverage for concolic fuzzer feedback

* actually kill process on timeout

* be extra careful after killing process

* increase command executor busy wait to 5ms

* implement concolic tracing stage

* address naming issue

* implement floating point expression filter for runtime

* rename expression filters to be less verbose

* implement expression pruning

* implement ConcolicMutationalStage

* refactor command executor and remove busy loop

* implement generic command executor

* remove debug prints

* refactor + documentation

* refactor

* fixed build, clippy

* no_std

* implement WithObservers executor as discussed

* add symqemu as a submodule

* fix symqemu submodule URL to be relative

* update the concolic runtime to match the new interface

* update the trace file header regularly to save constraints in case the program crashes

* add build dependencies for symqemu

* handle full mesage buffer properly

* better policy for updating trace header

* less aggregiously inefficient GC information serialization

* move concolic runtime hitmap count to filter

this is in preparation for the new runtime interface

* very WIP new runtime interface

* use more convenient types in rust runtime

* EmptyRuntime -> NopRuntime

* hide cpp_runtime and formatting

* implement tracing runtime using new runtime interface

* implement filters with new runtime interface

* use a local checkout for symcc_runtime

* make test runtime tracing

* use test_runtime in smoke test

* fix formatting

* make the clippy overlord happy?

* disable symcc build on everything but linux

* make more of symcc_runtime linux only

* fix linking symcc_runtime with C++ stdlib

* will clippy ever be happy?

* formatting

* don't export symcc runtime when compiling tests

* clippy...

* "don't export symcc runtime when compiling tests" for runtime crate as well

* clippy

* move command executor to LibAFL

* move concolic crate into LibAFL

* move concolic{metada,observer} into LibAFL

* move ConcolicFeedback into LibAFL

* move ConolicStage into LibAFL

* fix bug in symcc part of concolic runtime

* stb_image fuzzer with concolic as example fuzzer

* clean up basic_concolic_fuzzer

* clean up and document concolic example fuzzer

* formatting

* clippy

* remove basic_concolic_fuzzer (it is now part of the examples)

* remove the runtime crate in favor of symcc_runtime

* re-architect concolic smoke test and remove git submodules

* remove old submodule directories

* make coverage filter public

* focker docker build

* clippy

* clippy fixes

* fix ubuntu as well

* remove .gitmodules

* move concolic mutational stage into libafl behind feature flag

* script to install dependencies for concolic smoke test

* fix bug

* clippy

* add github action to run smoke test

* fix action

* ensure smoke test is run in correct directory

* remove devcontainer files

* address feedback

* clippy

* more clippy

* address more feedback

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-08-05 13:22:00 +02:00
Dominik Maier
4d50ba277a fixed typo 2021-08-04 15:29:42 +02:00
Dominik Maier
92ba3f59f9
StateRestorer.reset() removes old tmpfile (#242)
* StateRestorer.reset() removes old tmpfile

* checking map size on deref for extra safety

* clippy
2021-08-04 15:13:54 +02:00
s1341
3fac056b58
strdup is an allocating function, treat it as such (#241)
* strdup is an allocating function, treat it as such; poison target bytes after run

* Add cfg guards
2021-08-04 15:03:49 +02:00
Dominik Maier
5542a81e12
Added state restorer testcase, fixed restorer (#240)
* added state restorer testcase

* fixed testcase

* no_std, clippy

* printing less often
2021-08-03 23:53:30 +02:00
Dominik Maier
ff589d9a89 clippy fixes 2021-08-03 12:51:20 +02:00
julihoh
7750707fee
fix ci for latest clippy version (#239)
* clippy

* fix ubuntu as well
2021-08-03 12:29:30 +02:00
Dominik Maier
38c657338c added testcases for state restore, bugfixes 2021-08-03 05:12:51 +02:00
Toka
bfe0a97077
AFLFast (#208)
* Defined PowerScheduleTestcase

* calibrate stage

* powerschedule

* PowerQueueCorpusScheduler

* Calstat

* Integer for observer

* update power.rs

* calculate_score

* no_std

* no_std

* calibrate_case

* calculate_score done

* update fuzz_level

* update depth

* rename, PowerScheduleQueueScheduler::next

* increment hashmap

* n_fuzz

* no_std

* fmt

* clippy

* check bitmap_size

* hash

* compile

* rename, vec

* fuzzer runs

* fixes

* rename, no_std log2

* fmt

* clippy

* fmt

* unused imports

* use exec_time

* getter/setter

* No unwrap

* ToString

* fixes

* ahash

* fmt

* use favored from power.rs side

* rename

* IsFavoredMetadata

* run_target

* clippy fixes

* doc & fix

* doc

* rename

* forgot log2

* fix

* fix

* added comments explaining why the COE and FAST schedules are different from the thesis

* saturated increment

* saturating_add

* put n_fuzz in PowerScheduleMetadata

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-07-28 21:19:50 +02:00
Andrea Fioraldi
77541da9fd Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-07-28 15:12:37 +02:00
Andrea Fioraldi
1692bbc214 Remove debug print 2021-07-28 15:12:28 +02:00
Dominik Maier
7e93aaaf38 give shmem more space 2021-07-23 16:12:02 +02:00
Dominik Maier
a907435f4f added afl-persistent-config script 2021-07-23 15:40:27 +02:00
Andrea Fioraldi
0bd292f2ae Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-07-22 11:58:32 +02:00
Andrea Fioraldi
7e06b90364 Fix SimpleRestartingEventManager broken generics 2021-07-22 11:58:24 +02:00
s1341
5156b4cf8f
staterestore File::open should be File::create (#235) 2021-07-22 11:38:43 +02:00
David CARLIER
90b7ae08d6
x86 32 bits build fix (#234) 2021-07-21 21:48:33 +02:00
Andrea Fioraldi
2faf1d24c8
Hook syscalls in QemuBytesCoverageSugar (#233)
* add x64 syscalls numbers

* syscall hook

* update commit

* read guest mappings

* clippy

* read write hooks

* automerge fix

* type fix

* hooks syscalls in sugar
2021-07-21 12:29:46 +02:00
Andrea Fioraldi
db820d56a2
Qemu memory hooks (#232)
* add x64 syscalls numbers

* syscall hook

* update commit

* read guest mappings

* clippy

* read write hooks

* automerge fix

* type fix
2021-07-21 12:28:06 +02:00
Andrea Fioraldi
8e745f7d90 Remove useless fuzzbench_qemu build deps 2021-07-21 11:18:33 +02:00
Andrea Fioraldi
dfe39e2af7
libafl_sugar (#215)
* fuzzer mod

* libafl_sugar skeleton

* build libafl_sugar

* libfuzzer_stb_image_sugar

* Delete log

* qemu in libafl_sugar

* docker

* macos merda

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-07-20 11:47:33 +02:00
Dominik Maier
9591ed995e
Panic on Too Slow Broker (#230)
* panic on too slow broker

* constant for max pending pages
2021-07-20 02:39:03 +02:00
David CARLIER
b0cb74324c
fix android arm64 build (#231) 2021-07-20 02:38:44 +02:00
Andrea Fioraldi
230d7a1cb1
CachedOnDiskCorpus (#229)
* sized inputs

* push CachedOnDiskCorpus and fix OnDiskCorpus

* comments
2021-07-16 16:34:43 +02:00
Andrea Fioraldi
5cd7339b1a
Qemu read memory mappings (#228)
* add x64 syscalls numbers

* syscall hook

* update commit

* read guest mappings

* clippy
2021-07-16 10:38:00 +02:00
Dominik Maier
5a14b870e2
Added staterestore to restarting mgrs (#225)
* added staterestore to simple restarting mgr

* reworked launcher

* ? instead of unwrap

* no_std fixes

* windows

* fixed save fn

* added llvm to dockerfile
2021-07-15 13:13:07 +02:00
Andrea Fioraldi
b09fa4e3f4
Qemu syscalls hook (#226)
* add x64 syscalls numbers

* syscall hook

* update commit
2021-07-15 11:12:10 +02:00
Andrea Fioraldi
ac783c6119 Fix inifnite serialization for CmpValuesMetadata 2021-07-15 09:58:23 +02:00
Andrea Fioraldi
ec4c5ae88a
remove timeout on crash (#224) 2021-07-13 16:15:12 +02:00
Andrea Fioraldi
42b7c6d7e7
Qemu CmpLog (#223)
* empty libafl_qemu crate

* fuzzbench qemu fuzzer skeleton

* emu.run() works without bp

* working emu loop

* resolve elf symbols

* running Qemu fuzzer without coverage

* qemu fuzzer with edge coverage

* merge into inprocess::GLOBAL_STATE

* create QemuExecutor and remove QemuEmulator

* qemu hooks and persist edges mapping storing them in State

* windows fix

* add libafl_qemu to workspace

* windows fix

* some clippy

* clippy

* fix fuzzbench_qemu

* fix fuzzbench_qemu makefile

* fuck you macos

* resolve PIC symbols

* cmp hooks

* cmplog hooks

* qemu cmplog

* clippy
2021-07-13 16:02:53 +02:00
Dominik Maier
712c5daeb9
Reload corpus size after restart (addresses #210) (#220)
* reload corpus size after restart (addresses #210)

* no_std
2021-07-12 13:16:40 +02:00
Dominik Maier
a0ba0f0251 clippy 2021-07-12 10:30:41 +02:00
Toka
13b4a143b8
branch main (#219) 2021-07-11 01:47:01 +02:00
Toka
4dea81b2a2
MOpt Refactor & Bug fixes (#218)
* rename

* fmt

* post_exec

* post_exec

* bug fix & change type

* refactor

* clippy

* fix

* unnecessary trait

* mode in Mutator

* remove println
2021-07-10 16:32:10 +02:00
Dominik Maier
aad271abf4
Cache Rust in CI (#217)
* rust cache

* less warnings during docker build

* removed unused use
2021-07-10 14:42:10 +02:00
Dominik Maier
0121096e84
Fixes for no_std build (#214)
* builds on no_std

* fixed std build

* nightly fmt on CI

* nightly fmt on CI (again)

* fmt

* no_std build on unix

* more mem

* added no_std from #212 to gh workflow

* more ci, less nightly

* clippy

* more toolchains?

* docu

* y u no build

* more ci?

* next try

* fixed dockr

* more dockerfile fixes

* ondisk corpus fixed

* panic:?

* ubunutu

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-07-09 20:07:56 +02:00
Andrea Fioraldi
badf3f0e6e
Resolve symbols in PIC binaries in libafl_qemu (#216)
* empty libafl_qemu crate

* fuzzbench qemu fuzzer skeleton

* emu.run() works without bp

* working emu loop

* resolve elf symbols

* running Qemu fuzzer without coverage

* qemu fuzzer with edge coverage

* merge into inprocess::GLOBAL_STATE

* create QemuExecutor and remove QemuEmulator

* qemu hooks and persist edges mapping storing them in State

* windows fix

* add libafl_qemu to workspace

* windows fix

* some clippy

* clippy

* fix fuzzbench_qemu

* fix fuzzbench_qemu makefile

* fuck you macos

* resolve PIC symbols
2021-07-09 15:17:57 +02:00
Andrea Fioraldi
4af9af784f Serialize CmpValuesMetadata to an empty object to save space on State serialize 2021-07-09 14:35:31 +02:00
Andrea Fioraldi
fe57c5ecd6 Update book 2021-07-08 17:01:35 +02:00
Andrea Fioraldi
4b4773998c Update readme and todo 2021-07-08 15:23:59 +02:00
Andrea Fioraldi
d472a1242a
libafl_qemu (#211)
* empty libafl_qemu crate

* fuzzbench qemu fuzzer skeleton

* emu.run() works without bp

* working emu loop

* resolve elf symbols

* running Qemu fuzzer without coverage

* qemu fuzzer with edge coverage

* merge into inprocess::GLOBAL_STATE

* create QemuExecutor and remove QemuEmulator

* qemu hooks and persist edges mapping storing them in State

* windows fix

* add libafl_qemu to workspace

* windows fix

* some clippy

* clippy

* fix fuzzbench_qemu

* fix fuzzbench_qemu makefile

* fuck you macos
2021-07-08 15:21:14 +02:00
vanhauser-thc
d7dad357e2 enable github sponsor 2021-07-07 13:23:04 +02:00
Andrea Fioraldi
5b0c178ed6 Increase sleep in publis.sh 2021-07-05 14:55:27 +02:00
Andrea Fioraldi
a1fc2a5453 Bump to 0.5.0 2021-07-05 14:12:40 +02:00
Toka
849ff1fa04
MOpt scheduler (#161)
* add the struct for MOpt globals

* constants

* RAND_C

* more comments & reorder class members

* select_algorithm

* no_std fixes

* clippy fixes

* MOptMutator

* MutatorsTuple has HasLen

* MOptStage

* pso_update

* HasMOpt trait

* ScheduledMutator, core_fuzzing

* clippy fix

* fmt

* core_fuzzing

* core_fuzzing done

* fix

* pilot_mutate

* pilot_fuzzing

* pilot_fuzzing done

* MOpt metadata

* Make MOptMutator into a trait

* initialize_mopt

* No getter/setters

* fmt

* fixed compiler warnings & clippy warnings

* Comments

* fix type paramter, integrate into libpng

* fmt

* fmt

* No HasMOpt

* fmt

* improve

* pso_initialize, various fixes

* clippy

* fmt

* always pacemaker mode

* fmt

* fix

* less noisy fmt::Debug

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-07-05 13:54:15 +02:00
Toka
fbeec3ca6c
Faster feedback (#206)
* faster_feedback

* typo

* feedback_or

* comma

* crash dedup can use the fast one
2021-07-05 13:51:18 +02:00
Andrea Fioraldi
5b76c22ea7
Cmplog routines mutator (#204)
* save

* routines in meta

* execute passes

* fix cmplog rtn pass

* clippy
2021-07-05 09:54:44 +02:00
Dominik Maier
84a9e36acf
Github Actions Cache (#205)
* trying out github actions cache

* split up build steps

* deactivated cache for macos

* debugging

* also for windows (?))

* clippy fix

* out folder ignored
2021-07-02 20:51:22 +02:00
Toka
c01f1e3318
launcher example needs --cores (#203) 2021-07-02 16:52:27 +02:00
Toka
b3c52a4ad6
Test fuzzers (#187)
* build_all_fuzzer.shj

* run.sh

* output log

* ENABLE_SHARED off

* libc6-dev

* echo

* no need to cargo build twice

* replaced realpath (not available on macos) with /Users/domenukk/tmp/libaflrs/fuzzers/libfuzzer_libpng_launcher

* replaced PWD with pwd

* trying to get llvm-config working

* more sudo?

* slash

* trying to get all deps

* more info

* delete apt install from build_all_fuzzers.sh

* correct libfuzzer_libpng makefile

* fix build for libfuzzer_libpng

* fix other makefiles

* nproc not supported on macos

* no run.sh, use make short_test

* enable_shared=false

* just Linux

* fix

* forkserver makefile

* fix

* stb_image Makefile

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-07-02 15:35:41 +02:00
Andrea Fioraldi
f0743cbb17
remove serde bounds for Observer (#202) 2021-07-02 15:07:51 +02:00
Andrea Fioraldi
44f6e4c389
Improve introspection (#200)
* remove NUM_FEEDBACKS

* working introspection

* adust introspection stats

* bugfixes, clippy

* removed outdated define

* more clippy;

* no_std

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-07-02 10:58:36 +02:00
Dominik Maier
204b15a432
Mgr ID improvements (#201)
* added mgr_id to eventmanager

* trying to install missing llvm to ci

* moved mgr_id to own trait

* improved imports

* removed unrelated file from pr

* no_std fixes
2021-07-01 17:27:22 +02:00
Dominik Maier
4cafa8c253
added mgr_id to eventmanager (#196) 2021-06-30 21:58:06 +02:00
Dominik Maier
5a4e5b0a93
MacOS Build (#197)
* macos build

* more fix

* fixed clang pass build

* fixes for libfuzzer link

* more explanation links
2021-06-30 21:20:24 +02:00
Max Ammann
08263f7ade
Expose some details about introspection (#195)
* Expose some details about introspection, such that custom Stats implementations can use them

* Make the functions public

* Fix formatting
2021-06-30 14:16:36 +02:00
Dominik Maier
574a274be6 Merge branch 'main' into refix_shm_id 2021-06-30 13:14:28 +02:00
Dominik Maier
de4071bf23
Refix Shm ID (#194)
* print sender id

* storing sender id to env

* typo fix

* clippy fixes

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-06-30 09:06:51 +02:00
Dominik Maier
716af8920b clippy fixes 2021-06-29 12:30:49 +02:00
Dominik Maier
c2cd49413b typo fix 2021-06-29 12:09:49 +02:00
Dominik Maier
4a33dad9e4 Merge commit '6d2074bd7e2c7cdaba57a1a5b1c93886e9675663' into refix_shm_id 2021-06-29 12:06:40 +02:00
Dominik Maier
e479b4fa24 macos fixes 2021-06-28 16:18:17 +02:00
Andrea Fioraldi
8056cbe5cb Weak main to link non-fuzzing targets 2021-06-28 11:41:04 +02:00
Max Ammann
f60148fc76
Add simple issue templates (#189) 2021-06-25 14:05:34 +02:00
Andrea Fioraldi
5b54f0f068
Llvm passes (#185)
* enable llvm passes in libafl_cc

* cmplog rtn pass in fuzzbench fuzzer

* improve libafl_cc

* silence fuzzbench compiler wrapper

* instrumentation and runtime for rtn cmplog

* fix test

* fix test

* fuck clippy

* remove anon union in CmpLogMap

* windows.h

* remove libafl_targets_cmplog_wrapper

* no inline linking

* adapt fuzzers/
2021-06-23 09:38:15 +02:00
Dominik Maier
37f641f79b
Metadata lookup once (#186)
* metadata lookup once

* fix clippy
2021-06-22 18:41:46 +02:00
Andrea Fioraldi
bdb5efbf5b
Configurations (#162)
* print sender id

* storing sender id to env

* executor in llmp handle_in_client

* compile the lib

* compiling generic_inmemory

* fix forkserver

* adapt from fuzzers

* instrospection fix

* exitkind in NewTestcase

* fix libafl_frida

* fix firda_libpng

* send conf with Newtestcase event

* bump to 0.4.0

* no_std fix

* fmt

* fix libfuzzer_libmozjpeg

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-06-22 15:04:14 +02:00
Dominik Maier
5c5a1cf2e9
fixed fuzzbench early exits (#182) 2021-06-22 09:02:56 +02:00
Andrea Fioraldi
57d6df7951 Last and great fmt for fuzzbench 2021-06-21 17:56:09 +02:00
Andrea Fioraldi
abed61cc49 Propagate exit code in the compiler wrapper 2021-06-21 17:38:36 +02:00
Andrea Fioraldi
76892fddc6 Silence fuzzbench compiler 2021-06-21 17:15:09 +02:00
Andrea Fioraldi
ea40c21533 Fix args in fuzzers/fuzzbench 2021-06-21 14:17:35 +02:00
Andrea Fioraldi
fee9cae8ed Fix InProcessExecutor test mod 2021-06-21 11:58:04 +02:00
Andrea Fioraldi
3f1baf90b3 Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-06-21 11:39:51 +02:00
Andrea Fioraldi
6351cb16e5 Support multiple crash handlers when using multiple InProcessExecutors 2021-06-21 11:39:42 +02:00
Andrea Fioraldi
6c926c4841 Clippy go brrr 2021-06-18 10:02:44 +02:00
Andrea Fioraldi
8f5e2515dd Fix CI 2021-06-18 09:12:15 +02:00
Andrea Fioraldi
2fd8039f69 Fix max edges num count in pcguard 2021-06-17 16:56:35 +02:00
Andrea Fioraldi
5d49933a23 Fix libafl_targets 2021-06-17 10:55:12 +02:00
Andrea Fioraldi
e0fbe5bca2 Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-06-17 10:36:38 +02:00
Andrea Fioraldi
1ea8442478 Set maps size at compile time with env vars 2021-06-17 10:36:27 +02:00
Dominik Maier
8db453001f fixed fuzzbench some more 2021-06-16 23:41:08 +02:00
Dominik Maier
0af9c0c862
Fuzzbench fuzzer fix (#179) 2021-06-16 23:29:51 +02:00
Andrea Fioraldi
21508ee571 Remove useless trace-cmp 2021-06-16 19:02:39 +02:00
Andrea Fioraldi
d976b02609 Solve perf problem on CmpLog map reset 2021-06-16 18:59:15 +02:00
Dominik Maier
dea21da5c3
fuzzbench harness (#165)
* starting to build fuzzbench harness

* fuzzbench updated

* fuzzbench example readme

* removed dummy files

* Intial de-luxe dockerfile added

* added to dockerignore

* more fuzzbench

* dockerfile

* final dockerfile fun

* fuzzing fixes, switched rand, build fixes

* fmt

* added dummy fuzzone

* silence wrapper output

* clippy

* logfile fixes

* adopt changes to libafl-cc

* various fixes
2021-06-16 18:24:07 +02:00
Andrea Fioraldi
1faadec106
Move win32 libs in libafl_cc and improve static lib linking (#176)
* Move win32 libs in libafl_cc and improve static lib linking

* fmt
2021-06-16 14:21:13 +02:00
Gal Tashma
8202548648
dont send was_killed to forkserver more than once (#175)
Co-authored-by: galtashma <gal.tashma@swg.local>
2021-06-15 21:58:05 +02:00
Dominik Maier
c2feddbe7c
Implemented rand::Rng for libafl::Rand as feature flag (#174)
* implemented rand::Rng for libafl::Rand as feature flag

* fixed build

* renamed macro
2021-06-15 09:30:32 +02:00
Dominik Maier
b187157bef
Dockerfile for LibAFL (#168)
* generic inmemory fuzzer

* Intial de-luxe dockerfile added

* merged main

* reset generic fuzzer to main

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-06-14 20:56:37 +02:00
Gal Tashma
1b1060b35a
fix introspection for mutational stage (#172) 2021-06-14 14:40:36 +02:00
Toka
ad80df5bbb
compression fix (#170)
* compression fix

* use miniz_oxide

* fix Error::Compression
2021-06-14 11:06:53 +02:00
Andrea Fioraldi
2b0976132a
Generic Inmemory Fuzzer (#166)
* generic inmemory fuzzer

* Link whole archive

* fmt
2021-06-14 10:26:10 +02:00
s1341
ca4bdd3e3b
frida: small fixes (#169)
* Too large allocs should return 0; Don't forcibly free unfreed allocations in reset

* Make max ASAN allocation configurable
2021-06-13 12:27:27 +02:00
Dominik Maier
c123872b11 more informative error message for forkserver 2021-06-10 22:19:44 +02:00
Dominik Maier
022dc33251 clippy 2021-06-10 22:07:18 +02:00
Dominik Maier
c4dd0b25b8 fmt, clippy fixes 2021-06-10 13:39:44 +02:00
Dominik Maier
0c353daee6
Single-threaded Restartable Mgr (#129) (#159)
* initial single-threaded restartable mgr

* starting rework

* created SimpleRestartingManager

* fixed win build

* moved cpu to boplts

* bringing back cpu

* no_std fixes

* no_std fixes

* removed unused variable
2021-06-10 12:43:00 +02:00
s1341
bea557a48a Switch frida_libpng to ShadowExecutor when using cmplog 2021-06-10 12:30:57 +03:00
s1341
3d84a8d081
Merge pull request #164 from AFLplusplus/cmplog_instrumentation
frida: add `cmplog-cores` option
2021-06-09 17:56:55 +03:00
Omree
48af1661b4 change error message 2021-06-09 17:20:26 +03:00
Omree
f1c646dd1c Merge branch 'main' into cmplog_instrumentation 2021-06-09 17:05:37 +03:00
Omree
1181728a4f changed command line parameter from cmplog_cores to cmplog-cores 2021-06-09 16:55:42 +03:00
Omree
ed26319a21 add cmplog_cores command line argument support 2021-06-09 16:27:22 +03:00
Dominik Maier
6b235472e0
Added load_initial_inputs_forced to add all inputs to a corpus (fixes #123) (#158)
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-06-09 14:51:48 +02:00
Andrea Fioraldi
308e9c7fe9 adapt fuzzers/libfuzzer_stb_image to use ShadowTracingStage for CmpLog 2021-06-09 14:38:45 +02:00
Andrea Fioraldi
8fa654dd61 fix generics for ShadowExecutor 2021-06-09 14:34:38 +02:00
Andrea Fioraldi
2328ac252b Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-06-09 14:17:54 +02:00
Andrea Fioraldi
2b16e92461 introduce ShadowTracingStage 2021-06-09 14:17:43 +02:00
OB
7abd7c8162
Cmplog instrumentation for Frida (#99)
* libafl_targets: refactor sancov trace-pc

* cmp observer

* libaf_targets: new structure to isolate sancov

* fix C warning

* combined executor

* cmp observer and feedback

* I2SRandReplace mutator

* impl CmpMap for CmpLogMap in libafl_targets

* cmplog observer

* clippy

* TracingStage

* working random cmplog mutations

* enable cmplog for libfuzzer_stb_image

* re-enable new testcase stats print

* fix update stats display

* bump 0.3.1

* clippy

* clippy

* no clippy for fuzzers/

* fix

* add cmplog runtime instrumentation

* test cmplog against value profile feature

* fix compile error

* add target arch aarch64 for is_interesting_cmplog_instruction

* add cfg target aarch64 on cmplog related code within stalker loop

* revert changes in cargo.toml

* align code with 'main' branch

* revert accidently changed Cargo.toml file

* update cmplog runtime code to work with the cmplog backend implementation

* change magic to 8 bytes

* cmplog runs with observer- no crashes

* clippy fixes

* add cmplog_runtime as feature

* set cmplog command-line argument to false by default

* setup cmplog observer and mutator correctly

* decrease emitted code opcode count

* add cmplog testing to the harness

* get rid of irrelevant changes and unused code, add comments, change
feature name to "cmplog"

* get rid of some unessecery whitespaces and new lines

* fix clippy errors

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Omree <you@example.com>
2021-06-09 14:11:43 +02:00
Omree
b8e4f4c6fa fix clippy errors 2021-06-09 13:16:05 +03:00
Andrea Fioraldi
9e9425c622 introduce ShadowExecutor 2021-06-09 12:15:08 +02:00
Omree
3651e6aedf get rid of some unessecery whitespaces and new lines 2021-06-09 13:08:50 +03:00
Omree
0e2a280eae get rid of irrelevant changes and unused code, add comments, change
feature name to "cmplog"
2021-06-09 13:01:22 +03:00
Omree
1fc9796bdb add cmplog testing to the harness 2021-06-09 12:06:31 +03:00
Omree
584b034a52 decrease emitted code opcode count 2021-06-09 12:05:35 +03:00
Omree
2451302575 setup cmplog observer and mutator correctly 2021-06-09 12:03:57 +03:00
Omree
e8295988f2 set cmplog command-line argument to false by default 2021-06-09 12:01:55 +03:00
Omree
6f98bbe6cf add cmplog_runtime as feature 2021-06-09 12:01:39 +03:00
Omree
5de4c9305e Merge branch 'main' into cmplog_instrumentation 2021-06-09 10:37:43 +03:00
s1341
609939b5ec Use rlimit_cur as rlimit_max is set to MAX_LONG 2021-06-09 10:36:15 +03:00
s1341
cbf271d99f Remove stray print 2021-06-09 07:35:44 +03:00
Dominik Maier
6d2074bd7e storing sender id to env 2021-06-08 16:24:19 +02:00
Andrea Fioraldi
5c8c3be9e5 print sender id 2021-06-08 15:45:35 +02:00
Dominik Maier
24beae99f7
launchers without brokers (fixes #128) (#157) 2021-06-08 15:40:32 +02:00
s1341
4271790cb5
Add unique_name() to Input. Use it to generate filename in OnDiskCorpus (#152)
* Add unique_name() to Input. Use unique_name to generate filename in OnDiskCorpus

* updated duplicate ahash

* nostd fixes

* fmt

* rename unique_name to generate_name

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-06-08 09:54:38 +02:00
Andrea Fioraldi
cd9be5b33b Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-06-08 09:54:08 +02:00
Andrea Fioraldi
397a43c5d3 update build.rs for libafl_targets 2021-06-08 09:53:58 +02:00
Dominik Maier
36b823548a
nightly clippy fixes (#155)
* nightly clippy fixes

* more niglty clippy fixes

* added Safety section

* no_std fixes

* final fixes
2021-06-07 12:30:56 +02:00
Dominik Maier
35e655ca04
LLMP Changes (#130)
* llmp_changes

* fixed send

* no_std fixes
2021-06-07 02:15:31 +02:00
Dominik Maier
392ffd33f7
Fix client_id for outgoing messages (#154)
* attaching client_id to outgoing messages

* fixed forwarding, example
2021-06-07 01:48:52 +02:00
Dominik Maier
0d0bcc1796 clippy fixes 2021-06-07 01:44:07 +02:00
Dominik Maier
f858206ab1 macos fixes 2021-06-07 01:28:17 +02:00
Dominik Maier
3b2ee4bb70
Added MacOS CI (#131)
* added macos ci

* running tests on macos

* some macos fixes

* fmt

* some must_use infos

* trying' to fix MacOs testcases

* no main in test

* fixed MacOS testcases

* tried to fix build errors

* unified shmem_limits

* Revert "unified shmem_limits"

This reverts commit 8c6bb8d6a2cec71d72bb181b5b491737a771298e.

* hopefully fixed macos testcase

* removed unneeded values
2021-06-07 01:24:41 +02:00
Dominik Maier
370c652838 Merge branch 'main' into cmplog_instrumentation 2021-06-07 00:52:24 +02:00
Douman
11771c3323
Bump xxhash-rust minimal version to fixed one (#153)
* Bump minimal xxhash_rust version to 0.8.2

Note that 0.8.1 bug doesn't affect current usage, but still do it just in case

* Do not use const xxh3 not in cosnt context
2021-06-06 23:54:16 +02:00
Omree
0a5aa77cd6 cmplog runs with observer- no crashes 2021-06-06 13:03:11 +03:00
Omree
ea5aba220c change magic to 8 bytes 2021-06-06 12:53:24 +03:00
s1341
636194de0e
Frida switch from walk-proc-maps to frida-gum based extraction of ranges (#149)
* Bump frida-gum version

* Move from walk of /proc/pid/maps to frida based range/module locatoin
2021-06-06 10:40:07 +02:00
Gal Tashma
156ed08905
Eager and Fast FeedbackTuple Implementations (#144)
* Introduce eager and fast feedback_or! implementations (issue #135)

* rename FeedbackTuple to CombinedFeedback (as it is a struct not tuple) and add fast/eager AND
2021-06-04 14:07:02 +02:00
Andrea Fioraldi
42997dbde9 Fix #147 2021-06-04 14:03:31 +02:00
Omree
ac27efb954 update cmplog runtime code to work with the cmplog backend implementation 2021-06-02 10:04:03 +03:00
Omree
2a325beeff revert accidently changed Cargo.toml file 2021-06-02 10:04:03 +03:00
Omree
5bd08a6eee align code with 'main' branch 2021-06-02 10:04:03 +03:00
Omree
b59752eba5 revert changes in cargo.toml 2021-06-02 10:04:03 +03:00
Omree
23b2b4a06e add cfg target aarch64 on cmplog related code within stalker loop 2021-06-02 10:04:03 +03:00
Omree
2c0548a757 add target arch aarch64 for is_interesting_cmplog_instruction 2021-06-02 10:04:03 +03:00
Omree
8b2e86e7e6 fix compile error 2021-06-02 10:04:03 +03:00
Omree
85a90c7d21 test cmplog against value profile feature 2021-06-02 10:04:03 +03:00
Omree
2bbff1b7ab add cmplog runtime instrumentation 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
e6b95c1a4c fix 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
b999f45caa no clippy for fuzzers/ 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
e719e85aba clippy 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
9ae13eb5da clippy 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
69d87b3763 bump 0.3.1 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
aa14c903db fix update stats display 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
c4f13df9c7 re-enable new testcase stats print 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
aa6df29a9c enable cmplog for libfuzzer_stb_image 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
16d4c36f12 working random cmplog mutations 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
f61140bdcf TracingStage 2021-06-02 10:04:03 +03:00
Dominik Maier
b28306519f clippy 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
933b65dd86 cmplog observer 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
ccfc95aa3a impl CmpMap for CmpLogMap in libafl_targets 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
ae5b4f88cc I2SRandReplace mutator 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
8437c4adb7 cmp observer and feedback 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
f81a52e14d combined executor 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
a3a2b47b2a fix C warning 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
f25554805d libaf_targets: new structure to isolate sancov 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
a976c3b6f5 cmp observer 2021-06-02 10:04:03 +03:00
Andrea Fioraldi
eba6646f90 libafl_targets: refactor sancov trace-pc 2021-06-02 10:04:03 +03:00
Mrmaxmeier
de933fee63
check each feature in CI and fix introspection on no_std (#143)
* ci: check every feature with cargo-hack

* fix introspection on no_std

* ci: the dev branch is not a thing anymore

* ci: run tests with --all-features
2021-06-01 18:03:26 +02:00
Gal Tashma
ad9a2faaea
don't panick on time subtraction failure (#141)
On some machines, the system clock can be faulty and start_time maybe
actually be after the end time. This causes a panic, instead gracefully
just put a None time in `self.last_runtime`
2021-06-01 18:02:27 +02:00
Mrmaxmeier
1b755036ad
remove unnecessary generics on RandGenerators (#142) 2021-06-01 17:26:36 +02:00
Toka
c90604f123
TimeoutForkserverExecutor fix (#140)
* fix the call to kill

* fix
2021-05-31 19:31:32 +02:00
Toka
e4b3cc542a
Forkserver_simple uses TimeoutForkserverExecutor (#139)
* forkserver_simple uses TimeoutforkserverExecutor

* fmt

* from_millis
2021-05-31 15:44:56 +02:00
Toka
e68eaf8244
Timeout forkserver (#136)
* barebones for TimeoutForkserverExecutor

* TimeoutForkserverExecutor

* update pid in forkserverexecutor

* clppy and other small fixes

* doc

* fix

* no unwrap

* read_exact and error handling

* fix

* semicolon
2021-05-30 23:11:10 +02:00
David CARLIER
3e51981cf6
Fix tests on FreeBSD increasing couple of shared memory values (#138)
like macOs.
2021-05-30 23:09:54 +02:00
David CARLIER
e61f80584e
FreeBSD build fix proposal. (#137)
rlim_t is signed in this platform.
2021-05-29 00:31:04 +02:00
s1341
83bef6e85a
Fix frida bugs (#132)
* Get rid of extra deactivate

* Fix realloc, posix_memalign/memalign bugs

* Fix cfg attributes; Add instrumented ranges and translated PC to func errors

* Formatting

* Make hook_functionss aarch64 only for now.
2021-05-27 11:17:42 +02:00
Dominik Maier
945693f6ed fixed example testcase 2021-05-26 16:50:10 +02:00
Dominik Maier
ca869cd70a macos frida fixes 2021-05-26 14:01:33 +02:00
Dominik Maier
81ccf7f7d8 some macos fixes 2021-05-26 13:58:12 +02:00
Toka
5d44846c27
Improve TimeoutExecutor (#126)
* improve TimeoutExecutor

* fix for windows build
2021-05-25 22:20:52 +02:00
Andrea Fioraldi
a0804fd24d
Decouple llmp broker from manager (#125)
* decouple broker from manager

* fix no_std

* fix win build
2021-05-25 18:00:27 +02:00
Andrea Fioraldi
46716e8090
Remove executor hooks (#124)
* remove HasExecHooks from Executor

* adapt the frida executor

* adapt frida and avoid recursive type infearence

* fix win build
2021-05-25 15:19:10 +02:00
Dominik Maier
7493b59ba8 bringing back light clippy for fuzzers :) 2021-05-25 14:53:57 +02:00
s1341
3a21ad59a4
Hook using frida gum interceptor instead of gothook (#112)
* Move from gothook to frida-based hooks

* Force link against libc++

* Clippy + cleanup prints

* exclude ranges

* Add back guard pages; Implement libc hooks

* Bump frida-rust version

* Add hooks for mmap/munmap, as per issue #105

* Refactor to get rid of global allocator singleton

* Cleanup imports; Fix free out-of-range; Move to fixed addresses for asan allocatoins

* use frida-rust from crates.io now that it has caught up

* cargo fmt

* Clippy fixes

* Better clippy fix

* More clippy fix

* Formatting

* Review changes
2021-05-25 13:45:06 +02:00
Toka
d4410c072a
ForkserverExecutor (#111)
* add Forkserver, Pipe Outfile struct

* add forkserver executor struct, and shmem init

* close pipes in the destructor of Forkserver

* fill pre_exec to write out the inputs

* fix

* read_st, write_ctl

* more handshakes

* wrap Pipe in Arc, fill post_exec

* add Forkserver, Pipe Outfile struct

* add forkserver executor struct, and shmem init

* close pipes in the destructor of Forkserver

* fill pre_exec to write out the inputs

* fix

* read_st, write_ctl

* more handshakes

* wrap Pipe in Arc, fill post_exec

* fix for the lastest HasExecHooks trait

* use Dominik's pipe, remove Arc and temporarily pass RawFd to setstdin but trying to figure out other solutions

* add libafl_tests, put a very simple vulnerable program

* fix

* added forkserver_simple (mostly copy-pasted from babyfuzzer)

* fix test

* handle crash in post_exec

* add README.md

* check exec time to see why it's so slow

* remove double invokation of is_interesting for the obejctive

* make forkserver_simple AFL-like and improve speed

* some debugging help

* do not evaluate feedback if solution

* speedup the things

* working input placement via stdin in Forkserver

* don't call panic! but return errors, rewrite some comments

* use AFLplusplus/afl-cc instead of AFL

* use .cur_input like AFL

* bring the test for forkserver back

* add better README.md message

* failing the initial handshake should return an error

* delete some commented-out code

* format

* format

* ForkserverExecutor needs std and is unix-only for now

* clippy

* OutFile error handling

* fmt

* clippy

* don't build libafl_tests on windows

* fix

* keep test in forkserver.rs simple

* add forkserver_test feature for libafl_tests

* format

* some doc

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-05-25 13:40:00 +02:00
Max Ammann
1089c93577
Make load_initial_inputs work for arbitrary inputs (#121) 2021-05-24 14:03:32 +02:00
Andrea Fioraldi
c94cb53236 Merge branch 'main' of github.com:AFLplusplus/LibAFL into main 2021-05-24 14:02:32 +02:00
Andrea Fioraldi
aa4ed8d572 frida: update frida-rust to frida/frida-rust@69f5b8236a 2021-05-24 14:02:21 +02:00
Max Ammann
9569e24a06
Remove unused HasRand to avoid confusion with libafl::state::HasRand (#120) 2021-05-24 13:54:51 +02:00
Evan Richter
e65a2f9550
new Rand method: choose. fixes #117 (#118)
The choose method takes an ExactSizeIterator and returns a randomly
chosen item from it. Using this method prevents chosing items with an
incorrect upper_bound on the index.

Various macros help with defining and implementing repetitive mutation
strategies.
2021-05-22 11:51:24 +02:00
Andrea Fioraldi
cbec59bea8 fuzzers: re-enable LTO on release build for missing fuzzers 2021-05-21 17:52:23 +02:00
Andrea Fioraldi
3809a85df3 libafl: MultiStats UI padding 2021-05-21 17:47:48 +02:00
Andrea Fioraldi
349cc7b886 libafl: make clippy happy 2021-05-21 16:22:38 +02:00
Andrea Fioraldi
35181ec95b format 2021-05-21 16:00:06 +02:00
Andrea Fioraldi
c83210ad46 libfuzzer_libpng: re-enable LTO in release 2021-05-21 15:47:23 +02:00
Andrea Fioraldi
dd6f6fa03a libafl: asserts in MapFeedback::is_interesting to hint the compiler 2021-05-21 15:42:28 +02:00
Andrea Fioraldi
f506b3722e libafl: Introduce ConstMapObserver using const generics 2021-05-21 15:39:32 +02:00
s1341
533a93ddd6
Various frida/ashmem fixes (#116)
* Fix incorrect encoding of and imm: use a register for now

* Fix assumption regarding length of ashmem clients list

* Make harness less chatty

* Fix refcounting in the ashmem server

* Always work around the frida allocate-near bug, not just when doing asan.

* Add support for ashmem on devices which have a boot secret, but don't use it

* Formatting
2021-05-21 13:34:35 +02:00
Max Ammann
bfbaa7ae83
Make InProcessExecutor use a plain Input instead of bytes (#115)
* Make InProcessExecutor use a plain Input instead of bytes

* Use HasTargetBytes and fix CI
2021-05-20 17:57:31 +02:00
Andrea Fioraldi
2f54e9dc01
UserStats (#114)
* MultiStats

* custom event in MapFeedback

* fix introspection

* fix windows

* clippy

* fix nostd

* bump to 0.3.2
2021-05-20 16:49:12 +02:00
Andrea Fioraldi
921baf74b5 Update publish.sh with sleeps 2021-05-20 14:20:51 +02:00
Andrea Fioraldi
f0b5ab5ef0 Create a scripts folder 2021-05-20 14:17:14 +02:00
Andrea Fioraldi
acc5ed42a2
Basic CmpLog (#113)
* libafl_targets: refactor sancov trace-pc

* cmp observer

* libaf_targets: new structure to isolate sancov

* fix C warning

* combined executor

* cmp observer and feedback

* I2SRandReplace mutator

* impl CmpMap for CmpLogMap in libafl_targets

* cmplog observer

* clippy

* TracingStage

* working random cmplog mutations

* enable cmplog for libfuzzer_stb_image

* re-enable new testcase stats print

* fix update stats display

* bump 0.3.1

* clippy

* clippy

* no clippy for fuzzers/

* fix

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2021-05-20 14:05:20 +02:00
706 changed files with 143649 additions and 19443 deletions

148
.clang-format Normal file
View File

@ -0,0 +1,148 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: BeforeHash
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...

View File

@ -0,0 +1,29 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.191.0/containers/docker-existing-dockerfile
{
"name": "LibAFL Dockerfile",
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerFile": "../Dockerfile",
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"matklad.rust-analyzer"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line to run commands after the container is created - for example installing curl.
// "postCreateCommand": "apt-get update && apt-get install -y curl",
// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
// "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ],
// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}

35
.dockerignore Normal file
View File

@ -0,0 +1,35 @@
target
Cargo.lock
*.o
*.a
*.so
*.out
*.elf
*.bin
*.dll
*.exe
*.dSYM
.cur_input
crashes
callgrind.out.*
perf.data
perf.data.old
.vscode
test.dict
# Ignore all built fuzzers
fuzzer_*
AFLplusplus
# Ignore common dummy and logfiles
*.log
a
# ignore files from concolic tests
symcc_build
symcc

3
.github/FUNDING.yml vendored
View File

@ -1,6 +1,7 @@
# These are supported funding model platforms # These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: AFLplusplus
patreon: # Replace with a single Patreon username patreon: # Replace with a single Patreon username
open_collective: AFLplusplusEU open_collective: AFLplusplusEU
ko_fi: # Replace with a single Ko-fi username ko_fi: # Replace with a single Ko-fi username

29
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,29 @@
---
name: Bug Report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
**IMPORTANT**
1. You have verified that the issue to be present in the current `main` branch
Thank you for making LibAFL better!
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. ...
2. ...
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screen output/Screenshots**
If applicable, add copy-paste of the screen output or screenshot that shows the issue. Please ensure the output is in **English** and not in Chinese, Russian, German, etc.
**Additional context**
Add any other context about the problem here.

8
.github/ISSUE_TEMPLATE/empty.md vendored Normal file
View File

@ -0,0 +1,8 @@
---
name: Empty
about: A question or issue that doesn't fit the templates
title: ''
labels: ''
assignees: ''
---

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,77 +1,293 @@
name: Build and Test name: build and test
on: on:
push: push:
branches: [ main, dev ] branches: [ main ]
pull_request: pull_request:
branches: [ main, dev ] branches: [ main ]
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
jobs: jobs:
lint: common:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1
- name: Cache cargo registry
uses: actions/cache@v2
with: with:
path: | profile: minimal
~/.cargo/registry toolchain: nightly
~/.cargo/git override: true
key: clippy-cargo-${{ hashFiles('**/Cargo.toml') }} - name: install mdbook
- name: Add clippy uses: baptiste0928/cargo-install@v1.3.0
run: rustup component add clippy with:
#- name: Run clippy crate: mdbook
# uses: actions-rs/cargo@v1 - name: install linkcheck
# with: uses: baptiste0928/cargo-install@v1.3.0
# command: clippy with:
# args: --all crate: mdbook-linkcheck
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Install mimetype
if: runner.os == 'Linux'
run: sudo apt-get install libfile-mimeinfo-perl
- name: Check for binary blobs
if: runner.os == 'Linux'
run: ./scripts/check_for_blobs.sh
- name: Build libafl debug
run: cargo build -p libafl
- name: Build the book
run: cd docs && mdbook build
- name: Test the book
# TODO: fix books test fail with updated windows-rs
if: runner.os != 'Windows'
run: cd docs && mdbook test -L ../target/debug/deps
- name: Run tests
run: cargo test
- name: Test libafl no_std
run: cd libafl && cargo test --no-default-features
- name: Test libafl_targets no_std
run: cd libafl_targets && cargo test --no-default-features
ubuntu: ubuntu:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - name: Remove Dotnet & Haskell
- name: Default Build run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
run: cargo build --verbose - uses: actions-rs/toolchain@v1
- name: Default Test with:
run: cargo test --verbose profile: minimal
- name: Build all features toolchain: stable
run: cd libafl && cargo build --all-features --verbose - name: set mold linker as default linker
- name: Test all features uses: rui314/setup-mold@v1
run: cd libafl && cargo test --all-features --verbose - name: Install and cache deps
- name: Build no_std uses: awalsh128/cache-apt-pkgs-action@v1.1.0
run: cd libafl && cargo build --no-default-features --verbose with:
- name: Test no_std packages: llvm llvm-dev clang ninja-build clang-format-13 shellcheck libgtk-3-dev gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libslirp-dev
run: cd libafl && cargo test --no-default-features --verbose - name: get clang version
- name: Build examples run: command -v llvm-config && clang -v
run: cargo build --examples --verbose - name: Install cargo-hack
- uses: actions/checkout@v2 run: curl -LsSf https://github.com/taiki-e/cargo-hack/releases/latest/download/cargo-hack-x86_64-unknown-linux-gnu.tar.gz | tar xzf - -C ~/.cargo/bin
- name: Add nightly rustfmt and clippy
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@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 - name: Format
run: cargo fmt -- --check run: cargo fmt -- --check
- uses: actions/checkout@v2 - 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 - name: Build Docs
run: cargo doc run: cargo doc
- name: Test Docs - name: Test Docs
run: cargo test --all-features --doc run: cargo +nightly test --doc --all-features
- name: Run clippy
run: ./clippy.sh # ---- build and feature check ----
- name: Build fuzzers - name: Run a normal build
run: ./build_all_fuzzers.sh run: cargo build --verbose
# cargo-hack's --feature-powerset would be nice here but libafl has a too many knobs
- name: Check each feature
# Skipping `python` as it has to be built with the `maturin` tool
# `agpl`, `nautilus` require nightly
# `sancov_pcguard_edges` is tested seperately
run: cargo hack check --each-feature --clean-per-run --exclude-features=prelude,agpl,nautilus,python,sancov_pcguard_edges,arm,aarch64,i386,be,systemmode --no-dev-deps
- name: Check nightly features
run: cargo +nightly check --features=agpl && cargo +nightly check --features=nautilus
- name: Build examples
run: cargo build --examples --verbose
ubuntu-concolic:
runs-on: ubuntu-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Install smoke test deps
run: sudo ./libafl_concolic/test/smoke_test_ubuntu_deps.sh
- name: Run smoke test
run: ./libafl_concolic/test/smoke_test.sh
bindings:
runs-on: ubuntu-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: set mold linker as default linker
uses: rui314/setup-mold@v1
- name: Install deps
run: sudo apt-get install -y llvm llvm-dev clang ninja-build python3-dev python3-pip python3-venv
- name: Install maturin
run: python3 -m pip install maturin
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Run a maturin build
run: cd ./bindings/pylibafl && maturin build
fuzzers:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: set mold linker as default linker
if: runner.os == 'Linux' # mold only support linux until now
uses: rui314/setup-mold@v1
- name: Add nightly rustfmt and clippy
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
- name: Add no_std toolchain
run: rustup toolchain install nightly-x86_64-unknown-linux-gnu ; rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
- name: Install python
if: runner.os == 'macOS'
run: brew install --force-bottle --overwrite python@3.11
- uses: lyricwulf/abc@v1
with:
# 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`
macos: llvm libpng nasm coreutils z3 bash
- name: pip install
run: python3 -m pip install msgpack jinja2
# Note that nproc needs to have coreutils installed on macOS, so the order of CI commands matters.
- name: enable mult-thread for `make`
run: export MAKEFLAGS="-j$(expr $(nproc) \+ 1)"
- name: install cargo-make
uses: baptiste0928/cargo-install@v1.3.0
with:
crate: cargo-make
- uses: actions/checkout@v3
with:
submodules: true # recursively checkout submodules
- uses: Swatinem/rust-cache@v2
- name: Build and run example fuzzers (Linux)
if: runner.os == 'Linux'
run: ./scripts/test_all_fuzzers.sh
- name: Build and run example fuzzers (macOS)
if: runner.os == 'macOS' # use bash v4
run: /usr/local/bin/bash ./scripts/test_all_fuzzers.sh
nostd-build:
runs-on: ubuntu-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt, clippy, rust-src
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Add targets
run: rustup target add arm-linux-androideabi && rustup target add thumbv6m-none-eabi
- name: Build aarch64-unknown-none
run: cd ./fuzzers/baby_no_std && cargo +nightly build -Zbuild-std=core,alloc --target aarch64-unknown-none -v --release && cd ../..
- name: run x86_64 until panic!
run: cd ./fuzzers/baby_no_std && cargo +nightly run || test $? -ne 0 || exit 1
- name: no_std tests
run: cd ./libafl && cargo test --no-default-features
- name: libafl armv6m-none-eabi (32 bit no_std) clippy
run: cd ./libafl && cargo clippy --target thumbv6m-none-eabi --no-default-features
build-docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build docker
run: docker build -t libafl .
windows: windows:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Windows Build - name: Windows Build
run: cargo build --verbose run: cargo build --verbose
- name: Run clippy - name: Run clippy
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: clippy command: clippy
- name: Build docs
run: cargo doc
- name: Set LIBCLANG_PATH
run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV
- name: install cargo-make
run: cargo install --force cargo-make
- uses: ilammy/msvc-dev-cmd@v1
- name: Build fuzzers/frida_libpng
run: cd fuzzers/frida_libpng/ && cargo make test
- name: Build fuzzers/frida_gdiplus
run: cd fuzzers/frida_gdiplus/ && cargo make test
macos:
runs-on: macOS-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Add nightly rustfmt and clippy
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
- name: Install deps
run: brew install z3 gtk+3
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: MacOS Build
run: cargo build --verbose
- name: Run clippy
run: ./scripts/clippy.sh
- name: Increase map sizes
run: ./scripts/shmem_limits_macos.sh
- name: Run Tests
run: cargo test
other_targets:
runs-on: macOS-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: nttld/setup-ndk@v1
with:
ndk-version: r21e
- name: install ios
run: rustup target add aarch64-apple-ios
- name: install android
run: rustup target add aarch64-linux-android
- name: install cargo ndk
run: cargo install cargo-ndk
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Build iOS
run: cargo build --target aarch64-apple-ios
- name: Build Android
run: cargo ndk -t arm64-v8a build --release
#run: cargo build --target aarch64-linux-android
# TODO: Figure out how to properly build stuff with clang # TODO: Figure out how to properly build stuff with clang
#- name: Add clang path to $PATH env #- name: Add clang path to $PATH env
# if: runner.os == 'Windows' # if: runner.os == 'Windows'
@ -80,3 +296,36 @@ jobs:
# run: clang -v # run: clang -v
#- name: Windows Test #- name: Windows Test
# run: C:\Rust\.cargo\bin\cargo.exe test --verbose # run: C:\Rust\.cargo\bin\cargo.exe test --verbose
freebsd:
runs-on: macos-12
name: Simple build in FreeBSD
steps:
- uses: actions/checkout@v3
- name: Test in FreeBSD
id: test
uses: vmactions/freebsd-vm@v0
with:
usesh: true
sync: rsync
copyback: false
mem: 2048
release: 13.1
prepare: |
pkg install -y curl bash sudo llvm14
curl https://sh.rustup.rs -sSf | sh -s -- -y
run: |
freebsd-version
. "$HOME/.cargo/env"
rustup toolchain install nightly
export LLVM_CONFIG=/usr/local/bin/llvm-config14
pwd
ls -lah
echo "local/bin"
ls -lah /usr/local/bin/
which llvm-config
chmod +x ./scripts/clippy.sh
bash ./scripts/shmem_limits_fbsd.sh
bash ./scripts/clippy.sh
cargo test

35
.gitignore vendored
View File

@ -1,6 +1,14 @@
target target
target-bin
out
Cargo.lock Cargo.lock
vendor
.DS_Store
.env
*.tmp
*.swp
*.o *.o
*.a *.a
*.so *.so
@ -9,6 +17,11 @@ Cargo.lock
*.bin *.bin
*.dll *.dll
*.exe *.exe
*.dSYM
*.obj
.cur_input
.venv
crashes crashes
@ -20,4 +33,24 @@ perf.data.old
test.dict test.dict
# Ignore all built fuzzers # Ignore all built fuzzers
fuzzer_* fuzzer_*
AFLplusplus
test_*
*_fuzzer
*_harness
# Ignore common dummy and logfiles
*.log
a
forkserver_test
__pycache__
*.lafl_lock
*atomic_file_testfile*
**/libxml2
**/corpus_discovered
**/libxml2-*.tar.gz
libafl_nyx/QEMU-Nyx
libafl_nyx/packer

3
.gitmodules vendored
View File

@ -0,0 +1,3 @@
[submodule "libafl_concolic/symcc_runtime/symcc"]
path = libafl_concolic/symcc_runtime/symcc
url = https://github.com/AFLplusplus/symcc.git

View File

@ -1,9 +1,3 @@
[profile.release]
lto = true
codegen-units = 1
opt-level = 3
debug = true
[workspace] [workspace]
members = [ members = [
"libafl", "libafl",
@ -11,6 +5,17 @@ members = [
"libafl_cc", "libafl_cc",
"libafl_targets", "libafl_targets",
"libafl_frida", "libafl_frida",
"libafl_qemu",
"libafl_tinyinst",
"libafl_sugar",
"libafl_nyx",
"libafl_concolic/symcc_runtime",
"libafl_concolic/symcc_libafl",
"libafl_concolic/test/dump_constraints",
"libafl_concolic/test/runtime_test",
"utils/deexit",
"utils/gramatron/construct_automata",
"utils/libafl_benches",
] ]
default-members = [ default-members = [
"libafl", "libafl",
@ -20,4 +25,18 @@ default-members = [
] ]
exclude = [ exclude = [
"fuzzers", "fuzzers",
"bindings",
"scripts",
"libafl_qemu/libafl_qemu_build",
"libafl_qemu/libafl_qemu_sys"
] ]
[workspace.package]
version = "0.8.2"
[profile.release]
lto = true
codegen-units = 1
opt-level = 3
debug = true

122
Dockerfile Normal file
View File

@ -0,0 +1,122 @@
# syntax=docker/dockerfile:1.2
FROM rust:bullseye AS libafl
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
LABEL "about"="LibAFL Docker image"
# install sccache to cache subsequent builds of dependencies
RUN cargo install sccache
ENV HOME=/root
ENV SCCACHE_CACHE_SIZE="1G"
ENV SCCACHE_DIR=$HOME/.cache/sccache
ENV RUSTC_WRAPPER="/usr/local/cargo/bin/sccache"
ENV IS_DOCKER="1"
RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' \
echo "export PS1='"'[LibAFL \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc && \
mkdir ~/.cargo && \
echo "[build]\nrustc-wrapper = \"${RUSTC_WRAPPER}\"" >> ~/.cargo/config
RUN rustup component add rustfmt clippy
# Install clang 11, common build tools
RUN apt update && apt install -y build-essential gdb git wget clang clang-tools libc++-11-dev libc++abi-11-dev llvm
# Copy a dummy.rs and Cargo.toml first, so that dependencies are cached
WORKDIR /libafl
COPY Cargo.toml README.md ./
COPY libafl_derive/Cargo.toml libafl_derive/Cargo.toml
COPY scripts/dummy.rs libafl_derive/src/lib.rs
COPY libafl/Cargo.toml libafl/build.rs libafl/
COPY libafl/examples libafl/examples
COPY scripts/dummy.rs libafl/src/lib.rs
COPY libafl_frida/Cargo.toml libafl_frida/build.rs libafl_frida/
COPY scripts/dummy.rs libafl_frida/src/lib.rs
COPY libafl_frida/src/gettls.c libafl_frida/src/gettls.c
COPY libafl_qemu/Cargo.toml libafl_qemu/build.rs libafl_qemu/
COPY scripts/dummy.rs libafl_qemu/src/lib.rs
COPY libafl_qemu/libafl_qemu_build/Cargo.toml libafl_qemu/libafl_qemu_build/
COPY scripts/dummy.rs libafl_qemu/libafl_qemu_build/src/lib.rs
COPY libafl_qemu/libafl_qemu_sys/Cargo.toml libafl_qemu/libafl_qemu_sys/build.rs libafl_qemu/libafl_qemu_sys/
COPY scripts/dummy.rs libafl_qemu/libafl_qemu_sys/src/lib.rs
COPY libafl_sugar/Cargo.toml libafl_sugar/
COPY scripts/dummy.rs libafl_sugar/src/lib.rs
COPY libafl_cc/Cargo.toml libafl_cc/Cargo.toml
COPY libafl_cc/build.rs libafl_cc/build.rs
COPY libafl_cc/src libafl_cc/src
COPY scripts/dummy.rs libafl_cc/src/lib.rs
COPY libafl_targets/Cargo.toml libafl_targets/build.rs libafl_targets/
COPY libafl_targets/src libafl_targets/src
COPY scripts/dummy.rs libafl_targets/src/lib.rs
COPY libafl_concolic/test/dump_constraints/Cargo.toml libafl_concolic/test/dump_constraints/
COPY scripts/dummy.rs libafl_concolic/test/dump_constraints/src/lib.rs
COPY libafl_concolic/test/runtime_test/Cargo.toml libafl_concolic/test/runtime_test/
COPY scripts/dummy.rs libafl_concolic/test/runtime_test/src/lib.rs
COPY libafl_concolic/symcc_runtime/Cargo.toml libafl_concolic/symcc_runtime/build.rs libafl_concolic/symcc_runtime/
COPY scripts/dummy.rs libafl_concolic/symcc_runtime/src/lib.rs
COPY libafl_concolic/symcc_libafl/Cargo.toml libafl_concolic/symcc_libafl/
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 libafl_tinyinst/Cargo.toml libafl_tinyinst/
COPY scripts/dummy.rs libafl_tinyinst/src/lib.rs
COPY utils utils
RUN cargo build && cargo build --release
COPY scripts scripts
COPY docs docs
# Pre-build dependencies for a few common fuzzers
# Dep chain:
# libafl_cc (independent)
# libafl_derive -> libafl
# libafl -> libafl_targets
# libafl_targets -> libafl_frida
# Build once without source
COPY libafl_cc/src libafl_cc/src
RUN touch libafl_cc/src/lib.rs
COPY libafl_derive/src libafl_derive/src
RUN touch libafl_derive/src/lib.rs
COPY libafl/src libafl/src
RUN touch libafl/src/lib.rs
COPY libafl_targets/src libafl_targets/src
RUN touch libafl_targets/src/lib.rs
COPY libafl_frida/src libafl_frida/src
RUN touch libafl_qemu/libafl_qemu_build/src/lib.rs
COPY libafl_qemu/libafl_qemu_build/src libafl_qemu/libafl_qemu_build/src
RUN touch libafl_qemu/libafl_qemu_sys/src/lib.rs
COPY libafl_qemu/libafl_qemu_sys/src libafl_qemu/libafl_qemu_sys/src
RUN touch libafl_qemu/src/lib.rs
COPY libafl_qemu/src libafl_qemu/src
RUN touch libafl_frida/src/lib.rs
COPY libafl_concolic/symcc_libafl libafl_concolic/symcc_libafl
COPY libafl_concolic/symcc_runtime libafl_concolic/symcc_runtime
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
# Copy fuzzers over
COPY fuzzers fuzzers
# RUN ./scripts/test_all_fuzzers.sh --no-fmt
ENTRYPOINT [ "/bin/bash" ]

View File

@ -4,7 +4,12 @@
Advanced Fuzzing Library - Slot your own fuzzers together and extend their features using Rust. Advanced Fuzzing Library - Slot your own fuzzers together and extend their features using Rust.
LibAFL is written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>. LibAFL is written and maintained by
* [Andrea Fioraldi](https://twitter.com/andreafioraldi) <andrea@aflplus.plus>
* [Dominik Maier](https://twitter.com/domenuk) <dominik@aflplus.plus>
* [s1341](https://twitter.com/srubenst1341) <github@shmarya.net>
* [Dongjia Zhang](https://github.com/tokatoka) <toka@aflplus.plus>
## Why LibAFL? ## Why LibAFL?
@ -27,22 +32,34 @@ It offers a main crate that provide building blocks for custom fuzzers, [libafl]
LibAFL offers integrations with popular instrumentation frameworks. At the moment, the supported backends are: LibAFL offers integrations with popular instrumentation frameworks. At the moment, the supported backends are:
+ SanitizerCoverage, in [libafl_targets](./libafl_targets) + SanitizerCoverage, in [libafl_targets](./libafl_targets)
+ Frida, in [libafl_frida](./libafl_frida), by s1341 <github@shmarya.net> + Frida, in [libafl_frida](./libafl_frida)
+ More to come (QEMU-mode, ...) + QEMU user-mode, in [libafl_qemu](./libafl_qemu)
+ TinyInst, in [libafl_tinyinst](./libafl_tinyinst) by [elbiazo](https://github.com/elbiazo)
## Getting started ## Getting started
1. Install the Rust development language. We highly recommend *not* to use e.g. 1. Install the Dependecies
your Linux distribution package as this is likely outdated. So rather install - The Rust development language.
We highly recommend *not* to use e.g. your Linux distribition package as this is likely outdated. So rather install
Rust directly, instructions can be found [here](https://www.rust-lang.org/tools/install). Rust directly, instructions can be found [here](https://www.rust-lang.org/tools/install).
- LLVM tools
The LLVM tools are needed (newer than LLVM 11.0.0 but older than LLVM 15.0.0)
- Cargo-make
We use cargo-make to build the fuzzers in `fuzzers/` directory. You can install it with
```
cargo install cargo-make
```
2. Clone the LibAFL repository with 2. Clone the LibAFL repository with
``` ```
git clone https://github.com/AFLplusplus/LibAFL git clone https://github.com/AFLplusplus/LibAFL
``` ```
Build the library using 3. Build the library using
``` ```
cargo build --release cargo build --release
@ -63,32 +80,61 @@ cd docs && mdbook serve
We collect all example fuzzers in [`./fuzzers`](./fuzzers/). We collect all example fuzzers in [`./fuzzers`](./fuzzers/).
Be sure to read their documentation (and source), this is *the natural way to get started!* Be sure to read their documentation (and source), this is *the natural way to get started!*
You can run each example fuzzer with
```
cargo make run
```
as long as the fuzzer directory has `Makefile.toml` file.
The best-tested fuzzer is [`./fuzzers/libfuzzer_libpng`](./fuzzers/libfuzzer_libpng), a multicore libfuzzer-like fuzzer using LibAFL for a libpng harness. The best-tested fuzzer is [`./fuzzers/libfuzzer_libpng`](./fuzzers/libfuzzer_libpng), a multicore libfuzzer-like fuzzer using LibAFL for a libpng harness.
## Resources ## Resources
+ [Installation guide](./docs/src/getting_started/setup.md) + [Installation guide](./docs/src/getting_started/setup.md)
+ Our RC3 [talk](http://www.youtube.com/watch?v=3RWkT1Q5IV0 "Fuzzers Like LEGO") explaining the core concepts
+ [Online API documentation](https://docs.rs/libafl/) + [Online API documentation](https://docs.rs/libafl/)
+ The LibAFL book (very WIP) [online](https://aflplus.plus/libafl-book) or in the [repo](./docs/src/) + The LibAFL book (WIP) [online](https://aflplus.plus/libafl-book) or in the [repo](./docs/src/)
+ Our research [paper](https://www.s3.eurecom.fr/docs/ccs22_fioraldi.pdf)
+ Our RC3 [talk](http://www.youtube.com/watch?v=3RWkT1Q5IV0 "Fuzzers Like LEGO") explaining the core concepts
+ Our Fuzzcon Europe [talk](https://www.youtube.com/watch?v=PWB8GIhFAaI "LibAFL: The Advanced Fuzzing Library") with a (a bit but not so much outdated) step-by-step discussion on how to build some example fuzzers
+ The Fuzzing101 [solutions](https://github.com/epi052/fuzzing-101-solutions) & series of [blog posts](https://epi052.gitlab.io/notes-to-self/blog/2021-11-01-fuzzing-101-with-libafl/) by [epi](https://github.com/epi052)
+ Blogpost on binary-only fuzzing lib libaf_qemu, [Hacking TMNF - Fuzzing the game server](https://blog.bricked.tech/posts/tmnf/part1/), by [RickdeJager](https://github.com/RickdeJager).
## Contributing ## Contributing
Check the [TODO.md](./TODO.md) file for features that we plan to support.
For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 For bugs, feel free to open issues or contact us directly. Thank you for your support. <3
Even though we will gladly assist you in finishing up your PR, try to Even though we will gladly assist you in finishing up your PR, try to
- use *stable* rust - keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26))
- run `cargo fmt` on your code before pushing - run `cargo fmt` on your code before pushing
- check the output of `cargo clippy --all` or `./clippy.sh` - check the output of `cargo clippy --all` or `./clippy.sh`
- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. - run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code.
Some of the parts in this list may be hard, don't be afraid to open a PR if you cannot fix them by yourself, so we can help. Some of the parts in this list may be hard, don't be afraid to open a PR if you cannot fix them by yourself, so we can help.
## Cite
If you use LibAFL for your academic work, please cite the following paper:
```bibtex
@inproceedings{libafl,
author = {Andrea Fioraldi and Dominik Maier and Dongjia Zhang and Davide Balzarotti},
title = {{LibAFL: A Framework to Build Modular and Reusable Fuzzers}},
booktitle = {Proceedings of the 29th ACM conference on Computer and communications security (CCS)},
series = {CCS '22},
year = {2022},
month = {November},
location = {Los Angeles, U.S.A.},
publisher = {ACM},
}
```
#### License #### License
<sup> <sup>
@ -104,3 +150,10 @@ for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions. be dual licensed as above, without any additional terms or conditions.
</sub> </sub>
<br>
<sub>
Dependencies under more restrictive licenses, such as GPL or AGPL, can be enabled
using the respective feature in each crate when it is present, such as the
'agpl' feature of the libafl crate.
</sub>

26
TODO.md
View File

@ -1,26 +0,0 @@
# TODOs
- [ ] Objective-Specific Corpuses (named per objective)
- [ ] Good documentation
- [ ] LLMP compression
- [ ] AFL-Style Forkserver Executor
- [ ] LAIN / structured fuzzing example
- [ ] More informative outpus, deeper introspection (stats, what mutation did x, etc.)
- [ ] Timeout handling for llmp clients (no ping for n seconds -> treat as disconnected)
- [ ] "Launcher" example that spawns broker + n clients
- [ ] Heap for signal handling (bumpallo or llmp directly?)
- [ ] Frida support for Windows
- [ ] QEMU based instrumentation
- [ ] AFL++ LLVM passes in libafl_cc
- [x] LLMP Cross Machine Link (2 brokers connected via TCP)
- [x] Conditional composition of feedbacks (issue #24)
- [x] Other objectives examples (e.g. execution of a given program point)
- [x] Restart Count in Fuzzing Loop
- [x] Minset corpus scheduler
- [x] Win32 shared mem and crash handler to have Windows in-process executor
- [x] Other feedbacks examples (e.g. maximize allocations to spot OOMs)
- [x] A macro crate with derive directives (e.g. for SerdeAny impl).
- [x] Restarting EventMgr could use forks on Unix
- [x] Android Ashmem support
- [x] Errors in the Fuzzer should exit the fuzz run
- [x] Timeouts for executors (WIP on Windows)

View File

@ -0,0 +1,20 @@
[package]
name = "pylibafl"
version = "0.8.2"
edition = "2021"
[dependencies]
pyo3 = { version = "0.17", features = ["extension-module"] }
libafl_qemu = { path = "../../libafl_qemu", version = "0.8.2", features = ["python"] }
libafl_sugar = { path = "../../libafl_sugar", version = "0.8.2", features = ["python"] }
libafl = { path = "../../libafl", version = "0.8.2", features = ["python"] }
[build-dependencies]
pyo3-build-config = { version = "0.17" }
[lib]
name = "pylibafl"
crate-type = ["cdylib"]
[profile.dev]
panic = "abort"

View File

@ -0,0 +1,31 @@
# How to use python bindings
## First time setup
```bash
# Install maturin
pip install maturin
# Create virtual environment
python3 -m venv .env
```
## Build bindings
```
# Activate virtual environment
source .env/bin/activate
# Build python module
maturin develop
```
This is going to install `pylibafl` python module into this venv.
## Use bindings
### Example: Running baby_fuzzer in fuzzers/baby_fuzzer/baby_fuzzer.py
First, make sure the python virtual environment is activated. If not, run `source .env/bin/activate
`. Running `pip freeze` at this point should display the following (versions may differ):
```
maturin==0.12.6
pylibafl==0.7.0
toml==0.10.2
```
Then simply run
```
python PATH_TO_BABY_FUZZER/baby_fuzzer.py
```
The crashes directory will be created in the directory from which you ran the command.

View File

@ -0,0 +1 @@
nightly

View File

@ -0,0 +1,121 @@
use libafl;
#[cfg(target_os = "linux")]
use libafl_qemu;
use libafl_sugar;
use pyo3::{prelude::*, types::PyDict};
const LIBAFL_CODE: &str = r#"
class BaseObserver:
def flush(self):
pass
def pre_exec(self, state, input):
pass
def post_exec(self, state, input, exit_kind):
pass
def pre_exec_child(self, state, input):
pass
def post_exec_child(self, state, input, exit_kind):
pass
def name(self):
return type(self).__name__
def as_observer(self):
return Observer.new_py(self)
class BaseFeedback:
def init_state(self, state):
pass
def is_interesting(self, state, mgr, input, observers, exit_kind) -> bool:
return False
def append_metadata(self, state, testcase):
pass
def discard_metadata(self, state, input):
pass
def name(self):
return type(self).__name__
def as_feedback(self):
return Feedback.new_py(self)
class BaseExecutor:
def observers(self) -> ObserversTuple:
raise NotImplementedError('Implement this yourself')
def run_target(self, fuzzer, state, mgr, input) -> ExitKind:
raise NotImplementedError('Implement this yourself')
def as_executor(self):
return Executor.new_py(self)
class BaseStage:
def perform(self, fuzzer, executor, state, manager, corpus_idx):
pass
def as_stage(self):
return Stage.new_py(self)
class BaseMutator:
def mutate(self, state, input, stage_idx):
pass
def post_exec(self, state, stage_idx, corpus_idx):
pass
def as_mutator(self):
return Mutator.new_py(self)
class FnStage(BaseStage):
def __init__(self, fn):
self.fn = fn
def __call__(self, fuzzer, executor, state, manager, corpus_idx):
self.fn(fuzzer, executor, state, manager, corpus_idx)
def perform(self, fuzzer, executor, state, manager, corpus_idx):
self.fn(fuzzer, executor, state, manager, corpus_idx)
def feedback_not(a):
return NotFeedback(a).as_feedback()
def feedback_and(a, b):
return EagerAndFeedback(a, b).as_feedback()
def feedback_and_fast(a, b):
return FastAndFeedback(a, b).as_feedback()
def feedback_or(a, b):
return EagerOrFeedback(a, b).as_feedback()
def feedback_or_fast(a, b):
return FastOrFeedback(a, b).as_feedback()
"#;
#[pymodule]
#[pyo3(name = "pylibafl")]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
let modules = py.import("sys")?.getattr("modules")?;
let sugar_module = PyModule::new(py, "sugar")?;
libafl_sugar::python_module(py, sugar_module)?;
m.add_submodule(sugar_module)?;
modules.set_item("pylibafl.sugar", sugar_module)?;
#[cfg(target_os = "linux")]
let qemu_module = PyModule::new(py, "qemu")?;
#[cfg(target_os = "linux")]
libafl_qemu::python_module(py, qemu_module)?;
#[cfg(target_os = "linux")]
m.add_submodule(qemu_module)?;
#[cfg(target_os = "linux")]
modules.set_item("pylibafl.qemu", qemu_module)?;
let libafl_module = PyModule::new(py, "libafl")?;
libafl::pybind::python_module(py, libafl_module)?;
libafl_module.add("__builtins__", py.import("builtins")?)?;
let locals = PyDict::new(py);
py.run(LIBAFL_CODE, Some(libafl_module.dict()), Some(locals))?;
for (key, val) in locals.iter() {
libafl_module.add(key.extract::<&str>()?, val)?;
}
m.add_submodule(libafl_module)?;
modules.set_item("pylibafl.libafl", libafl_module)?;
Ok(())
}

94
bindings/pylibafl/test.py Normal file
View File

@ -0,0 +1,94 @@
from pylibafl.libafl import *
import ctypes
class FooObserver(BaseObserver):
def __init__(self):
self.n = 0
def name(self):
return "Foo"
def pre_exec(self, state, input):
if self.n % 10000 == 0:
print("FOO!", self.n, input)
self.n += 1
class FooFeedback(BaseFeedback):
def is_interesting(self, state, mgr, input, observers, exit_kind):
ob = observers.match_name("Foo").unwrap_py()
return ob.n % 10000 == 0
class FooExecutor(BaseExecutor):
def __init__(self, harness, observers: ObserversTuple):
self.h = harness
self.o = observers
def observers(self):
return self.o
def run_target(self, fuzzer, state, mgr, input) -> ExitKind:
return (self.h)(input)
libc = ctypes.cdll.LoadLibrary("libc.so.6")
area_ptr = libc.calloc(1, 4096)
observer = StdMapObserverI8("mymap", area_ptr, 4096)
m = observer.as_map_observer()
observers = ObserversTuple(
[observer.as_map_observer().as_observer(), FooObserver().as_observer()]
)
feedback = feedback_or(MaxMapFeedbackI8(m).as_feedback(), FooFeedback().as_feedback())
objective = feedback_and_fast(
CrashFeedback().as_feedback(), MaxMapFeedbackI8(m).as_feedback()
)
fuzzer = StdFuzzer(feedback, objective)
rand = StdRand.with_current_nanos()
state = StdState(
rand.as_rand(),
InMemoryCorpus().as_corpus(),
InMemoryCorpus().as_corpus(),
feedback,
objective,
)
monitor = SimpleMonitor(lambda s: print(s))
mgr = SimpleEventManager(monitor.as_monitor())
def harness(buf) -> ExitKind:
# print(buf)
m[0] = 1
if len(buf) > 0 and buf[0] == ord("a"):
m[1] = 1
if len(buf) > 1 and buf[1] == ord("b"):
m[2] = 1
if len(buf) > 2 and buf[2] == ord("c"):
m[3] = 1
return ExitKind.crash()
return ExitKind.ok()
# executor = InProcessExecutor(harness, observers, fuzzer, state, mgr.as_manager())
executor = FooExecutor(harness, observers)
stage = StdMutationalStage(StdHavocMutator().as_mutator())
stage_tuple_list = StagesTuple([stage.as_stage()])
fuzzer.add_input(state, executor.as_executor(), mgr.as_manager(), b"\0\0")
fuzzer.fuzz_loop(executor.as_executor(), state, mgr.as_manager(), stage_tuple_list)

View File

@ -1,16 +0,0 @@
#!/bin/sh
# TODO: This should be rewritten in rust, a Makefile, or some platform-independent language
cd fuzzers
for fuzzer in *;
do
echo "[+] Checking fmt, clippy, and building $fuzzer"
cd $fuzzer \
&& cargo fmt --all -- --check \
&& ../../clippy.sh --no-clean \
&& cargo build \
&& cd .. \
|| exit 1
done

View File

@ -1,25 +0,0 @@
#!/bin/sh
# Clippy checks
if [ "$1" != "--no-clean" ]; then
# Usually, we want to clean, since clippy won't work otherwise.
echo "[+] Cleaning up previous builds..."
cargo clean -p libafl
fi
RUST_BACKTRACE=full cargo clippy --all --all-features --tests -- \
-D clippy::pedantic \
-W clippy::unused_self \
-W clippy::too_many_lines \
-W clippy::option_if_let_else \
-W clippy::must-use-candidate \
-W clippy::if-not-else \
-W clippy::similar-names \
-A clippy::type_repetition_in_bounds \
-A clippy::missing-errors-doc \
-A clippy::cast-possible-truncation \
-A clippy::used-underscore-binding \
-A clippy::ptr-as-ptr \
-A clippy::missing-panics-doc \
-A clippy::missing-docs-in-private-items \
-A clippy::unseparated-literal-suffix \
-A clippy::module-name-repetitions \
-A clippy::unreadable-literal \

View File

@ -4,3 +4,8 @@ language = "en"
multilingual = false multilingual = false
src = "src" src = "src"
title = "The LibAFL Fuzzing Library" title = "The LibAFL Fuzzing Library"
[output.html]
[output.linkcheck]
optional = true

View File

@ -9,13 +9,32 @@
- [Build](./getting_started/build.md) - [Build](./getting_started/build.md)
- [Crates](./getting_started/crates.md) - [Crates](./getting_started/crates.md)
- [Baby Fuzzer](./baby_fuzzer.md) - [Baby Fuzzer](./baby_fuzzer/baby_fuzzer.md)
- [More Examples](./baby_fuzzer/more_examples.md)
- [Core Concepts](./core_concepts/core_concepts.md)
- [Observer](./core_concepts/observer.md)
- [Executor](./core_concepts/executor.md)
- [Feedback](./core_concepts/feedback.md)
- [Input](./core_concepts/input.md)
- [Corpus](./core_concepts/corpus.md)
- [Mutator](./core_concepts/mutator.md)
- [Generator](./core_concepts/generator.md)
- [Stage](./core_concepts/stage.md)
- [Design](./design/design.md) - [Design](./design/design.md)
- [Core Concepts](./design/core_concepts.md)
- [Architecture](./design/architecture.md) - [Architecture](./design/architecture.md)
- [Metadata](./design/metadata.md)
- [Migrating from LibAFL <0.9 to 0.9](./design/migration-0.9.md)
- [Understanding Metadata](./medatata/metadata.md) - [Message Passing](./message_passing/message_passing.md)
- [Definition](./medatata/definition.md) - [Spawning Instances](./message_passing/spawn_instances.md)
- [(De)Serialization](./medatata/de_serialization.md) - [Configurations](./message_passing/configurations.md)
- [Usage](./medatata/usage.md)
- [Tutorial](./tutorial/tutorial.md)
- [Introduction](./tutorial/intro.md)
- [Advanced Features](./advanced_features/advanced_features.md)
- [Binary-Only Fuzzing with `Frida`](./advanced_features/frida.md)
- [Concolic Tracing & Hybrid Fuzzing](./advanced_features/concolic.md)
- [LibAFL in `no_std` environments (Kernels, Hypervisors, ...)](./advanced_features/no_std.md)
- [Snapshot Fuzzing in Nyx](./advanced_features/nyx.md)

View File

@ -0,0 +1,4 @@
# Advanced Features
In addition to core building blocks for fuzzers, LibAFL also has features for more advanced/niche fuzzing techniques.
The following sections are dedicated to some of these features.

View File

@ -0,0 +1,184 @@
# Concolic Tracing and Hybrid Fuzzing
LibAFL has support for concolic tracing based on the [SymCC](https://github.com/eurecom-s3/symcc) instrumenting compiler.
For those uninitiated, the following attempts to describe concolic tracing from the ground up using an example.
Then, we'll go through the relationship of SymCC and LibAFL concolic tracing.
Finally, we'll walk through building a basic hybrid fuzzer using LibAFL.
## Concolic Tracing by Example
Suppose you want to fuzz the following program:
```rust
fn target(input: &[u8]) -> i32 {
match &input {
// fictitious crashing input
&[1, 3, 3, 7] => 1337,
// standard error handling code
&[] => -1,
// representative of normal execution
_ => 0
}
}
```
A simple coverage-maximizing fuzzer that generates new inputs somewhat randomly will have a hard time finding an input that triggers the fictitious crashing input.
Many techniques have been proposed to make fuzzing less random and more directly attempt to mutate the input to flip specific branches, such as the ones involved in crashing the above program.
Concolic tracing allows us to construct an input that exercises a new path in the program (such as the crashing one in the example) **analytically** instead of **stochastically** (ie. guessing).
In principle, concolic tracing works by observing all executed instructions in an execution of the program that depend on the input.
To understand what this entails, we'll run an example with the above program.
First, we'll simplify the program to simple if-then-else-statements:
```rust
fn target(input: &[u8]) -> i32 {
if input.len() == 4 {
if input[0] == 1 {
if input[1] == 3 {
if input[2] == 3 {
if input[3] == 7 {
return 1337;
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
} else {
if input.len() == 0 {
return -1;
} else {
return 0;
}
}
}
```
Next, we'll trace the program on the input `[]`.
The trace would look like this:
```rust,ignore
Branch { // if input.len() == 4
condition: Equals {
left: Variable { name: "input_len" },
right: Integer { value: 4 }
},
taken: false // This condition turned out to be false...
}
Branch { // if input.len() == 0
condition: Equals {
left: Variable { name: "input_len" },
right: Integer { value: 0 }
},
taken: true // This condition turned out to be true!
}
```
Using this trace, we can easily deduce that we can force the program to take a different path by having an input of length 4 or having an input with non-zero length.
We do this by negating each branch condition and analytically solving the resulting 'expression'.
In fact, we can create these expressions for any computation and give them to an [SMT](https://en.wikipedia.org/wiki/Satisfiability_modulo_theories)-Solver that will generate an input that satisfies the expression (as long as such an input exists).
In hybrid fuzzing, we combine this tracing + solving approach with more traditional fuzzing techniques.
## Concolic Tracing in LibAFL, SymCC and SymQEMU
The concolic tracing support in LibAFL is implemented using SymCC.
SymCC is a compiler plugin for clang that can be used as a drop-in replacement for a normal C or C++ compiler.
SymCC will instrument the compiled code with callbacks into a runtime that can be supplied by the user.
These callbacks allow the runtime to construct a trace that similar to the previous example.
### SymCC and its Runtimes
SymCC ships with 2 runtimes:
* a 'simple' runtime that attempts to solve any branches it comes across using [Z3](https://github.com/Z3Prover/z3/wiki) and
* a [QSym](https://github.com/sslab-gatech/qsym)-based runtime, which does a bit more filtering on the expressions and also solves using Z3.
The integration with LibAFL, however, requires you to **BYORT** (_bring your own runtime_) using the [`symcc_runtime`](https://docs.rs/symcc_runtime/0.1/symcc_runtime) crate.
This crate allows you to easily build a custom runtime out of the built-in building blocks or create entirely new runtimes with full flexibility.
Checkout out the `symcc_runtime` docs for more information on how to build your own runtime.
### SymQEMU
[SymQEMU](https://github.com/eurecom-s3/symqemu) is a sibling project to SymCC.
Instead of instrumenting the target at compile-time, it inserts instrumentation via dynamic binary translation, building on top of the [`QEMU`](https://www.qemu.org) emulation stack.
This means that using SymQEMU, any (x86) binary can be traced without the need to build in instrumentation ahead of time.
The `symcc_runtime` crate supports this use case and runtimes built with `symcc_runtime` also work with SymQEMU.
## Hybrid Fuzzing in LibAFL
The LibAFL repository contains an [example hybrid fuzzer](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/libfuzzer_stb_image_concolic).
There are three main steps involved with building a hybrid fuzzer using LibAFL:
1. Building a runtime,
2. choosing an instrumentation method and
3. building the fuzzer.
Note that the order of these steps is important.
For example, we need to have runtime ready before we can do instrumentation with SymCC.
### Building a Runtime
Building a custom runtime can be done easily using the `symcc_runtime` crate.
Note, that a custom runtime is a separate shared object file, which means that we need a separate crate for our runtime.
Check out the [example hybrid fuzzer's runtime](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/libfuzzer_stb_image_concolic/runtime) and the [`symcc_runtime` docs](https://docs.rs/symcc_runtime/0.1/symcc_runtime) for inspiration.
### Instrumentation
There are two main instrumentation methods to make use of concolic tracing in LibAFL:
* Using an **compile-time** instrumented target with **SymCC**.
This only works when the source is available for the target and the target is reasonably easy to build using the SymCC compiler wrapper.
* Using **SymQEMU** to dynamically instrument the target at **runtime**.
This avoids a separate instrumented target with concolic tracing instrumentation and does not require source code.
It should be noted, however, that the 'quality' of the generated expressions can be significantly worse and SymQEMU generally produces significantly more and significantly more convoluted expressions than SymCC.
Therefore, it is recommended to use SymCC over SymQEMU when possible.
#### Using SymCC
The target needs to be instrumented ahead of fuzzing using SymCC.
How exactly this is done does not matter.
However, the SymCC compiler needs to be made aware of the location of the runtime that it should instrument against.
This is done by setting the `SYMCC_RUNTIME_DIR` environment variable to the directory which contains the runtime (typically the `target/(debug|release)` folder of your runtime crate).
The example hybrid fuzzer instruments the target in its [`build.rs` build script](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/libfuzzer_stb_image_concolic/fuzzer/build.rs#L50).
It does this by cloning and building a copy of SymCC and then using this version to instrument the target.
The [`symcc_libafl` crate](https://docs.rs/symcc_libafl) contains helper functions for cloning and building SymCC.
Make sure you satisfy the [build requirements](https://github.com/eurecom-s3/symcc#readme) of SymCC before attempting to build it.
#### Using SymQEMU
Build SymQEMU according to its [build instructions](https://github.com/eurecom-s3/symqemu#readme).
By default, SymQEMU looks for the runtime in a sibling directory.
Since we don't have a runtime there, we need to let it know the path to your runtime by setting `--symcc-build` argument of the `configure` script to the path of your runtime.
### Building the Fuzzer
No matter the instrumentation method, the interface between the fuzzer and the instrumented target should now be consistent.
The only difference between using SymCC and SymQEMU should be the binary that represents the target:
In the case of SymCC it will be the binary that was build with instrumentation and with SymQEMU it will be the emulator binary (eg. `x86_64-linux-user/symqemu-x86_64`), followed by your uninstrumented target binary and arguments.
You can use the [`CommandExecutor`](https://docs.rs/libafl/0.6.0/libafl/executors/command/struct.CommandExecutor.html) to execute your target ([example](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs#L244)).
When configuring the command, make sure you pass the `SYMCC_INPUT_FILE` environment variable the input file path, if your target reads input from a file (instead of standard input).
#### Serialization and Solving
While it is perfectly possible to build a custom runtime that also performs the solving step of hybrid fuzzing in the context of the target process, the intended use of the LibAFL concolic tracing support is to serialize the (filtered and pre-processed) branch conditions using the [`TracingRuntime`](https://docs.rs/symcc_runtime/0.1/symcc_runtime/tracing/struct.TracingRuntime.html).
This serialized representation can be deserialized in the fuzzer process for solving using a [`ConcolicObserver`](https://docs.rs/libafl/0.6.0/libafl/observers/concolic/struct.ConcolicObserver.html) wrapped in a [`ConcolicTracingStage`](https://docs.rs/libafl/0.6.0/libafl/stages/concolic/struct.ConcolicTracingStage.html), which will attach a [`ConcolicMetadata`](https://docs.rs/libafl/0.6.0/libafl/observers/concolic/struct.ConcolicMetadata.html) to every [`TestCase`](https://docs.rs/libafl/0.6.0/libafl/corpus/testcase/struct.Testcase.html).
The `ConcolicMetadata` can be used to replay the concolic trace and solved using an SMT-Solver.
Most use-cases involving concolic tracing, however, will need to define some policy around which branches they want to solve.
The [`SimpleConcolicMutationalStage`](https://docs.rs/libafl/0.6.0//libafl/stages/concolic/struct.SimpleConcolicMutationalStage.html) can be used for testing purposes.
It will attempt to solve all branches, like the original simple backend from SymCC, using Z3.
### Example
The example fuzzer shows how to use the [`ConcolicTracingStage` together with the `SimpleConcolicMutationalStage`](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs#L222) to build a basic hybrid fuzzer.

View File

@ -0,0 +1,87 @@
# Binary-only Fuzzing with Frida
LibAFL supports different instrumentation engines for binary-only fuzzing.
A potent cross-platform (Windows, MacOS, Android, Linux, iOS) option for binary-only fuzzing is Frida; the dynamic instrumentation tool.
In this section, we will talk about the components in fuzzing with `libafl_frida`.
You can take a look at a working example in our [`fuzzers/frida_libpng`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/frida_libpng) folder for Linux, and [`fuzzers/frida_gdiplus`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/frida_gdiplus) for Windows.
## Dependencies
If you are on Linux or OSX, you'll need [libc++](https://libcxx.llvm.org/) for `libafl_frida` in addition to libafl's dependencies.
If you are on Windows, you'll need to install llvm tools.
## Harness & Instrumentation
LibAFL uses Frida's [__Stalker__](https://frida.re/docs/stalker/) to trace the execution of your program and instrument your harness.
Thus, you have to compile your harness to a dynamic library. Frida instruments your PUT after dynamically loading it.
For example in our `frida_libpng` example, we load the dynamic library and find the symbol to harness as follows:
```rust,ignore
let lib = libloading::Library::new(module_name).unwrap();
let target_func: libloading::Symbol<
unsafe extern "C" fn(data: *const u8, size: usize) -> i32,
> = lib.get(symbol_name.as_bytes()).unwrap();
```
## `FridaInstrumentationHelper` and Runtimes
To use functionalities that Frida offers, we'll first need to obtain `Gum` object by `Gum::obtain()`.
In LibAFL, we use the `FridaInstrumentationHelper` struct to manage frida-related state. `FridaInstrumentationHelper` is a key component that sets up the [__Transformer__](https://frida.re/docs/stalker/#transformer) that is used to generate the instrumented code. It also initializes the `Runtimes` that offer various instrumentation.
We have `CoverageRuntime` that can track the edge coverage, `AsanRuntime` for address sanitizer, `DrCovRuntime` that uses [__DrCov__](https://dynamorio.org/page_drcov.html) for coverage collection (to be imported in coverage tools like Lighthouse, bncov, dragondance,...), and `CmpLogRuntime` for cmplog instrumentation.
All of these runtimes can be slotted into `FridaInstrumentationHelper` at build time.
Combined with any `Runtime` you'd like to use, you can initialize the `FridaInstrumentationHelper` like this:
```rust,ignore
let gum = Gum::obtain();
let frida_options = FridaOptions::parse_env_options();
let coverage = CoverageRuntime::new();
let mut frida_helper = FridaInstrumentationHelper::new(
&gum,
&frida_options,
module_name,
modules_to_instrument,
tuple_list!(coverage),
);
```
## Running the Fuzzer
After setting up the `FridaInstrumentationHelper`. You can obtain the pointer to the coverage map by calling `map_ptr_mut()`.
```rust,ignore
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr(
"edges",
frida_helper.map_ptr_mut().unwrap(),
MAP_SIZE,
));
```
You can then link this observer to `FridaInProcessExecutor` as follows:
```rust,ignore
let mut executor = FridaInProcessExecutor::new(
&gum,
InProcessExecutor::new(
&mut frida_harness,
tuple_list!(
edges_observer,
time_observer,
AsanErrorsObserver::new(&ASAN_ERRORS)
),
&mut fuzzer,
&mut state,
&mut mgr,
)?,
&mut frida_helper,
);
```
And, finally you can run the fuzzer.
See the `frida_` examples in [`./fuzzers`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/) for more information and, for linux or full-system, play around with `libafl_qemu`, another binary-only tracer.

View File

@ -0,0 +1,40 @@
# Using LibAFL in `no_std` environments
It is possible to use LibAFL in `no_std` environments e.g. custom platforms like microcontrollers, kernels, hypervisors, and more.
You can simply add LibAFL to your `Cargo.toml` file:
```toml
libafl = { path = "path/to/libafl/", default-features = false}
```
Then build your project e.g. for `aarch64-unknown-none` using:
```sh
cargo build --no-default-features --target aarch64-unknown-none
```
## Use custom timing
The minimum amount of input LibAFL needs for `no_std` is a monotonically increasing timestamp.
For this, anywhere in your project you need to implement the `external_current_millis` function, which returns the current time in milliseconds.
```c
// Assume this a clock source from a custom stdlib, which you want to use, which returns current time in seconds.
int my_real_seconds(void)
{
return *CLOCK;
}
```
Here, we use it in Rust. `external_current_millis` is then called from LibAFL.
Note that it needs to be `no_mangle` in order to get picked up by LibAFL at linktime:
```rust,ignore
#[no_mangle]
pub extern "C" fn external_current_millis() -> u64 {
unsafe { my_real_seconds()*1000 }
}
```
See [./fuzzers/baby_no_std](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/baby_no_std) for an example.

View File

@ -0,0 +1,126 @@
# Snapshot Fuzzing in Nyx
NYX supports both source-based and binary-only fuzzing.
Currently, `libafl_nyx` only supports [afl++](https://github.com/AFLplusplus/AFLplusplus)'s instruction. To install it, you can use `sudo apt install aflplusplus`. Or compile from the source:
```bash
git clone https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus
make all # this will not compile afl's additional extension
```
Then you should compile the target with the afl++ compiler wrapper:
```bash
export CC=afl-clang-fast
export CXX=afl-clang-fast++
# the following line depends on your target
./configure --enable-shared=no
make
```
For binary-only fuzzing, Nyx uses intel-PT(Intel® Processor Trace). You can find the supported CPU at <https://www.intel.com/content/www/us/en/support/articles/000056730/processors.html>.
## Preparing Nyx working directory
This step is used to pack the target into Nyx's kernel. Don't worry, we have a template shell script in our [example](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/nyx_libxml2_parallel/setup_libxml2.sh):
the parameter's meaning is listed below:
```bash
git clone https://github.com/nyx-fuzz/packer
python3 "./packer/packer/nyx_packer.py" \
./libxml2/xmllint \ # your target binary
/tmp/nyx_libxml2 \ # the nyx work directory
afl \ # instruction type
instrumentation \
-args "/tmp/input" \ # the args of the program, means that we will run `xmllint /tmp/input` in each run.
-file "/tmp/input" \ # the input will be generated in `/tmp/input`. If no `--file`, then input will be passed through stdin
--fast_reload_mode \
--purge || exit
```
Then, you can generate the config file:
```bash
python3 ./packer/packer/nyx_config_gen.py /tmp/nyx_libxml2/ Kernel || exit
```
## Standalone fuzzing
In the [example fuzzer](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/nyx_libxml2_standalone/src/main.rs). First you need to run `./setup_libxml2.sh`, It will prepare your target and create your nyx work directory in `/tmp/libxml2`. After that, you can start write your code.
First, to create `Nyxhelper`:
```rust,ignore
let share_dir = Path::new("/tmp/nyx_libxml2/");
let cpu_id = 0; // use first cpu
let parallel_mode = false; // close parallel_mode
let mut helper = NyxHelper::new(share_dir, cpu_id, true, parallel_mode, None).unwrap(); // we don't the set the last parameter in standalone mode, we just use None, here
```
Then, fetch `trace_bits`, create an observer and the `NyxExecutor`:
```rust,ignore
let trace_bits = unsafe { std::slice::from_raw_parts_mut(helper.trace_bits, helper.map_size) };
let observer = StdMapObserver::new("trace", trace_bits);
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
```
Finally, use them as normal and pass them into `fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)` to start fuzzing.
## Parallel fuzzing
In the [example fuzzer](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/nyx_libxml2_parallel/src/main.rs). First you need to run `./setup_libxml2.sh` as described before.
Parallel fuzzing relies on [`Launcher`](../message_passing/spawn_instances.md), so spawn logic should be written in the scoop of anonymous function `run_client`:
```rust,ignore
let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id: usize| {}
```
In `run_client`, you need to create `NyxHelper` first:
```rust,ignore
let share_dir = Path::new("/tmp/nyx_libxml2/");
let cpu_id = _core_id as u32;
let parallel_mode = true;
let mut helper = NyxHelper::new(
share_dir, // nyx work directory
cpu_id, // current cpu id
true, // open snap_mode
parallel_mode, // open parallel mode
Some(parent_cpu_id.id as u32), // the cpu-id of master instance, there is only one master instance, other instances will be treated as slaved
)
.unwrap();
```
Then you can fetch the trace_bits and create an observer and `NyxExecutor`
```rust,ignore
let trace_bits =
unsafe { std::slice::from_raw_parts_mut(helper.trace_bits, helper.map_size) };
let observer = StdMapObserver::new("trace", trace_bits);
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
```
Finally, open a `Launcher` as normal to start fuzzing:
```rust,ignore
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),
}
```

View File

@ -1,321 +0,0 @@
# Baby Fuzzer
This chapter will teach you how to create a naive fuzzer using the LibAFL API, you will learn about basic entities such as `State`, `Observer`, and `Executor`.
The following chapters will discuss in detail the components of LibAFL, while here we will just scratch the fundamentals.
We are going to fuzz a simple Rust function that panics under a condition. The fuzzer will be single-threaded and will stop after the crash like libFuzzer does normally.
You can find a complete version of this tutorial as an example fuzzer in [`fuzzers/baby_fuzzer`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/baby_fuzzer).
## Creating a project
We use cargo to create a new Rust project with LibAFL as a dependency.
```sh
$ cargo new baby_fuzzer
$ cd baby_fuzzer
```
The generated _Cargo.toml_ looks like the following:
```toml
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
```
In order to use LibAFl we must add it as dependency adding `libafl = { path = "path/to/libafl/" }` under `[dependencies]`.
You can use the LibAFL version from crates.io if you want, in this case, you have to use `libafl = "*"` to get the latest version.
As we are going to fuzz Rust code, we want that a panic does not simply cause the program exit, but an abort that can be caught by the fuzzer.
To do that, we specify `panic = "abort"` in the [profiles](https://doc.rust-lang.org/cargo/reference/profiles.html).
Alongside this setting, we add some optimization flags for the compile when building in release mode.
The final _Cargo.toml_ should look similar to the following:
```toml
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { path = "path/to/libafl/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
```
## The function under test
Opening `src/main.rs` we have an empty main function.
To start, we create the closure that we want to fuzz. It takes a buffer as input and panics if it starts with "abc".
```rust
let mut harness = |buf: &[u8]| {
if buf.len() > 0 && buf[0] == 'a' as u8 {
if buf.len() > 1 && buf[1] == 'b' as u8 {
if buf.len() > 2 && buf[2] == 'c' as u8 {
panic!("=)");
}
}
}
};
// To test the panic:
// let input = "abc".as_bytes();
// harness(&input);
```
## Generating and running some tests
One of the main components that a LibAFL-based fuzzer uses is the State, a container of the data that is evolved during the fuzzing process, such as the Corpus of inputs.
In our main so we create a basic State instance like the following:
```rust
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
(),
);
```
It takes a random number generator, that is part of the fuzzer state, in this case, we use the default one `StdRand` but you can choose a different one. We seed it with the current nanoseconds.
As the second parameter, it takes an instance of something implementing the Corpus trait, InMemoryCorpus in this case. The corpus is the container of the testcases evolved by the fuzzer, in this case, we keep it all in memory.
We will discuss later the last parameter. The third is another corpus, in this case, to store the testcases that are considered as "solutions" for the fuzzer. For our purpose, the solution is the input that triggers the panic. In this case, we want to store it to disk under the `crashes` directory so we can inspect it.
Another required component is the EventManager. It handles some events such as the addition of a testcase to the corpus during the fuzzing process. For our purpose, we use the simplest one that just displays the information about these events to the user using a Stats instance.
```rust
// The Stats trait define how the fuzzer stats are reported to the user
let stats = SimpleStats::new(|s| println!("{}", s));
// The event manager handle the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(stats);
```
In addition, we have the Fuzzer, an entity that contains some actions that alter the State. On of these actions is the scheduling of the testcases to the fuzzer using a CorpusScheduler.
We create it as QueueCorpusScheduler, a scheduler that serves testcases to the fuzzer in a FIFO fashion.
```rust
// A queue policy to get testcasess from the corpus
let scheduler = QueueCorpusScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, (), ());
```
Last but not least, we need an Executor that is the entity responsible to run our program under test. In this example, we want to run the harness function in process, and so we use the InProcessExecutor.
```rust
// Create the executor for an in-process function
let mut executor = InProcessExecutor::new(
&mut harness,
(),
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create the Executor");
```
It takes a reference to the harness, the state, and the event manager. We will discuss the second parameter later.
As the executor expects that the harness returns an ExitKind object, we add `ExitKind::Ok` to our harness function.
Now we have the 4 major entities ready for running our tests, but we still cannot generate testcases.
For this purpose, we use a Generator, RandPrintablesGenerator that generates a string of printable bytes.
```rust
// Generator of printable bytearrays of max size 32
let mut generator = RandPrintablesGenerator::new(32);
// Generate 8 initial inputs
state
.generate_initial_inputs(&mut executor, &mut generator, &mut mgr, &scheduler, 8)
.expect("Failed to generate the initial corpus".into());
```
Now you can prepend the following `use` directives to your main.rs and compile it.
```rust
use std::path::PathBuf;
use libafl::{
bolts::{current_nanos, rands::StdRand},
corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
generators::RandPrintablesGenerator,
state::StdState,
stats::SimpleStats,
};
```
When running, you should see something similar to:
```sh
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/baby_fuzzer`
[LOG Debug]: Loaded 0 over 8 initial testcases
```
## Evolving the corpus with feedbacks
Now you simply ran 8 randomly generated testcases but none of them has been stored in the corpus. If you are very lucky, maybe you triggered the panic by chance but you don't see any saved file in `crashes`.
Now we want to turn our simple fuzzer into a feedback-based one and increase the chance to generate the right input to trigger the panic. We are going to implement a simple feedback based on the 3 conditions that are needed to reach the panic.
To do that, we need a way to keep track of if a condition is satisfied. The component that feeds the fuzzer with information about properties of a fuzzing run, the satisfied conditions in our case, is the Observer. We use the StdMapObserver, the default observer that uses a map to keep track of covered elements. In our fuzzer, each condition is mapped to an entry of such map.
We represent such map as a `static mut` variable:
```rust
// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
fn signals_set(idx: usize) {
unsafe { SIGNALS[idx] = 1 };
}
```
As we don't rely on any instrumentation engine, we have to manually track the satisfied conditions in a map modyfing our tested function:
```rust
// The closure that we want to fuzz
let mut harness = |buf: &[u8]| {
signals_set(0);
if buf.len() > 0 && buf[0] == 'a' as u8 {
signals_set(1);
if buf.len() > 1 && buf[1] == 'b' as u8 {
signals_set(2);
if buf.len() > 2 && buf[2] == 'c' as u8 {
panic!("=)");
}
}
}
ExitKind::Ok
};
```
The observer can be created directly from the `SIGNALS` map, in the following way:
```rust
// Create an observation channel using the signals map
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
```
The observers are usually kept in the corresponding executor as they keep track of information that is valid for just one run. We have then to modify our InProcessExecutor creation to include the observer as follows:
```rust
// Create the executor for an in-process function with just one observer
let mut executor =
InProcessExecutor::new(&mut harness, tuple_list!(observer), &mut state, &mut mgr)
.expect("Failed to create the Executor".into());
```
Now that the fuzzer can observe which condition is satisfied, we need a way to rate an input as interesting (i.e. worth of addition to the corpus) based on this observation. Here comes the notion of Feedback. The Feedback is part of the State and provides a way to rate input and its corresponding execution as interesting looking for the information in the observers. Feedbacks can maintain a cumulative state of the information seen so far in a so-called FeedbackState instance, in our case it maintains the set of conditions satisfied in the previous runs.
We use MaxMapFeedback, a feedback that implements a novelty search over the map of the MapObserver. Basically, if there is a value in the observer's map that is greater than the maximum value registered so far for the same entry, it rates the input as interesting and updates its state.
Feedbacks are used also to decide if an input is a "solution". The feedback that does that is called the Objective Feedback and when it rates an input as interested it is not saved to the corpus but to the solutions, written in the `crashes` folder in our case. We use the CrashFeedback to tell the fuzzer that if an input causes the program to crash it is a solution for us.
We need to update our State creation including the feedback state and the Fuzzer including the feedback and the objective:
```rust
// The state of the edges feedback.
let feedback_state = MapFeedbackState::with_observer(&observer);
// Feedback to rate the interestingness of an input
let feedback = MaxMapFeedback::new(&feedback_state, &observer);
// A feedback to choose if an input is a solution or not
let objective = CrashFeedback::new();
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
// States of the feedbacks.
// They are the data related to the feedbacks that you want to persist in the State.
tuple_list!(feedback_state),
);
// ...
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
```
## The actual fuzzing
Now, after including the correct `use`, we can run the program, but the outcome is not so different from the previous one as the random generator does not take into account what we save as interesting in the corpus. To do that, we need to plug a Mutator.
Another central component of LibAFL are the Stages, that are actions done on individual inputs taken from the corpus. The MutationalStage mutates the input and executes it several times for instance.
As the last step, we create a MutationalStage that uses a mutator inspired by the havoc mutator of AFL.
```rust
// Setup a mutational stage with a basic bytes mutator
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.expect("Error in the fuzzing loop");
```
`fuzz_loop` will request a testcase for each iteration to the fuzzer using the scheduler and then it will invoke the stage.
After adding this code, we have a proper fuzzer, that can run a find the input that panics the function in less than a second.
```
$ cargo run
Compiling baby_fuzzer v0.1.0 (/home/andrea/Desktop/baby_fuzzer)
Finished dev [unoptimized + debuginfo] target(s) in 1.56s
Running `target/debug/baby_fuzzer`
[New Testcase] clients: 1, corpus: 2, objectives: 0, executions: 1, exec/sec: 0
[LOG Debug]: Loaded 1 over 8 initial testcases
[New Testcase] clients: 1, corpus: 3, objectives: 0, executions: 804, exec/sec: 0
[New Testcase] clients: 1, corpus: 4, objectives: 0, executions: 1408, exec/sec: 0
thread 'main' panicked at '=)', src/main.rs:35:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Crashed with SIGABRT
Child crashed!
[Objective] clients: 1, corpus: 4, objectives: 1, executions: 1408, exec/sec: 0
Waiting for broker...
Bye!
```
As you can see, after the panic message, the `objectives` count of the log increased by one and you will find the crashing input in `crashes/id_0`.

View File

@ -0,0 +1,381 @@
# A Simple LibAFL Fuzzer
This chapter discusses a naive fuzzer using the LibAFL API.
You will learn about basic entities such as `State`, `Observer`, and `Executor`.
While the following chapters discuss the components of LibAFL in detail, here we introduce the fundamentals.
We are going to fuzz a simple Rust function that panics under a condition. The fuzzer will be single-threaded and will stop after the crash, just like libFuzzer normally does.
You can find a complete version of this tutorial as an example fuzzer in [`fuzzers/baby_fuzzer`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/baby_fuzzer).
> ### Warning
>
> This example fuzzer is too naive for any real-world usage.
> Its purpose is solely to show the main components of the library, for a more in-depth walkthrough on building a custom fuzzer go to the [Tutorial chapter](../tutorial/intro.md) directly.
## Creating a project
We use cargo to create a new Rust project with LibAFL as a dependency.
```sh
$ cargo new baby_fuzzer
$ cd baby_fuzzer
```
The generated `Cargo.toml` looks like the following:
```toml
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
```
In order to use LibAFl we must add it as dependency adding `libafl = { path = "path/to/libafl/" }` under `[dependencies]`.
You can use the LibAFL version from [crates.io](https://crates.io/crates/libafl) if you want, in this case, you have to use `libafl = "*"` to get the latest version (or set it to the current version).
As we are going to fuzz Rust code, we want that a panic does not simply cause the program to exit, but raise an `abort` that can then be caught by the fuzzer.
To do that, we specify `panic = "abort"` in the [profiles](https://doc.rust-lang.org/cargo/reference/profiles.html).
Alongside this setting, we add some optimization flags for the compilation, when building in release mode.
The final `Cargo.toml` should look similar to the following:
```toml
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { path = "path/to/libafl/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
```
## The function under test
Opening `src/main.rs`, we have an empty `main` function.
To start, we create the closure that we want to fuzz. It takes a buffer as input and panics if it starts with `"abc"`.
`ExitKind` is used to inform the fuzzer about the harness' exit status.
```rust
extern crate libafl;
use libafl::{
bolts::AsSlice,
inputs::{BytesInput, HasTargetBytes},
executors::ExitKind,
};
fn main(){
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
if buf.len() > 0 && buf[0] == 'a' as u8 {
if buf.len() > 1 && buf[1] == 'b' as u8 {
if buf.len() > 2 && buf[2] == 'c' as u8 {
panic!("=)");
}
}
}
ExitKind::Ok
};
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
harness(&input);
}
```
## Generating and running some tests
One of the main components that a LibAFL-based fuzzer uses is the State, a container of the data that is evolved during the fuzzing process.
Includes all State, such as the Corpus of inputs, the current RNG state, and potential Metadata for the testcases and run.
In our `main` we create a basic State instance like the following:
```rust,ignore
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
&mut (),
&mut ()
).unwrap();
```
- The first parameter is a random number generator, that is part of the fuzzer state, in this case, we use the default one `StdRand`, but you can choose a different one. We seed it with the current nanoseconds.
- The second parameter is an instance of something implementing the Corpus trait, `InMemoryCorpus` in this case. The corpus is the container of the testcases evolved by the fuzzer, in this case, we keep it all in memory.
To avoid type annotation error, you can use `InMemoryCorpus::<BytesInput>::new()` to replace `InMemoryCorpus::new()`. If not, type annotation will be automatically inferred when adding `executor`.
- third parameter is another corpus that stores the "solution" testcases for the fuzzer. For our purpose, the solution is the input that triggers the panic. In this case, we want to store it to disk under the `crashes` directory, so we can inspect it.
- last two parameters are feedback and objective, we will discuss them later.
Another required component is the **EventManager**. It handles some events such as the addition of a testcase to the corpus during the fuzzing process. For our purpose, we use the simplest one that just displays the information about these events to the user using a `Monitor` instance.
```rust,ignore
// The Monitor trait defines how the fuzzer stats are displayed to the user
let mon = SimpleMonitor::new(|s| println!("{}", s));
// The event manager handle the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(mon);
```
In addition, we have the **Fuzzer**, an entity that contains some actions that alter the State. One of these actions is the scheduling of the testcases to the fuzzer using a **Scheduler**.
We create it as `QueueScheduler`, a scheduler that serves testcases to the fuzzer in a FIFO fashion.
```rust,ignore
// A queue policy to get testcasess from the corpus
let scheduler = QueueScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, (), ());
```
Last but not least, we need an **Executor** that is the entity responsible to run our program under test. In this example, we want to run the harness function in-process (without forking off a child, for example), and so we use the `InProcessExecutor`.
```rust,ignore
// Create the executor for an in-process function
let mut executor = InProcessExecutor::new(
&mut harness,
(),
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create the Executor");
```
It takes a reference to the harness, the state, and the event manager. We will discuss the second parameter later.
As the executor expects that the harness returns an ExitKind object, so we have added `ExitKind::Ok` to our harness function before.
Now we have the 4 major entities ready for running our tests, but we still cannot generate testcases.
For this purpose, we use a **Generator**, `RandPrintablesGenerator` that generates a string of printable bytes.
```rust,ignore
use libafl::generators::RandPrintablesGenerator;
// Generator of printable bytearrays of max size 32
let mut generator = RandPrintablesGenerator::new(32);
// Generate 8 initial inputs
state
.generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8)
.expect("Failed to generate the initial corpus".into());
```
Now you can prepend the necessary `use` directives to your main.rs and compile the fuzzer.
```rust
extern crate libafl;
use std::path::PathBuf;
use libafl::{
bolts::{AsSlice, current_nanos, rands::StdRand},
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
fuzzer::StdFuzzer,
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
schedulers::QueueScheduler,
state::StdState,
};
```
When running, you should see something similar to:
```sh
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/baby_fuzzer`
[LOG Debug]: Loaded 0 over 8 initial testcases
```
## Evolving the corpus with feedbacks
Now you simply ran 8 randomly generated testcases, but none of them has been stored in the corpus. If you are very lucky, maybe you triggered the panic by chance but you don't see any saved file in `crashes`.
Now we want to turn our simple fuzzer into a feedback-based one and increase the chance to generate the right input to trigger the panic. We are going to implement a simple feedback based on the 3 conditions that are needed to reach the panic. To do that, we need a way to keep track of if a condition is satisfied.
**Observer** can record the information about properties of a fuzzing run and then feeds the fuzzer. We use the `StdMapObserver`, the default observer that uses a map to keep track of covered elements. In our fuzzer, each condition is mapped to an entry of such map.
We represent such map as a `static mut` variable.
As we don't rely on any instrumentation engine, we have to manually track the satisfied conditions by `singals_set` in our harness:
```rust
extern crate libafl;
use libafl::{
bolts::AsSlice,
inputs::{BytesInput, HasTargetBytes},
executors::ExitKind,
};
// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
fn signals_set(idx: usize) {
unsafe { SIGNALS[idx] = 1 };
}
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
signals_set(0); // set SIGNALS[0]
if buf.len() > 0 && buf[0] == 'a' as u8 {
signals_set(1); // set SIGNALS[1]
if buf.len() > 1 && buf[1] == 'b' as u8 {
signals_set(2); // set SIGNALS[2]
if buf.len() > 2 && buf[2] == 'c' as u8 {
panic!("=)");
}
}
}
ExitKind::Ok
};
```
The observer can be created directly from the `SIGNALS` map, in the following way:
```rust,ignore
// Create an observation channel using the signals map
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
```
The observers are usually kept in the corresponding executor as they keep track of information that is valid for just one run. We have then to modify our InProcessExecutor creation to include the observer as follows:
```rust,ignore
// Create the executor for an in-process function with just one observer
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(observer),
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create the Executor".into());
```
Now that the fuzzer can observe which condition is satisfied, we need a way to rate an input as interesting (i.e. worth of addition to the corpus) based on this observation. Here comes the notion of Feedback.
**Feedback** is part of the State and provides a way to rate input and its corresponding execution as interesting looking for the information in the observers. Feedbacks can maintain a cumulative state of the information seen so far in a metadata in the State, in our case it maintains the set of conditions satisfied in the previous runs.
We use `MaxMapFeedback`, a feedback that implements a novelty search over the map of the MapObserver. Basically, if there is a value in the observer's map that is greater than the maximum value registered so far for the same entry, it rates the input as interesting and updates its state.
**Objective Feedback** is another kind of Feedback which decide if an input is a "solution". It will save input to solutions(`./crashes` in our case) other than corpus when the input is rated interesting. We use `CrashFeedback` to tell the fuzzer that if an input causes the program to crash it is a solution for us.
We need to update our State creation including the feedback state and the Fuzzer including the feedback and the objective:
```rust,ignore
extern crate libafl;
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
corpus::{InMemoryCorpus, OnDiskCorpus},
feedbacks::{MaxMapFeedback, CrashFeedback},
fuzzer::StdFuzzer,
state::StdState,
observers::StdMapObserver,
};
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new();
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
&mut feedback,
&mut objective
).unwrap();
// ...
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
```
## The actual fuzzing
Now, after including the correct `use`, we can run the program, but the outcome is not so different from the previous one as the random generator does not take into account what we save as interesting in the corpus. To do that, we need to plug a Mutator.
**Stages** perform actions on individual inputs, taken from the corpus.
For instance, the `MutationalStage` executes the harness several times in a row, every time with mutated inputs.
As the last step, we create a MutationalStage that uses a mutator inspired by the havoc mutator of AFL.
```rust,ignore
use libafl::{
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
stages::mutational::StdMutationalStage,
fuzzer::Fuzzer,
};
// ...
// Setup a mutational stage with a basic bytes mutator
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.expect("Error in the fuzzing loop");
```
`fuzz_loop` will request a testcase for each iteration to the fuzzer using the scheduler and then it will invoke the stage.
After adding this code, we have a proper fuzzer, that can run a find the input that panics the function in less than a second.
```text
$ cargo run
Compiling baby_fuzzer v0.1.0 (/home/andrea/Desktop/baby_fuzzer)
Finished dev [unoptimized + debuginfo] target(s) in 1.56s
Running `target/debug/baby_fuzzer`
[New Testcase] clients: 1, corpus: 2, objectives: 0, executions: 1, exec/sec: 0
[LOG Debug]: Loaded 1 over 8 initial testcases
[New Testcase] clients: 1, corpus: 3, objectives: 0, executions: 804, exec/sec: 0
[New Testcase] clients: 1, corpus: 4, objectives: 0, executions: 1408, exec/sec: 0
thread 'main' panicked at '=)', src/main.rs:35:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Crashed with SIGABRT
Child crashed!
[Objective] clients: 1, corpus: 4, objectives: 1, executions: 1408, exec/sec: 0
Waiting for broker...
Bye!
```
As you can see, after the panic message, the `objectives` count of the log increased by one and you will find the crashing input in `crashes/`.
The complete code can be found in [`./fuzzers/baby_fuzzer`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/baby_fuzzer) alongside other `baby_` fuzzers.

View File

@ -0,0 +1,12 @@
# More Examples
Examples can be found under `./fuzzer`.
|fuzzer name|usage|
| ---- | ---- |
| baby_fuzzer_gramatron | [Gramatron](https://github.com/HexHive/Gramatron) is a fuzzer that uses **grammar automatons** in conjunction with aggressive mutation operators to synthesize complex bug triggers |
| baby_fuzzer_grimoire | [Grimoire](https://www.usenix.org/system/files/sec19-blazytko.pdf) is a fully automated coverage-guided fuzzer which works **without any form of human interaction or pre-configuration** |
| baby_fuzzer_nautilus | [nautilus](https://www.ndss-symposium.org/wp-content/uploads/2019/02/ndss2019_04A-3_Aschermann_paper.pdf) is a **coverage guided, grammar based** fuzzer|
|baby_fuzzer_tokens| basic **token level** fuzzer with token level mutations|
|baby_fuzzer_with_forkexecutor| example for **InProcessForkExecutor**|
|baby_no_std|a minimalistic example how to create a libafl based fuzzer that works on **`no_std`** environments like TEEs, Kernels or on barew metal|

View File

@ -0,0 +1,5 @@
# Core Concepts
LibAFL is designed around some core concepts that we think can effectively abstract most of the other fuzzers designs.
Here, we discuss these concepts and provide some examples related to other fuzzers.

View File

@ -0,0 +1,11 @@
# Corpus
The Corpus is where testcases are stored. We define a Testcase as an Input and a set of related metadata like execution time for instance.
A Corpus can store testcases in different ways, for example on disk, or in memory, or implement a cache to speedup on disk storage.
Usually, a testcase is added to the Corpus when it is considered as interesting, but a Corpus is used also to store testcases that fulfill an objective (like crashing the tested program for instance).
Related to the Corpus, there is the way in which the fuzzer should ask for the next testcase to fuzz picking it from the Corpus. The taxonomy for this in LibAFL is CorpusScheduler, the entity representing the policy to pop testcases from the Corpus, FIFO for instance.
Speaking about the code, [`Corpus`](https://docs.rs/libafl/0/libafl/corpus/trait.Corpus.html) and [`CorpusScheduler`](https://docs.rs/libafl/0/libafl/corpus/trait.CorpusScheduler.html) are traits.

View File

@ -0,0 +1,70 @@
# Executor
In different fuzzers, this concept of executing the program under test means each run is now always the same.
For instance, for in-memory fuzzers like libFuzzer an execution is a call to an harness function, for hypervisor-based fuzzers like [kAFL](https://github.com/IntelLabs/kAFL) instead an entire operating system is started from a snapshot for each run.
In our model, an Executor is the entity that defines not only how to execute the target, but all the volatile operations that are related to just a single run of the target.
So the Executor is for instance responsible to inform the program about the input that the fuzzer wants to use in the run, writing to a memory location for instance or passing it as a parameter to the harness function.
In our model, it can also hold a set of Observers connected with each execution.
In Rust, we bind this concept to the [`Executor`](https://docs.rs/libafl/0/libafl/executors/trait.Executor.html) trait. A structure implementing this trait must implement [`HasObservers`](https://docs.rs/libafl/0/libafl/executors/trait.HasObservers.html) too if wants to hold a set of Observers.
By default, we implement some commonly used Executors such as [`InProcessExecutor`](https://docs.rs/libafl/0/libafl/executors/inprocess/struct.InProcessExecutor.html) in which the target is a harness function providing in-process crash detection. Another Executor is the [`ForkserverExecutor`](https://docs.rs/libafl/0/libafl/executors/forkserver/struct.ForkserverExecutor.html) that implements an AFL-like mechanism to spawn child processes to fuzz.
A common pattern when creating an Executor is wrapping an existing one, for instance [`TimeoutExecutor`](https://docs.rs/libafl/0.6.1/libafl/executors/timeout/struct.TimeoutExecutor.html) wraps an executor and install a timeout callback before calling the original run function of the wrapped executor.
## InProcessExecutor
Let's begin with the base case; `InProcessExecutor`.
This executor executes the harness program (function) inside the fuzzer process.
When you want to execute the harness as fast as possible, you will most probably want to use this `InprocessExecutor`.
One thing to note here is, when your harness is likely to have heap corruption bugs, you want to use another allocator so that corrupted heap does not affect the fuzzer itself. (For example, we adopt MiMalloc in some of our fuzzers.). Alternatively you can compile your harness with address sanitizer to make sure you can catch these heap bugs.
## ForkserverExecutor
Next, we'll take a look at the `ForkserverExecutor`. In this case, it is `afl-cc` (from AFLplusplus/AFLplusplus) that compiles the harness code, and therefore, we can't use `EDGES_MAP` anymore. Hopefully, we have [_a way_](https://github.com/AFLplusplus/AFLplusplus/blob/2e15661f184c77ac1fbb6f868c894e946cbb7f17/instrumentation/afl-compiler-rt.o.c#L270) to tell the forkserver which map to record the coverage.
As you can see from the forkserver example,
```rust,ignore
//Coverage map shared between observer and executor
let mut shmem = StdShMemProvider::new().unwrap().new_shmem(MAP_SIZE).unwrap();
//let the forkserver know the shmid
shmem.write_to_env("__AFL_SHM_ID").unwrap();
let mut shmem_buf = shmem.as_mut_slice();
```
Here we make a shared memory region; `shmem`, and write this to environmental variable `__AFL_SHM_ID`. Then the instrumented binary, or the forkserver, finds this shared memory region (from the aforementioned env var) to record its coverage. On your fuzzer side, you can pass this shmem map to your `Observer` to obtain coverage feedbacks combined with any `Feedback`.
Another feature of the `ForkserverExecutor` to mention is the shared memory testcases. In normal cases, the mutated input is passed between the forkserver and the instrumented binary via `.cur_input` file. You can improve your forkserver fuzzer's performance by passing the input with shared memory.
If the target is configured to use shared memory testcases, the `ForkserverExecutor` will notice this during the handshake and will automatically set up things accordingly.
See AFL++'s [_documentation_](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md#5-shared-memory-fuzzing) or the fuzzer example in `forkserver_simple/src/program.c` for reference.
## InprocessForkExecutor
Finally, we'll talk about the `InProcessForkExecutor`.
`InProcessForkExecutor` has only one difference from `InprocessExecutor`; It forks before running the harness and that's it.
But why do we want to do so? well, under some circumstances, you may find your harness pretty unstable or your harness wreaks havoc on the global states. In this case, you want to fork it before executing the harness runs in the child process so that it doesn't break things.
However, we have to take care of the shared memory, it's the child process that runs the harness code and writes the coverage to the map.
We have to make the map shared between the parent process and the child process, so we'll use shared memory again. You should compile your harness with `pointer_maps` (for `libafl_targets`) features enabled, this way, we can have a pointer; `EDGES_MAP_PTR` that can point to any coverage map.
On your fuzzer side, you can allocate a shared memory region and make the `EDGES_MAP_PTR` point to your shared memory.
```rust,ignore
let mut shmem;
unsafe{
shmem = StdShMemProvider::new().unwrap().new_shmem(MAX_EDGES_NUM).unwrap();
}
let shmem_buf = shmem.as_mut_slice();
unsafe{
EDGES_PTR = shmem_buf.as_ptr();
}
```
Again, you can pass this shmem map to your `Observer` and `Feedback` to obtain coverage feedbacks.

View File

@ -0,0 +1,26 @@
# Feedback
The Feedback is an entity that classifies the outcome of an execution of the program under test as interesting or not.
Typically, if an execution is interesting, the corresponding input used to feed the target program is added to a corpus.
Most of the time, the notion of Feedback is deeply linked to the Observer, but they are different concepts.
The Feedback, in most of the cases, processes the information reported by one or more observers to decide if the execution is interesting.
The concept of "interestingness" is abstract, but typically it is related to a novelty search (i.e. interesting inputs are those that reach a previously unseen edge in the control flow graph).
As an example, given an Observer that reports all the sizes of memory allocations, a maximization Feedback can be used to maximize these sizes to sport pathological inputs in terms of memory consumption.
In terms of code, the library offers the [`Feedback`](https://docs.rs/libafl/0/libafl/feedbacks/trait.Feedback.html) and the [`FeedbackState`](https://docs.rs/libafl/0/libafl/feedbacks/trait.FeedbackState.html) traits.
The first is used to implement functors that, given the state of the observers from the last execution, tells if the execution was interesting. The second is tied with `Feedback` and it is the state of the data that the feedback wants to persist in the fuzzers's state, for instance the cumulative map holding all the edges seen so far in the case of a feedback based on edge coverage.
Multiple Feedbacks can be combined into boolean formula, considering for instance an execution as interesting if it triggers new code paths or execute in less time compared to the average execution time using [`feedback_or`](https://docs.rs/libafl/*/libafl/macro.feedback_or.html).
On top, logic operators like `feedback_or` and `feedback_and` have a `_fast` option (`feedback_or_fast` where the second feedback will not be evaluated, if the first part already answers the `interestingness` question, to save precious performance.
Using `feedback_and_fast` in combination with [`ConstFeedback`](https://docs.rs/libafl/*/libafl/feedbacks/enum.ConstFeedback.html#method.new), certain feedbacks can be disabled dynamically.
## Objectives
While feedbacks are commonly used to decide if an [`Input`](https://docs.rs/libafl/*/libafl/inputs/trait.Input.html) should be kept for future mutations, they serve a double-purpose, as so-called `Objective Feedbacks`.
In this case, the `interestingness` of a feedback indicates, if an `Objective` has been hit.
Commonly, these would be a`crash or a timeout, but they can also be used to find specific parts of the program, for sanitization, or a differential fuzzing success.

View File

@ -0,0 +1,9 @@
# Generator
A Generator is a component designed to generate an Input from scratch.
Typically, a random generator is used to generate random inputs.
Generators are traditionally less used in Feedback-driven Fuzzing, but there are exceptions, like Nautilus, that uses a Grammar generator to create the initial corpus and a sub-tree Generator as a mutation of its grammar Mutator.
In the code, [`Generator`](https://docs.rs/libafl/0/libafl/generators/trait.Generator.html) is a trait.

View File

@ -0,0 +1,15 @@
# Input
Formally, the input of a program is the data taken from external sources that affect the program behavior.
In our model of an abstract fuzzer, we define the Input as the internal representation of the program input (or a part of it).
In the straightforward case, the input of the program is a byte array and in fuzzers such as AFL we store and manipulate exactly these byte arrays.
But it is not always the case. A program can expect inputs that are not byte arrays (e.g. a sequence of syscalls) and the fuzzer does not represent the Input in the same way that the program consumes it.
In case of a grammar fuzzer for instance, the Input is generally an Abstract Syntax Tree because it is a data structure that can be easily manipulated while maintaining the validity, but the program expects a byte array as input, so just before the execution, the tree is serialized to a sequence of bytes.
In the Rust code, an [`Input`](https://docs.rs/libafl/*/libafl/inputs/trait.Input.html) is a trait that can be implemented only by structures that are serializable and have only owned data as fields.
While most fuzzer use a normal `BytesInput`], more advanced inputs like inputs include special inputs for grammar fuzzing ([GramatronInput](https://docs.rs/libafl/*/libafl/inputs/gramatron/struct.GramatronInput.html) or `NautilusInput` on nightly), as well as the token-level [EncodedInput](https://docs.rs/libafl/*/libafl/inputs/encoded/struct.EncodedInput.html).

View File

@ -0,0 +1,9 @@
# Mutator
The Mutator is an entity that takes one or more Inputs and generates a new derived one.
Mutators can be composed, and they are generally linked to a specific Input type.
There can be, for instance, a Mutator that applies more than a single type of mutation on the input. Consider a generic Mutator for a byte stream, bit flip is just one of the possible mutations but not the only one, there is also, for instance, the random replacement of a byte of the copy of a chunk.
In LibAFL, [`Mutator`](https://docs.rs/libafl/*/libafl/mutators/trait.Mutator.html) is a trait.

View File

@ -0,0 +1,14 @@
# Observer
An Observer is an entity that provides an information observed during the execution of the program under test to the fuzzer.
The information contained in the Observer is not preserved across executions, but it may be serialized and passed on to other nodes if an `Input` is considered `interesting`, and added to the `Corpus`.
As an example, the coverage map, filled during the execution to report the executed edges used by fuzzers such as AFL and `HonggFuzz` can be considered an observation. Another `Observer` can be the time spent executing a run, the program output, or more advanced observation, like maximum stack depth at runtime.
This information is not preserved across runs, and it is an observation of a dynamic property of the program.
In terms of code, in the library this entity is described by the [`Observer`](https://docs.rs/libafl/0/libafl/observers/trait.Observer.html) trait.
In addition to holding the volatile data connected with the last execution of the target, the structures implementing this trait can define some execution hooks that are executed before and after each fuzz case. In these hooks, the observer can modify the fuzzer's state.
The fuzzer will act based on these observers through a [`Feedback`](./feedback.md), that reduces the observation to the choice if a testcase is `interesting` for the fuzzer, or not.

View File

@ -0,0 +1,9 @@
# Stage
A Stage is an entity that operates on a single Input got from the Corpus.
For instance, a Mutational Stage, given an input of the corpus, applies a Mutator and executes the generated input one or more time. How many times this has to be done can be scheduled, AFL for instance uses a performance score of the input to choose how many times the havoc mutator should be invoked. This can depend also on other parameters, for instance, the length of the input if we want to just apply a sequential bitflip, or be a fixed value.
A stage can also be an analysis stage, for instance, the Colorization stage of Redqueen that aims to introduce more entropy in a testcase or the Trimming stage of AFL that aims to reduce the size of a testcase.
There are several stages in the LibAFL codebase implementing the [`Stage`](https://docs.rs/libafl/*/libafl/stages/trait.Stage.html) trait.

View File

@ -2,12 +2,14 @@
The LibAFL architecture is built around some entities to allow code reuse and low-cost abstractions. The LibAFL architecture is built around some entities to allow code reuse and low-cost abstractions.
Initially, we started thinking to implement LibAFL in an Object Oriented language, such C++. When we landed to Rust, we immediately changed our idea as we realized that, while Rust allows a sort of OOP pattern, we can build the library using a more sane approach like the one described in [this blogpost](https://kyren.github.io/2018/09/14/rustconf-talk.html) about game design in Rust. Initially, we started thinking about implementing LibAFL in a traditional Object-Oriented language, like C++. When we switched to Rust, we immediately changed our idea as we realized that, we can build the library using a more rust-y approach, namely the one described in [this blogpost](https://kyren.github.io/2018/09/14/rustconf-talk.html) about game design in Rust.
The LibAFL code reuse meachanism is so based on components rather than sub-classes, but there are still some OOP patterns in the library. The LibAFL code reuse mechanism is based on components, rather than sub-classes, but there are still some OOP patterns in the library.
Thinking about similar fuzzers, you can observe that most of the times the data structures that are modified are the ones related to testcases and the fuzzer global state. Thinking about similar fuzzers, you can observe that most of the time the data structures that are modified are the ones related to testcases and the fuzzer global state.
Beside the entities described previously, we introduce the Testcase and State entities. The Testcase is a container for an Input stored in the Corpus and its metadata (so, in the implementation, the Corpus stores Testcases) and the State contains all the metadata that are evolved while running the fuzzer, Corpus included. Beside the entities previously described, we introduce the [`Testcase`](https://docs.rs/libafl/0.6/libafl/corpus/testcase/struct.Testcase.html) and [`State`](https://docs.rs/libafl/0.6/libafl/state/struct.StdState.html) entities. The Testcase is a container for an Input stored in the Corpus and its metadata (so, in the implementation, the Corpus stores Testcases) and the State contains all the metadata that are evolved while running the fuzzer, Corpus included.
The State, in the implementation, contains only owned objects that are serializable, and it is serializable itself. Some fuzzers may want to serialize its state when pausing or just, when doing in-process fuzzing, serialize on crash and deserialize in the new process to continue to fuzz with all the metadata preserved.
Additionally, we group the entities that are "actions", like the `CorpusScheduler` and the `Feedbacks`, in a common place, the [`Fuzzer'](https://docs.rs/libafl/*/libafl/fuzzer/struct.StdFuzzer.html).

View File

@ -1,86 +0,0 @@
# Core Concepts
LibAFL is designed around some core concepts that we think can effectively abstract most of the other fuzzers designs.
Here, we discuss these concepts and provide some examples related to other fuzzers.
TODO add links to trait definitions in docs.rs
## Observer
An Observer, or Observation Channel, is an entity that provides an information observed during the execution of the program under test to the fuzzer.
The information contained in the Observer is not preserved across executions.
As an example, the coverage shared map filled during the execution to report the executed edges used by fuzzers such as AFL and HonggFuzz can be considered an Observation Channel.
This information is not preserved across runs and it is an observation of a dynamic property of the program.
## Executor
In different fuzzers, this concept of executing the program under test means each run is now always the same.
For instance, for in-memory fuzzers like libFuzzer an execution is a call to an harness function, for hypervisor-based fuzzers like [kAFL](https://github.com/IntelLabs/kAFL) instead an entire operating system is started from a snapshot for each run.
In our model, an Executor is the entity that defines not only how to execute the target, but all the volatile operations that are related to just a single run of the target.
So the Executor is for instance responsible to inform the program about the input that the fuzzer wants to use in the run, writing to a memory location for instance or passing it as a parameter to the harness function.
It also holds a set of Observers, as they are related to just a single run of the target.
## Feedback
The Feedback is an entity that classifies the outcome of an execution of the program under test as interesting or not.
Typically, if an execution is interesting, the corresponding input used to feed the target program is added to a corpus.
Most of the times, the notion of Feedback is deeply linked to the Observer, but they are different concepts.
The Feedback, in most of the cases, processes the information reported by one or more observers to decide if the execution is interesting.
The concept of "interestingness" is abstract, but typically it is related to a novelty search (i.e. interesting inputs are those that reach a previously unseen edge in the control flow graph).
As an example, given an Observer that reports all the sizes of memory allocations, a maximization Feedback can be used to maximize these sizes to sport pathological inputs in terms of memory consumption.
## Input
Formally, the input of a program is the data taken from external sources that affect the program behaviour.
In our model of an abstract fuzzer, we define the Input as the internal representation of the program input (or a part of it).
In the straightforward case, the input of the program is a byte array and in fuzzers such as AFL we store and manipulate exactly these byte arrays.
But it is not always the case. A program can expect inputs that are not byte arrays (e.g. a sequence of syscalls) and the fuzzer does not represent the Input in the same way that the program consumes it.
In case of a grammar fuzzer for instance, the Input is generally an Abstract Syntax Tree because it is a data structure that can be easily manipulated while maintaining the validity, but the program expects a byte array as input, so just before the execution, the tree is serialized to a sequence of bytes.
## Corpus
The Corpus is where testcases are stored. A Testcase is defined as an Input and a set of related metadata like execution time for instance.
For instance, a Corpus can store testcases on disk, or in memory, or implement a cache to speedup on disk storage.
Usually, a testcase is added to the Corpus when it is considered as interesting.
## Mutator
The Mutator is an entity that takes one or more Inputs and generates a new derived one.
Mutators can be composed and they are generally linked to a specific Input type.
There can be, for instance, a Mutator that applies more than a single type of mutation on the input. Consider a generic Mutator for a byte stream, bit flip is just one of the possible mutations but not the only one, there is also, for instance, the random replacement of a byte of the copy of a chunk.
This Mutator will simple schedule the application of some other Mutators.
## Generator
A Generator is a component designed to generate an Input from scratch.
Typically, a random generator is used to generate random inputs.
Generators are traditionally less used in Feedback-driven Fuzzing, but there are exceptions, like Nautilus, that uses a Grammar generator to create the initial corpus and a sub-tree Generator as a mutation of its grammar Mutator.
## Stage
A Stage is an entity that operates on a single Input got from the Corpus.
For instance, a Mutational Stage, given an input of the corpus, applies a Mutator and executes the generated input one or more time. How many times this has to be done can be scheduled, AFL for instance uses a performance score of the input to choose how many times the havoc mutator should be invoked. This can depend also on other parameters, for instance, the length of the input if we want to just apply a sequential bitflip, or be a fixed value.
A stage can also be an analysis stage, for instance, the Colorization stage of Redqueen that aims to introduce more entropy in a testcase or the Trimming stage of AFL that aims to reduce the size of a testcase.

View File

@ -1,3 +1,3 @@
# Design # Design
In this chapter, we introduce the abstract Core Concepts behind LibAFL, we then discuss how we designed the library to take into account these concepts while allowing code reuse and extensibility. In this chapter, we discuss how we designed the library taking into account the core concepts while allowing code reuse and extensibility.

View File

@ -0,0 +1,44 @@
# Metadata
A metadata in LibAFL is a self-contained structure that holds associated data to the State or to a Testcase.
In terms of code, a metadata can be defined as a Rust struct registered in the SerdeAny register.
```rust
extern crate libafl;
extern crate serde;
use libafl::SerdeAny;
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize, SerdeAny)]
pub struct MyMetadata {
//...
}
```
The struct must be static, so it cannot hold references to borrowed objects.
As an alternative to `derive(SerdeAny)` that is a proc-macro in `libafl_derive` the user can use `libafl::impl_serdeany!(MyMetadata);`.
## Usage
Metadata objects are primarly intended to be used inside [`SerdeAnyMap`](https://docs.rs/libafl/0.5.0/libafl/bolts/serdeany/serdeany_registry/struct.SerdeAnyMap.html) and [`NamedSerdeAnyMap`](https://docs.rs/libafl/0.5.0/libafl/bolts/serdeany/serdeany_registry/struct.NamedSerdeAnyMap.html).
With these maps, the user can retrieve instances by type (and name). Internally, the instances are stored as SerdeAny trait objects.
Structs that want to have a set of metadata must implement the [`HasMetadata`](https://docs.rs/libafl/0.5.0/libafl/state/trait.HasMetadata.html) trait.
By default, Testcase and State implement it and hold a SerdeAnyMap testcase.
## (De)Serialization
We are interested to store State's Metadata to not lose them in case of crash or stop of a fuzzer. To do that, they must be serialized and unserialized using Serde.
As Metadata is stored in a SerdeAnyMap as trait objects, they cannot be deserialized using Serde by default.
To cope with this problem, in LibAFL each SerdeAny struct must be registered in a global registry that keeps track of types and allows the (de)serialization of the registered types.
Normally, the `impl_serdeany` macro does that for the user creating a constructor function that fills the registry. However, when using LibAFL in no_std mode, this operation must be carried out manually before any other operation in the `main` function.
To do that, the developer needs to know each metadata type that is used inside the fuzzer and call `RegistryBuilder::register::<MyMetadata>()` for each of them at the beginning of `main`.

View File

@ -0,0 +1,162 @@
# Migrating from LibAFL <0.9 to 0.9
Internal APIs of LibAFL have changed in version 0.9 to prefer associated types in cases where components were "fixed" to
particular versions of other components. As a result, many existing custom components will not be compatible between
versions prior to 0.9 and version 0.9.
## Reasons for this change
When implementing a trait with a generic, it is possible to have more than one instantiation of that generic trait. As a
result, everywhere where consistency across generic types was required to implement a trait, it needed to be properly
and explicitly constrained at every point. This led to `impl`s which were at best difficult to debug and, at worst,
incorrect and caused confusing bugs for users.
For example, consider the `MapCorpusMinimizer` implementation (from <0.9) below:
```rust,ignore
impl<E, I, O, S, TS> CorpusMinimizer<I, S> for MapCorpusMinimizer<E, I, O, S, TS>
where
E: Copy + Hash + Eq,
I: Input,
for<'a> O: MapObserver<Entry = E> + AsIter<'a, Item = E>,
S: HasMetadata + HasCorpus<I>,
TS: TestcaseScore<I, S>,
{
fn minimize<CS, EX, EM, OT, Z>(
&self,
fuzzer: &mut Z,
executor: &mut EX,
manager: &mut EM,
state: &mut S,
) -> Result<(), Error>
where
CS: Scheduler<I, S>,
EX: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
EM: EventManager<EX, I, S, Z>,
OT: ObserversTuple<S>,
Z: Evaluator<EX, EM, I, S> + HasScheduler<CS, I, S>,
{
// --- SNIP ---
}
}
```
It was previously necessary to constrain every generic using a slew of other generics; above, it is necessary to
constrain the input type (`I`) for every generic, despite the fact that this was already made clear by the state (`S`)
and that the input will necessarily be the same over every implementation for that type.
Below is the same code, but with the associated types changes (note that some generic names have changed):
```rust,ignore
impl<E, O, T, TS> CorpusMinimizer<E> for MapCorpusMinimizer<E, O, T, TS>
where
E: UsesState,
for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>,
E::State: HasMetadata + HasCorpus,
T: Copy + Hash + Eq,
TS: TestcaseScore<E::State>,
{
fn minimize<CS, EM, Z>(
&self,
fuzzer: &mut Z,
executor: &mut E,
manager: &mut EM,
state: &mut E::State,
) -> Result<(), Error>
where
E: Executor<EM, Z> + HasObservers,
CS: Scheduler<State=E::State>,
EM: UsesState<State=E::State>,
Z: HasScheduler<CS, State=E::State>,
{
// --- SNIP ---
}
}
```
The executor is constrained to `EM` and `Z`, with each of their respective states being constrained to `E`'s state. It
is no longer necessary to explicitly defined a generic for the input type, the state type, or the generic type, as these
are all present as associated types for `E`. Additionally, we don't even need to specify any details about the observers
(`OT` in the previous version) as the type does not need to be constrained and is not shared by other types.
## Scope
You are affected by this change if:
- You specified explicit generics for a type (e.g., `MaxMapFeedback::<_, (), _>::new(...)`)
- You implemented a custom component (e.g., `Mutator`, `Executor`, `State`, `Fuzzer`, `Feedback`, `Observer`, etc.)
If you did neither of these, congrats! You are likely unaffected by these changes.
### Migrating explicit generics
Migrating specific generics should be a quite simple process; you should review the API documentation for details on the
order of generics and replace them accordingly. Generally speaking, it should no longer be necessary to specify these
generics.
See `fuzzers/` for examples of these changes.
### Migrating component types
If you implemented a Mutator, Executor, State, or another kind of component, you must update your implementation. The
main changes to the API are in the use of "Uses*" for associated types.
In many scenarios, Input, Observers, and State generics have been moved into traits with associated types (namely,
"UsesInput", "UsesObservers", and "UsesState". These traits are required for many existing traits now and are very
straightforward to implement. In a majority of cases, you will have generics on your custom implementation or a fixed
type to implement this with. Thankfully, Rust will let you know when you need to implement this type.
As an example, `InMemoryCorpus` before 0.9 looked like this:
```rust,ignore
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct InMemoryCorpus<I>
where
I: Input,
{
entries: Vec<RefCell<Testcase<I>>>,
current: Option<usize>,
}
impl<I> Corpus<I> for InMemoryCorpus<I>
where
I: Input,
{
// --- SNIP ---
}
```
After 0.9, all `Corpus` implementations are required to implement `UsesInput` and `Corpus` no longer has a generic for
the input type (as it is now provided by the UsesInput impl). The migrated implementation is shown below:
```rust,ignore
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct InMemoryCorpus<I>
where
I: Input,
{
entries: Vec<RefCell<Testcase<I>>>,
current: Option<usize>,
}
impl<I> UsesInput for InMemoryCorpus<I>
where
I: Input,
{
type Input = I;
}
impl<I> Corpus for InMemoryCorpus<I>
where
I: Input,
{
// --- SNIP ---
}
```
Now, `Corpus` cannot be accidentally implemented for another type other than that specified by `InMemoryCorpus`, as it
is fixed to the associated type for `UsesInput`.
A more complex example of migration can be found in the "Reasons for this change" section of this document.

View File

@ -1,4 +1,4 @@
# Build # Building LibAFL
LibAFL, as most of the Rust projects, can be built using `cargo` from the root directory of the project with: LibAFL, as most of the Rust projects, can be built using `cargo` from the root directory of the project with:
@ -10,16 +10,19 @@ Note that the `--release` flag is optional for development, but you needed to ad
Slowdowns of 10x or more are not uncommon for Debug builds. Slowdowns of 10x or more are not uncommon for Debug builds.
The LibAFL repository is composed of multiple crates. The LibAFL repository is composed of multiple crates.
The top-level Cargo.toml is the workspace file grouping these crates. The [top-level `Cargo.toml`](https://github.com/AFLplusplus/LibAFL/blob/main/Cargo.toml) is the workspace file grouping these crates.
Calling `cargo build` from the root directory will compile all crates in the workspace. Calling `cargo build` from the root directory will compile all crates in the workspace.
## Build Example Fuzzers ## Build Example Fuzzers
We group example fuzzers in the `./fuzzers` directory of the LibAFL repository. The best starting point for experienced rustaceans is to read through, and adapt, the example fuzzers.
We group these fuzzers in the [`./fuzzers`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers) directory of the LibAFL repository.
The directory contains a set of crates that are not part of the workspace. The directory contains a set of crates that are not part of the workspace.
Each of these example fuzzers uses particular features of LibAFL, sometimes combined with different instrumentation backends (e.g. [SanitizerCoverage](https://clang.llvm.org/docs/SanitizerCoverage.html), [Frida](https://frida.re/), ...). Each of these example fuzzers uses particular features of LibAFL, sometimes combined with different instrumentation backends (e.g. [SanitizerCoverage](https://clang.llvm.org/docs/SanitizerCoverage.html), [Frida](https://frida.re/), ...).
You can use these crates as examples and as skeletons for custom fuzzers with similar feature sets. You can use these crates as examples and as skeletons for custom fuzzers with similar feature sets.
Each fuzzer will have a `README.md` file in its directory, describing the fuzzer and its features.
To build an example fuzzer you have to invoke cargo from its respective folder (`fuzzers/[FUZZER_NAME]`). To build an example fuzzer, you have to invoke `cargo build --release` from its respective folder (`fuzzers/[FUZZER_NAME]`).

View File

@ -1,40 +1,88 @@
# Crates # Crates
LibAFL is composed by different crates. LibAFL is composed of different crates.
Each one has its self-contained purpose, and the user may not need to use all of them in its project. A crate is an individual library in Rust's Cargo build system, that you can use by adding it to your project's `Cargo.toml`, like:
```toml
[dependencies]
libafl = { version = "*" }
```
## Crate List
For LibAFL, each crate has its self-contained purpose, and the user may not need to use all of them in its project.
Following the naming convention of the folders in the project's root, they are: Following the naming convention of the folders in the project's root, they are:
### libafl ### [`libafl`](https://github.com/AFLplusplus/LibAFL/tree/main/libafl)
This is the main crate that contains all the components needed to build a fuzzer. This is the main crate that contains all the components needed to build a fuzzer.
This crate has the following feature flags: This crate has a number of feature flags that enable and disable certain aspects of LibAFL.
The features can be found in [LibAFL's `Cargo.toml`](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/Cargo.toml) under "`[features]`", and are usually explained with comments there.
Some features worthy of remark are:
- std, that enables the parts of the code that use the Rust standard library. Without this flag, libafl is no_std. - `std` enables the parts of the code that use the Rust standard library. Without this flag, LibAFL is `no_std` compatible. This disables a range of features, but allows us to use LibAFL in embedded environments, read [the `no_std` section](../advanced_features/no_std.md) for further details.
- derive, that enables the usage of the `derive(...)` macros defined in libafl_derive from libafl. - `derive` enables the usage of the `derive(...)` macros defined in libafl_derive from libafl.
- `rand_trait` allows you to use LibAFL's very fast (*but insecure!*) random number generator wherever compatibility with Rust's [`rand` crate](https://crates.io/crates/rand) is needed.
- `llmp_bind_public` makes LibAFL's LLMP bind to a public TCP port, over which other fuzzers nodes can communicate with this instance.
- `introspection` adds performance statistics to LibAFL.
By default, std and derive are both set. You can choose the features by using `features = ["feature1", "feature2", ...]` for LibAFL in your `Cargo.toml`.
Out of this list, by default, `std`, `derive`, and `rand_trait` are already set.
You can choose to disable them by setting `default-features = false` in your `Cargo.toml`.
### libafl_sugar
The sugar crate abstracts away most of the complexity of LibAFL's API.
Instead of high flexibility, it aims to be high-level and easy-to-use.
It is not as flexible as stitching your fuzzer together from each individual component, but allows you to build a fuzzer with minimal lines of code.
To see it in action, take a look at the [`libfuzzer_stb_image_sugar` example fuzzer](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/libfuzzer_stb_image_sugar).
### libafl_derive ### libafl_derive
This a proc-macro crate paired with the libafl crate. This a proc-macro crate paired with the `libafl` crate.
At the moment, it just expose the `derive(SerdeAny)` macro that can be used to define metadata structs. At the moment, it just exposes the `derive(SerdeAny)` macro that can be used to define Metadata structs, see the section about [Metadata](../design/metadata.md) for details.
### libafl_targets ### libafl_targets
This crate that exposes, under feature flags, pieces of code to interact with targets This crate exposes code to interact with, and to instrument, targets.
To enable and disable features at compile-time, the features are enabled and disabled using feature flags.
Currently, the supported flags are: Currently, the supported flags are:
- pcguard_edges, that defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges in a map. - `pcguard_edges` defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges in a map.
- pcguard_hitcounts, that defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges with the hitcounts (like AFL) in a map. - `pcguard_hitcounts defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges with the hitcounts (like AFL) in a map.
- libfuzzer, that expose a compatibility layer with libFuzzer style harnesses. - `libfuzzer` exposes a compatibility layer with libFuzzer style harnesses.
- value_profile, that defines the SanitizerCoverage trace-cmp hooks to track the matching bits of each comparison in a map. - `value_profile` defines the SanitizerCoverage trace-cmp hooks to track the matching bits of each comparison in a map.
### libafl_cc ### libafl_cc
This is a library that provides some utils to wrap compilers and create source level fuzzers. This is a library that provides utils wrap compilers and create source-level fuzzers.
At the moment, only the Clang compiler is supported. At the moment, only the Clang compiler is supported.
To understand it deeper, look through the tutorials and examples.
### libafl_frida
This library bridges LibAFL with Frida as instrumentation backend.
With this crate, you can instrument targets on Linux/macOS/Windows/Android for coverage collection.
Additionally, it supports CmpLog, and AddressSanitizer instrumentation and runtimes for aarch64.
See further information, as well as usage instructions, [later in the book](../advanced_features/frida.md).
### libafl_qemu
This library bridges LibAFL with QEMU user-mode to fuzz ELF cross-platform binaries.
It works on Linux and can collect edge coverage without collisions!
It also supports a wide range of hooks and instrumentation options.
### libafl_nyx
[Nyx](https://nyx-fuzz.com/) is a KVM-based snapshot fuzzer. `libafl_nyx` adds these capabilities to LibAFL. There is a specific section explaining usage of libafl_nyx [later in the book](../advanced_features/nyx.md).
### libafl_concolic
Concolic fuzzing is the combination of fuzzing and a symbolic execution engine.
This can reach greater depth than normal fuzzing, and is exposed in this crate.
There is a specific section explaining usage of libafl_concolic [later in the book](../advanced_features/concolic.md).

View File

@ -1,4 +1,5 @@
# Getting Started # Getting Started
To start using LibAFL, there are some first steps to do. In this chapter, we will To get started with LibAFL, there are some initial steps to take.
discuss how to download LibAFL and build with `cargo`, how are structured its crates and the purpose of each crate. In this chapter, we discuss how to download and build LibAFL, using Rust's `cargo` command.
We also describe the structure of LibAFL's components, so-called crates, and the purpose of each individual crate.

View File

@ -1,26 +1,28 @@
# Setup # Setup
The first step is to download LibAFL and all its dependencies that are not automatically installed with `cargo`. The first step is to download LibAFL and all dependencies that are not automatically installed with `cargo`.
> ### Command Line Notation > ### Command Line Notation
> >
> In this chapter and throughout the book, well show some commands used in the > In this chapter and throughout the book, we show some commands used in the
> terminal. Lines that you should enter in a terminal all start with `$`. You > terminal. Lines that you should enter in a terminal all start with `$`. You
> dont need to type in the `$` character; it indicates the start of each > dont need to type in the `$` character; it indicates the start of each
> command. Lines that dont start with `$` typically show the output of the > command. Lines that dont start with `$` typically show the output of the
> previous command. Additionally, PowerShell-specific examples will use `>` > previous command. Additionally, PowerShell-specific examples will use `>`
> rather than `$`. > rather than `$`.
The easiest way to download LibAFL is using `git`. While you technically do not need to install LibAFL, but can use the version from crates.io directly, we do recommend to download or clone the GitHub version.
This gets you the example fuzzers, additional utilities, and latest patches.
The easiest way to do this is to use `git`.
```sh ```sh
$ git clone git@github.com:AFLplusplus/LibAFL.git $ git clone git@github.com:AFLplusplus/LibAFL.git
``` ```
You can alternatively, on a UNIX-like machine, download a compressed archive and extract with: You can alternatively, on a UNIX-like machine, download a compressed archive and extract it with:
```sh ```sh
$ wget https://github.com/AFLplusplus/LibAFL/archive/main.tar.gz wget https://github.com/AFLplusplus/LibAFL/archive/main.tar.gz
$ tar xvf LibAFL-main.tar.gz $ tar xvf LibAFL-main.tar.gz
$ rm LibAFL-main.tar.gz $ rm LibAFL-main.tar.gz
$ ls LibAFL-main # this is the extracted folder $ ls LibAFL-main # this is the extracted folder
@ -29,30 +31,29 @@ $ ls LibAFL-main # this is the extracted folder
## Clang installation ## Clang installation
One of the external dependencies of LibAFL is the Clang C/C++ compiler. One of the external dependencies of LibAFL is the Clang C/C++ compiler.
While most of the code is in pure Rust, we still need a C compiler because Rust stable While most of the code is in pure Rust, we still need a C compiler because stable Rust still does not support features that some parts of LibAFL may need, such as weak linking, and LLVM builtins linking.
still does not support features that we need such as weak linking and LLVM builtins linking, For these parts, we use C to expose the missing functionalities to our Rust codebase.
and so we use C to expose the missing functionalities to our Rust codebase.
In addition, if you want to perform source-level fuzz testing of C/C++ applications, In addition, if you want to perform source-level fuzz testing of C/C++ applications,
you will likely need Clang with its instrumentation options to compile the programs you will likely need Clang with its instrumentation options to compile the programs
under test. under test.
On Linux you can use your distro's package manager to get Clang, On Linux you could use your distribution's package manager to get Clang,
but these packages are not always updated, so we suggest you to use the but these packages are not always up-to-date.
Debian/Ubuntu prebuilt packages from LLVM that are available using their [official repository](https://apt.llvm.org/). Instead, we suggest using the Debian/Ubuntu prebuilt packages from LLVM that are available using their [official repository](https://apt.llvm.org/).
For Microsoft Windows, you can download the [installer package](https://llvm.org/builds/) that LLVM generates periodically. For Microsoft Windows, you can download the [installer package](https://llvm.org/builds/) that LLVM generates periodically.
Despite that Clang is the default C compiler on macOS, we discourage the use of the build shipped by Apple and encourage Despite Clang being the default C compiler on MacOS, we discourage the use of the build shipped by Apple and encourage
the installation from `brew` or directly a fresh build from the source code. the installation from [Homebrew](https://brew.sh/), using `brew install llvm`.
Alternatively you can download and build the LLVM source tree - Clang included - following the steps Alternatively, you can download and build the LLVM source tree - Clang included - following the steps
explained [here](https://clang.llvm.org/get_started.html). explained [here](https://clang.llvm.org/get_started.html).
## Rust installation ## Rust installation
If you don't have Rust installed, you can easily follow the steps described [here](https://www.rust-lang.org/tools/install) If you do not have Rust installed, you can easily follow the steps described [here](https://www.rust-lang.org/tools/install)
to install it on any supported system. to install it on any supported system.
Be aware that Rust versions shipped with Linux distributions may be outdated, LibAFL always targets the latest `stable` version available via `rustup upgrade`.
We suggest to install Clang and LLVM first. We suggest installing Clang and LLVM first.

View File

@ -1,29 +1,34 @@
# Introduction # Introduction
Fuzzers are important assets in the pockets of security researchers and developers alike. Fuzzers are important tools for security researchers and developers alike.
A wide range of cool state-of-the-art tools like [AFL++](https://github.com/AFLplusplus/AFLplusplus), [libFuzzer](https://llvm.org/docs/LibFuzzer.html) or [honggfuzz](https://github.com/google/honggfuzz) are available to users. They do their job in a very effective way, finding thousands of bugs. A wide range of state-of-the-art tools like [AFL++](https://github.com/AFLplusplus/AFLplusplus), [libFuzzer](https://llvm.org/docs/LibFuzzer.html) or [honggfuzz](https://github.com/google/honggfuzz) are available to users. They do their job in a very effective way, finding thousands of bugs.
From the power user perspective, however, these tools are limited. From the perspective of a power user, however, these tools are limited.
Their design does not treat extensibility as a first-class citizen. Their design does not treat extensibility as a first-class citizen.
Usually, a fuzzer developer can choose to either fork one of these existing tools, or to create a new fuzzer from scratch. Usually, a fuzzer developer can choose to either fork one of these existing tools, or to create a new fuzzer from scratch.
In any case, researchers end up with tons of fuzzers, all of which are incompatible with each other. In any case, researchers end up with tons of fuzzers, all of which are incompatible with each other.
Their outstanding features can not just be combined for new projects. Their outstanding features can not just be combined for new projects.
Instead, we keep reinventing the wheel and may completely miss out on features that are complex to reimplement. By reinventing the wheel over and over, we may completely miss out on features that are complex to reimplement.
Here comes LibAFL, a library that IS NOT a fuzzer, but a collection of reusable pieces of fuzzers, written in Rust. To tackle this issue, we created LibAFL, a library that is _not just another fuzzer_, but a collection of reusable pieces for individual fuzzers.
LibAFL helps you develop your own custom fuzzer, tailored for your specific needs. LibAFL, written in Rust, helps you develop a fuzzer tailored for your specific needs.
Be it a specific target, a particular instrumentation backend, or a custom mutator, you can leverage existing bits and pieces to craft the fastest and most efficient fuzzer you can envision. Be it a specific target, a particular instrumentation backend, or a custom mutator, you can leverage existing bits and pieces to craft the fastest and most efficient fuzzer you can envision.
## Why LibAFL? ## Why LibAFL?
LibAFL gives you many of the benefits of an off-the-shelf fuzzer, while being completely customizable. LibAFL gives you many of the benefits of an off-the-shelf fuzzer, while being completely customizable.
Some highlight features currently include: Some highlight features currently include:
- `multi platform`: LibAFL works pretty much anywhere you can find a Rust compiler for. We already used it on *Windows*, *Android*, *MacOS*, and *Linux*, on *x86_64*, *aarch64*, ... - `multi platform`: LibAFL works pretty much anywhere you can find a Rust compiler for. We already used it on *Windows*, *Android*, *MacOS*, and *Linux*, on *x86_64*, *aarch64*, ...
- `portable`: `LibAFL` can be built in `no_std` mode. This means it does not require a specific OS-dependent runtime to function. Define an allocator and a way to map pages, you should be good to inject LibAFL in obscure targets like embedded devices, hypervisors, or maybe even WebAssembly? - `portable`: `LibAFL` can be built in `no_std` mode.
- `adaptable`: Given year of experience fine-tuning *AFLplusplus* and our academic fuzzing background, we could incorporate recent fuzzing trends into LibAFL's deign and make it future-proof. This means it does not require a specific OS-dependent runtime to function.
Define an allocator and a way to map pages, and you are good to inject LibAFL in obscure targets like embedded devices, hypervisors, or maybe even WebAssembly?
- `adaptable`: Given years of experience fine-tuning *AFLplusplus* and our academic fuzzing background, we could incorporate recent fuzzing trends into LibAFL's design and make it future-proof.
To give an example, as opposed to old-skool fuzzers, a `BytesInput` is just one of the potential forms of inputs: To give an example, as opposed to old-skool fuzzers, a `BytesInput` is just one of the potential forms of inputs:
feel free to use and mutate an Abstract Syntax Tree instead, for structured fuzzing. feel free to use and mutate an Abstract Syntax Tree instead, for structured fuzzing.
- `scalable`: As part of LibAFL, we developed `Low Level Message Passing`, `LLMP` for short, which allows LibAFL to scale almost linearly over cores. That is, if you chose to use this feature - it is your fuzzer, after all. Scaling to multiple machines over TCP is on the near road-map. - `scalable`: As part of LibAFL, we developed `Low Level Message Passing`, `LLMP` for short, which allows LibAFL to scale almost linearly over cores. That is, if you chose to use this feature - it is your fuzzer, after all.
- `fast`: We do everything we can at compiletime so that the runtime overhead is as minimal as it can get. Scaling to multiple machines over TCP is also possible, using LLMP's `broker2broker` feature.
- `bring your own target`: We support binary-only modes, like Frida-Mode with ASAN and CmpLog, as well as multiple compilation passes for sourced-based instrumentation, and of course support custom instrumentation. - `fast`: We do everything we can at compile time so that the runtime overhead is as minimal as it can get.
- `usable`: This one is on you to decide. Dig right in! - `bring your own target`: We support binary-only modes, like QEMU-Mode and Frida-Mode with ASAN and CmpLog, as well as multiple compilation passes for sourced-based instrumentation.
Of course, we also support custom instrumentation, as you can see in the Python example based on Google's Atheris.
- `usable`: This one is on you to decide. Dig right in!

View File

@ -1,9 +1,15 @@
# The LibAFL Fuzzing Library # The LibAFL Fuzzing Library
<img align="right" src="https://github.com/AFLplusplus/Website/raw/master/static/logo_256x256.png" alt="AFL++ Logo">
*by Andrea Fioraldi and Dominik Maier* *by Andrea Fioraldi and Dominik Maier*
Welcome to LibAFL, the Advanced Fuzzing Library.
This book shall be a gentle introduction into the library.
This version of the LibAFL book is coupled with the release 1.0 beta of the library. This version of the LibAFL book is coupled with the release 1.0 beta of the library.
This document is still work-in-progress and incomplete. The structure and the concepts explained here are subject to change in future revisions, as the structure of LibAFL itself will evolve. This document is still work-in-progress and incomplete. The structure and the concepts explained here are subject to change in future revisions, as the structure of LibAFL itself will evolve.
The HTML version of this book is available online at [https://aflplus.plus/libafl-book/](https://aflplus.plus/libafl-book/) and offline from the LibAFL repository in the docs/ folder. The HTML version of this book is available online at [https://aflplus.plus/libafl-book/](https://aflplus.plus/libafl-book/) and offline from the LibAFL repository in the `docs/` folder.
Build it using `mdbook build` in this folder, or run `mdbook serve` to view the book.

View File

@ -1,3 +0,0 @@
# (De)Serialization
TODO describe the SerdeAny registry

View File

@ -1,19 +0,0 @@
# Definition
A metadata in LibAFL is a self contained structure that holds associated data to the State or to a Testcase.
In terms of code, a metadata can be defined as a Rust struct registered in the SerdeAny register.
```rust
use libafl::SerdeAny;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, SerdeAny)]
pub struct MyMetadata {
...
}
```
The struct must be static, so it cannot hold references to borrowed objects.

View File

@ -1,3 +0,0 @@
# Understanding Metadata
In this chapter, we discuss in depth the metadata system of LibAFL and its usage.

View File

@ -1,3 +0,0 @@
# Usage
TODO describe the HasMetadata interface

View File

@ -0,0 +1,9 @@
# Configurations
Configurations for individual fuzzer nodes are relevant for multi node fuzzing.
The chapter describes how to run nodes with different configurations
in one fuzzing cluster.
This allows, for example, a node compiled with ASAN, to know that it needs to rerun new testcases for a node without ASAN, while the same binary/configuration does not.
Fuzzers with the same configuration can exchange Observers for new testcases and reuse them without rerunning the input.
A different configuration indicates, that only the raw input can be exchanged, it must be rerun on the other node to capture relevant observations.

View File

@ -0,0 +1,93 @@
# Message Passing
LibAFL offers a standard mechanism for message passing over processes and machines with a low overhead.
We use message passing to inform the other connected clients/fuzzers/nodes about new testcases, metadata, and statistics about the current run.
Depending on individual needs, LibAFL can also write testcase contents to disk, while still using events to notify other fuzzers, using an `OnDiskCorpus`.
In our tests, message passing scales very well to share new testcases and metadata between multiple running fuzzer instances for multi-core fuzzing.
Specifically, it scales _a lot_ better than using memory locks on a shared corpus, and _a lot_ better than sharing the testcases via the filesystem, as AFL traditionally does.
Think "all cores are green" in `htop`, aka., no kernel interaction.
The `EventManager` interface is used to send Events over the wire using `Low Level Message Passing`, a custom message passing mechanism over shared memory or TCP.
## Low Level Message Passing (LLMP)
LibAFL comes with a reasonably lock-free message passing mechanism that scales well across cores and, using its *broker2broker* mechanism, even to connected machines via TCP.
Most example fuzzers use this mechanism, and it is the best `EventManager` if you want to fuzz on more than a single core.
In the following, we will describe the inner workings of `LLMP`.
`LLMP` has one `broker` process that can forward messages sent by any client process to all other clients.
The broker can also intercept and filter the messages it receives instead of forwarding them.
A common use-case for messages filtered by the broker are the status messages sent from each client to the broker directly.
The broker used this information to paint a simple UI, with up-to-date information about all clients, however the other clients don't need to receive this information.
### Speedy Local Messages via Shared Memory
Throughout LibAFL, we use a wrapper around different operating system's shared maps, called `ShMem`.
Shared maps, called shared memory for the sake of not colliding with Rust's `map()` functions, are the backbone of `LLMP`.
Each client, usually a fuzzer trying to share stats and new testcases, maps an outgoing `ShMem` map.
With very few exceptions, only this client writes to this map, therefore, we do not run in race conditions and can live without locks.
The broker reads from all client's `ShMem` maps.
It checks all incoming client maps periodically and then forwards new messages to its outgoing broadcast-`ShMem`, mapped by all connected clients.
To send new messages, a client places a new message at the end of their shared memory and then updates a static field to notify the broker.
Once the outgoing map is full, the sender allocates a new `ShMem` using the respective `ShMemProvider`.
It then sends the information needed to map the newly-allocated page in connected processes to the old page, using an end of page (`EOP`) message.
Once the receiver maps the new page, flags it as safe for unmapping from the sending process (to avoid race conditions if we have more than a single EOP in a short time), and then continues to read from the new `ShMem`.
The schema for client's maps to the broker is as follows:
```text
[client0] [client1] ... [clientN]
| | /
[client0_out] [client1_out] ... [clientN_out]
| / /
|________________/ /
|________________________________/
\|/
[broker]
```
The broker loops over all incoming maps, and checks for new messages.
On `std` builds, the broker will sleep a few milliseconds after a loop, since we do not need the messages to arrive instantly.
After the broker received a new message from clientN, (`clientN_out->current_id != last_message->message_id`) the broker copies the message content to its own broadcast shared memory.
The clients periodically, for example after finishing `n` mutations, check for new incoming messages by checking if (`current_broadcast_map->current_id != last_message->message_id`).
While the broker uses the same EOP mechanism to map new `ShMem`s for its outgoing map, it never unmaps old pages.
This additional memory overhead serves a good purpose: by keeping all broadcast pages around, we make sure that new clients can join in on a fuzzing campaign at a later point in time
They just need to re-read all broadcasted messages from start to finish.
So the outgoing messages flow like this over the outgoing broadcast `Shmem`:
```text
[broker]
|
[current_broadcast_shmem]
|
|___________________________________
|_________________ \
| \ \
| | |
\|/ \|/ \|/
[client0] [client1] ... [clientN]
```
To use `LLMP` in LibAFL, you usually want to use an `LlmpEventManager` or its restarting variant.
They are the default if using LibAFL's `Launcher`.
If you should want to use `LLMP` in its raw form, without any `LibAFL` abstractions, take a look at the `llmp_test` example in [./libafl/examples](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/examples/llmp_test/main.rs).
You can run the example using `cargo run --example llmp_test` with the appropriate modes, as indicated by its help output.
First, you will have to create a broker using `LlmpBroker::new()`.
Then, create some `LlmpClient``s` in other threads and register them with the main thread using `LlmpBroker::register_client`.
Finally, call `LlmpBroker::loop_forever()`.
### B2B: Connecting Fuzzers via TCP
For `broker2broker` communication, all broadcast messages are additionally forwarded via network sockets.
To facilitate this, we spawn an additional client thread in the broker, that reads the broadcast shared memory, just like any other client would.
For broker2broker communication, this b2b client listens for TCP connections from other, remote brokers.
It keeps a pool of open sockets to other, remote, b2b brokers around at any time.
When receiving a new message on the local broker shared memory, the b2b client will forward it to all connected remote brokers via TCP.
Additionally, the broker can receive messages from all connected (remote) brokers, and forward them to the local broker over a client `ShMem`.
As a sidenote, the tcp listener used for b2b communication is also used for an initial handshake when a new client tries to connect to a broker locally, simply exchanging the initial `ShMem` descriptions.

View File

@ -0,0 +1,59 @@
# Spawning Instances
Multiple fuzzer instances can be spawned using different ways.
## Manually, via a TCP port
The straightforward way to do Multi-Threading is to use the `LlmpRestartingEventManager`, specifically to use `setup_restarting_mgr_std`.
It abstracts away all the pesky details about restarts on crash handling (for in-memory fuzzers) and multi-threading.
With it, every instance you launch manually tries to connect to a TCP port on the local machine.
If the port is not yet bound, this instance becomes the broker, itself binding to the port to await new clients.
If the port is already bound, the EventManager will try to connect to it.
The instance becomes a client and can now communicate with all other nodes.
Launching nodes manually has the benefit that you can have multiple nodes with different configurations, such as clients fuzzing with and without ASAN.
While it's called "restarting" manager, it uses `fork` on Unix operating systems as optimization and only actually restarts from scratch on Windows.
## Automated, with Launcher
The Launcher is the lazy way to do multiprocessing.
You can use the Launcher builder to create a fuzzer that spawns multiple nodes with one click, all using restarting event managers and the same configuration.
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()`:
```rust,ignore
Launcher::builder()
.configuration(EventConfig::from_name(&configuration))
.shmem_provider(shmem_provider)
.monitor(mon)
.run_client(&mut run_client)
.cores(cores)
.broker_port(broker_port)
.stdout_file(stdout_file)
.remote_broker_addr(broker_addr)
.build()
.launch()
```
This first starts a broker, then spawns `n` clients, according to the value passed to `cores`.
The value is a string indicating the cores to bind to, for example, `0,2,5` or `0-3`.
For each client, `run_client` will be called.
On Windows, the Launcher will restart each client, while on Unix, it will use `fork`.
Advanced use-cases:
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/`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers).
## Other ways
The `LlmpEventManager` family is the easiest way to spawn instances, but for obscure targets, you may need to come up with other solutions.
LLMP is even, in theory, `no_std` compatible, and even completely different EventManagers can be used for message passing.
If you are in this situation, please either read through the current implementations and/or reach out to us.

View File

@ -0,0 +1,8 @@
# Introduction
> ## Under Construction!
>
> This section is under construction.
> Please check back later (or open a PR)
>
> In the meantime, find the final Lain-based fuzzer in [the fuzzers folder](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers/tutorial)

View File

@ -0,0 +1,5 @@
# Tutorial
In this chapter, we will build a custom fuzzer using the [Lain](https://github.com/microsoft/lain) mutator in Rust.
This tutorial will introduce you in writing extensions to LibAFL like Feedbacks and Testcase's metadata.

4
fuzzers/FRET/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.qcow2
corpus
*.axf
demo

41
fuzzers/FRET/Cargo.toml Normal file
View File

@ -0,0 +1,41 @@
[package]
name = "fret"
version = "0.8.2"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2021"
[features]
default = ["std", "snapshot_restore", "singlecore", "restarting", "feed_systemtrace", "fuzz_int" ]
std = []
snapshot_restore = []
snapshot_fast = [ "snapshot_restore" ]
singlecore = []
restarting = ['singlecore']
trace_abbs = []
systemstate = []
feed_systemgraph = [ "systemstate" ]
feed_systemtrace = [ "systemstate" ]
feed_longest = [ ]
feed_afl = [ ]
feed_genetic = [ ]
fuzz_int = [ ]
gensize_1 = [ ]
gensize_10 = [ ]
gensize_100 = [ ]
observer_hitcounts = []
no_hash_state = []
run_until_saturation = []
[profile.release]
lto = true
codegen-units = 1
debug = true
[dependencies]
libafl = { path = "../../libafl/" }
libafl_qemu = { path = "../../libafl_qemu/", features = ["arm", "systemmode"] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
hashbrown = { version = "0.12", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
petgraph = { version="0.6.0", features = ["serde-1"] }
ron = "0.7" # write serialized data - including hashmaps
rand = "0.5"

26
fuzzers/FRET/README.md Normal file
View File

@ -0,0 +1,26 @@
# Qemu systemmode with launcher
This folder contains an example fuzzer for the qemu systemmode, using LLMP for fast multi-process fuzzing and crash detection.
## Build
To build this example, run
```bash
cargo build --release
cd example; sh build.sh; cd ..
```
This will build the the fuzzer (src/fuzzer.rs) and a small example binary based on FreeRTOS, which can run under a qemu emulation target.
## Run
Since the instrumentation is based on snapshtos QEMU needs a virtual drive (even if it is unused...).
Create on and then run the fuzzer:
```bash
# create an image
qemu-img create -f qcow2 dummy.qcow2 32M
# run the fuzzer
KERNEL=./example/example.elf target/release/qemu_systemmode -icount shift=auto,align=off,sleep=off -machine mps2-an385 -monitor null -kernel ./example/example.elf -serial null -nographic -snapshot -drive if=none,format=qcow2,file=dummy.qcow2 -S
```
Currently the ``KERNEL`` variable is needed because the fuzzer does not parse QEMUs arguments to find the binary.

12
fuzzers/FRET/benchmark/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
*dump
timedump*
corpora
build
mnt
.R*
*.png
*.pdf
bins
.snakemake
*.zip
*.tar.*

View File

@ -0,0 +1,57 @@
TIME=7200
corpora/%/seed:
mkdir -p $$(dirname $@)
LINE=$$(grep "^$$(basename $*)" target_symbols.csv); \
export \
KERNEL=benchmark/build/$*.elf \
FUZZ_MAIN=$$(echo $$LINE | cut -d, -f2) \
FUZZ_INPUT=$$(echo $$LINE | cut -d, -f3) \
FUZZ_INPUT_LEN=$$(echo $$LINE | cut -d, -f4) \
BREAKPOINT=$$(echo $$LINE | cut -d, -f5) \
SEED_DIR=benchmark/corpora/$* \
DUMP_SEED=seed; \
../fuzzer.sh
timedump/%$(FUZZ_RANDOM)$(SUFFIX): corpora/%/seed
mkdir -p $$(dirname $@)
LINE=$$(grep "^$$(basename $*)" target_symbols.csv); \
export \
KERNEL=benchmark/build/$*.elf \
FUZZ_MAIN=$$(echo $$LINE | cut -d, -f2) \
FUZZ_INPUT=$$(echo $$LINE | cut -d, -f3) \
FUZZ_INPUT_LEN=$$(echo $$LINE | cut -d, -f4) \
BREAKPOINT=$$(echo $$LINE | cut -d, -f5) \
SEED_RANDOM=1 \
TIME_DUMP=benchmark/$@ \
CASE_DUMP=benchmark/$@; \
../fuzzer.sh + + + + + $(TIME) + + + > $@_log
#SEED_DIR=benchmark/corpora/$*
all_sequential: timedump/sequential/mpeg2$(FUZZ_RANDOM) timedump/sequential/dijkstra$(FUZZ_RANDOM) timedump/sequential/epic$(FUZZ_RANDOM) \
timedump/sequential/g723_enc$(FUZZ_RANDOM) timedump/sequential/audiobeam$(FUZZ_RANDOM) \
timedump/sequential/gsm_enc$(FUZZ_RANDOM)
all_kernel: timedump/kernel/bsort$(FUZZ_RANDOM) timedump/kernel/insertsort$(FUZZ_RANDOM) #timedump/kernel/fft$(FUZZ_RANDOM)
all_app: timedump/app/lift$(FUZZ_RANDOM)
all_system: timedump/lift$(FUZZ_RANDOM)$(SUFFIX)
all_period: timedump/waters$(FUZZ_RANDOM)$(SUFFIX)
tacle_rtos: timedump/tacle_rtos$(FUZZ_RANDOM)
graphics:
Rscript --vanilla plot_comparison.r mnt/timedump/sequential audiobeam
Rscript --vanilla plot_comparison.r mnt/timedump/sequential dijkstra
Rscript --vanilla plot_comparison.r mnt/timedump/sequential epic
Rscript --vanilla plot_comparison.r mnt/timedump/sequential g723_enc
# Rscript --vanilla plot_comparison.r mnt/timedump/sequential gsm_enc
# Rscript --vanilla plot_comparison.r mnt/timedump/sequential huff_dec
Rscript --vanilla plot_comparison.r mnt/timedump/sequential mpeg2
# Rscript --vanilla plot_comparison.r mnt/timedump/sequential rijndael_dec
# Rscript --vanilla plot_comparison.r mnt/timedump/sequential rijndael_enc
clean:
rm -rf corpora timedump

View File

@ -0,0 +1,281 @@
import csv
import os
def_flags="--no-default-features --features std,snapshot_restore,singlecore,restarting,run_until_saturation"
remote="timedump_253048_1873f6_all/"
RUNTIME=10
TARGET_REPS_A=2
TARGET_REPS_B=2
NUM_NODES=2
REP_PER_NODE_A=int(TARGET_REPS_A/NUM_NODES)
REP_PER_NODE_B=int(TARGET_REPS_B/NUM_NODES)
NODE_ID= 0 if os.getenv('NODE_ID') == None else int(os.environ['NODE_ID'])
MY_RANGE_A=range(NODE_ID*REP_PER_NODE_A,(NODE_ID+1)*REP_PER_NODE_A)
MY_RANGE_B=range(NODE_ID*REP_PER_NODE_B,(NODE_ID+1)*REP_PER_NODE_B)
rule build_showmap:
output:
directory("bins/target_showmap")
shell:
"cargo build --target-dir {output} {def_flags},systemstate"
rule build_random:
output:
directory("bins/target_random")
shell:
"cargo build --target-dir {output} {def_flags},feed_longest"
rule build_feedlongest:
output:
directory("bins/target_feedlongest")
shell:
"cargo build --target-dir {output} {def_flags},feed_longest"
rule build_frafl:
output:
directory("bins/target_frafl")
shell:
"cargo build --target-dir {output} {def_flags},feed_afl,feed_longest"
rule build_afl:
output:
directory("bins/target_afl")
shell:
"cargo build --target-dir {output} {def_flags},feed_afl,observer_hitcounts"
rule build_state:
output:
directory("bins/target_state")
shell:
"cargo build --target-dir {output} {def_flags},feed_systemtrace"
rule build_nohashstate:
output:
directory("bins/target_nohashstate")
shell:
"cargo build --target-dir {output} {def_flags},feed_systemtrace,no_hash_state"
rule build_graph:
output:
directory("bins/target_graph")
shell:
"cargo build --target-dir {output} {def_flags},feed_systemgraph"
rule build_showmap_int:
output:
directory("bins/target_showmap_int")
shell:
"cargo build --target-dir {output} {def_flags},systemstate,fuzz_int"
rule build_random_int:
output:
directory("bins/target_random_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_longest,fuzz_int"
rule build_state_int:
output:
directory("bins/target_state_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_systemtrace,fuzz_int"
rule build_nohashstate_int:
output:
directory("bins/target_nohashstate_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_systemtrace,fuzz_int,no_hash_state"
rule build_frafl_int:
output:
directory("bins/target_frafl_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_afl,feed_longest,fuzz_int"
rule build_afl_int:
output:
directory("bins/target_afl_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_afl,fuzz_int,observer_hitcounts"
rule build_feedlongest_int:
output:
directory("bins/target_feedlongest_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_longest,fuzz_int"
rule build_feedgeneration1:
output:
directory("bins/target_feedgeneration1")
shell:
"cargo build --target-dir {output} {def_flags},feed_genetic,gensize_1"
rule build_feedgeneration1_int:
output:
directory("bins/target_feedgeneration1_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_genetic,fuzz_int,gensize_1"
rule build_feedgeneration10:
output:
directory("bins/target_feedgeneration10")
shell:
"cargo build --target-dir {output} {def_flags},feed_genetic,gensize_10"
rule build_feedgeneration10_int:
output:
directory("bins/target_feedgeneration10_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_genetic,fuzz_int,gensize_10"
rule build_feedgeneration100:
output:
directory("bins/target_feedgeneration100")
shell:
"cargo build --target-dir {output} {def_flags},feed_genetic,gensize_100"
rule build_feedgeneration100_int:
output:
directory("bins/target_feedgeneration100_int")
shell:
"cargo build --target-dir {output} {def_flags},feed_genetic,fuzz_int,gensize_100"
rule run_bench:
input:
"build/{target}.elf",
"bins/target_{fuzzer}"
output:
multiext("timedump/{fuzzer}/{target}.{num}", "", ".log") # , ".case"
run:
with open('target_symbols.csv') as csvfile:
reader = csv.DictReader(csvfile)
line = next((x for x in reader if x['kernel']==wildcards.target), None)
if line == None:
return False
kernel=line['kernel']
fuzz_main=line['main_function']
fuzz_input=line['input_symbol']
fuzz_len=line['input_size']
bkp=line['return_function']
script="""
mkdir -p $(dirname {output[0]})
export KERNEL=$(pwd)/{input[0]}
export FUZZ_MAIN={fuzz_main}
export FUZZ_INPUT={fuzz_input}
export FUZZ_INPUT_LEN={fuzz_len}
export BREAKPOINT={bkp}
export SEED_RANDOM={wildcards.num}
export TIME_DUMP=$(pwd)/{output[0]}
export CASE_DUMP=$(pwd)/{output[0]}.case
export TRACE_DUMP=$(pwd)/{output[0]}.trace
export FUZZ_ITERS={RUNTIME}
export FUZZER=$(pwd)/{input[1]}/debug/fret
set +e
../fuzzer.sh > {output[1]} 2>&1
exit 0
"""
if wildcards.fuzzer.find('random') >= 0:
script="export FUZZ_RANDOM={output[1]}\n"+script
shell(script)
rule run_showmap:
input:
"{remote}build/{target}.elf",
"bins/target_showmap",
"bins/target_showmap_int",
"{remote}timedump/{fuzzer}/{target}.{num}.case"
output:
"{remote}timedump/{fuzzer}/{target}.{num}.trace.ron",
"{remote}timedump/{fuzzer}/{target}.{num}.case.time",
run:
with open('target_symbols.csv') as csvfile:
reader = csv.DictReader(csvfile)
line = next((x for x in reader if x['kernel']==wildcards.target), None)
if line == None:
return False
kernel=line['kernel']
fuzz_main=line['main_function']
fuzz_input=line['input_symbol']
fuzz_len=line['input_size']
bkp=line['return_function']
script=""
if wildcards.fuzzer.find('_int') > -1:
script="export FUZZER=$(pwd)/{input[2]}/debug/fret\n"
else:
script="export FUZZER=$(pwd)/{input[1]}/debug/fret\n"
script+="""
mkdir -p $(dirname {output})
export KERNEL=$(pwd)/{input[0]}
export FUZZ_MAIN={fuzz_main}
export FUZZ_INPUT={fuzz_input}
export FUZZ_INPUT_LEN={fuzz_len}
export BREAKPOINT={bkp}
export TRACE_DUMP=$(pwd)/{output[0]}
export DO_SHOWMAP=$(pwd)/{input[3]}
export TIME_DUMP=$(pwd)/{output[1]}
set +e
../fuzzer.sh
exit 0
"""
if wildcards.fuzzer.find('random') >= 0:
script="export FUZZ_RANDOM=1\n"+script
shell(script)
rule tarnsform_trace:
input:
"{remote}timedump/{fuzzer}/{target}.{num}.trace.ron"
output:
"{remote}timedump/{fuzzer}/{target}.{num}.trace.csv"
shell:
"$(pwd)/../../../../state2gantt/target/debug/state2gantt {input} > {output[0]}"
rule trace2gantt:
input:
"{remote}timedump/{fuzzer}/{target}.{num}.trace.csv"
output:
"{remote}timedump/{fuzzer}/{target}.{num}.trace.csv.png"
shell:
"Rscript --vanilla $(pwd)/../../../../state2gantt/gantt.R {input}"
rule all_main:
input:
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['random','afl','feedgeneration10','state'], target=['waters','watersv2'],num=range(0,3))
rule all_main_int:
input:
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['random_int','afl_int','feedgeneration10_int','state_int'], target=['waters_int','watersv2_int'],num=range(0,4))
rule all_compare_feedgeneration:
input:
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['feedgeneration1','feedgeneration10','feedgeneration100'], target=['waters_int','watersv2'],num=range(0,10))
rule all_compare_feedgeneration_int:
input:
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['feedgeneration1_int','feedgeneration10_int','feedgeneration100_int'], target=['waters_int','watersv2_int'],num=range(0,10))
rule all_compare_afl:
input:
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['afl','frafl','feedlongest'], target=['waters','watersv2'],num=range(0,10))
rule all_compare_afl_int:
input:
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['afl_int','frafl_int','feedlongest_int'], target=['waters_int','watersv2_int'],num=range(0,10))
rule all_images:
input:
expand("{remote}timedump/{fuzzer}/{target}.{num}.trace.csv.png",remote=remote, fuzzer=['afl','feedgeneration10','state'], target=['waters','watersv2'],num=range(0,3))
rule all_images_int:
input:
expand("{remote}timedump/{fuzzer}/{target}.{num}.trace.csv.png",remote=remote, fuzzer=['afl_int','feedgeneration10_int','state_int'], target=['waters_int','watersv2_int'],num=range(0,3))
rule clusterfuzz:
input:
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['random','afl','feedgeneration10','state'], target=['waters','watersv2'],num=MY_RANGE_A),
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['random_int','afl_int','feedgeneration10_int','state_int'], target=['waters_int','watersv2_int'],num=MY_RANGE_A),
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['feedgeneration1','feedgeneration10','feedgeneration100'], target=['waters_int','watersv2'],num=MY_RANGE_B),
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['feedgeneration1_int','feedgeneration10_int','feedgeneration100_int'], target=['waters_int','watersv2_int'],num=MY_RANGE_B),
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['afl','frafl','feedlongest'], target=['waters','watersv2'],num=MY_RANGE_B),
expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['afl_int','frafl_int','feedlongest_int'], target=['waters_int','watersv2_int'],num=MY_RANGE_B),
rule all_bins:
input:
expand("bins/target_{target}{flag}",target=['random','afl','frafl','state','feedgeneration100'],flag=['','_int'])

View File

@ -0,0 +1,83 @@
library("mosaic")
args = commandArgs(trailingOnly=TRUE)
#myolors=c("#339933","#0066ff","#993300") # grün, balu, rot
myolors=c("dark green","dark blue","dark red", "yellow") # grün, balu, rot
if (length(args)==0) {
runtype="timedump"
target="waters"
filename_1=sprintf("%s.png",target)
filename_2=sprintf("%s_maxline.png",target)
filename_3=sprintf("%s_hist.png",target)
} else {
runtype=args[1]
target=args[2]
filename_1=sprintf("%s.png",args[2])
filename_2=sprintf("%s_maxline.png",args[2])
filename_3=sprintf("%s_hist.png",args[2])
# filename_1=args[3]
}
file_1=sprintf("~/code/FRET/LibAFL/fuzzers/FRET/benchmark/%s/%s_state",runtype,target)
file_2=sprintf("~/code/FRET/LibAFL/fuzzers/FRET/benchmark/%s/%s_afl",runtype,target)
file_3=sprintf("~/code/FRET/LibAFL/fuzzers/FRET/benchmark/%s/%s_random",runtype,target)
file_4=sprintf("~/code/FRET/LibAFL/fuzzers/FRET/benchmark/%s/%s_graph",runtype,target)
timetrace <- read.table(file_1, quote="\"", comment.char="")
timetrace_afl <- read.table(file_2, quote="\"", comment.char="")
timetrace_rand <- read.table(file_3, quote="\"", comment.char="")
timetrace_graph <- read.table(file_4, quote="\"", comment.char="")
timetrace[[2]]=seq_len(length(timetrace[[1]]))
timetrace_afl[[2]]=seq_len(length(timetrace_afl[[1]]))
timetrace_rand[[2]]=seq_len(length(timetrace_rand[[1]]))
timetrace_graph[[2]]=seq_len(length(timetrace_graph[[1]]))
names(timetrace)[1] <- "timetrace"
names(timetrace)[2] <- "iter"
names(timetrace_afl)[1] <- "timetrace"
names(timetrace_afl)[2] <- "iter"
names(timetrace_rand)[1] <- "timetrace"
names(timetrace_rand)[2] <- "iter"
names(timetrace_graph)[1] <- "timetrace"
names(timetrace_graph)[2] <- "iter"
png(file=filename_1)
# pdf(file=filename_1,width=8, height=8)
plot(timetrace[[2]],timetrace[[1]], col=myolors[1], xlab="iters", ylab="wcet", pch='.')
points(timetrace_afl[[2]],timetrace_afl[[1]], col=myolors[2], pch='.')
points(timetrace_rand[[2]],timetrace_rand[[1]], col=myolors[3], pch='.')
points(timetrace_graph[[2]],timetrace_graph[[1]], col=myolors[4], pch='.')
abline(lm(timetrace ~ iter, data=timetrace),col=myolors[1])
abline(lm(timetrace ~ iter, data=timetrace_afl),col=myolors[2])
abline(lm(timetrace ~ iter, data=timetrace_rand),col=myolors[3])
dev.off()
png(file=filename_3)
gf_histogram(~ timetrace,data=timetrace, fill=myolors[1]) %>%
gf_histogram(~ timetrace,data=timetrace_afl, fill=myolors[2]) %>%
gf_histogram(~ timetrace,data=timetrace_rand, fill=myolors[3]) %>%
gf_histogram(~ timetrace,data=timetrace_graph, fill=myolors[4])
dev.off()
# Takes a flat list
trace2maxline <- function(tr) {
maxline = tr
for (var in seq_len(length(maxline))[2:length(maxline)]) {
maxline[var] = max(maxline[var],maxline[var-1])
}
#plot(seq_len(length(maxline)),maxline,"l",xlab="Index",ylab="WOET")
return(maxline)
}
timetrace[[1]] <- trace2maxline(timetrace[[1]])
timetrace_afl[[1]] <- trace2maxline(timetrace_afl[[1]])
timetrace_rand[[1]] <- trace2maxline(timetrace_rand[[1]])
timetrace_graph[[1]] <- trace2maxline(timetrace_graph[[1]])
png(file=filename_2)
plot(timetrace[[2]],timetrace[[1]], col=myolors[1], xlab="iters", ylab="wcet", pch='.')
points(timetrace_afl[[2]],timetrace_afl[[1]], col=myolors[2], pch='.')
points(timetrace_rand[[2]],timetrace_rand[[1]], col=myolors[3], pch='.')
points(timetrace_graph[[2]],timetrace_graph[[1]], col=myolors[4], pch='.')
#abline(lm(timetrace ~ iter, data=timetrace),col=myolors[1])
#abline(lm(timetrace ~ iter, data=timetrace_afl),col=myolors[2])
#abline(lm(timetrace ~ iter, data=timetrace_rand),col=myolors[3])
dev.off()

View File

@ -0,0 +1,327 @@
library("mosaic")
library("dplyr")
library("foreach")
library("doParallel")
#setup parallel backend to use many processors
cores=detectCores()
cl <- makeCluster(cores[1]-1) #not to overload your computer
registerDoParallel(cl)
args = commandArgs(trailingOnly=TRUE)
if (length(args)==0) {
runtype="timedump_253048_1873f6_all/timedump"
target="waters_int"
outputpath="~/code/FRET/LibAFL/fuzzers/FRET/benchmark/"
#MY_SELECTION <- c('state', 'afl', 'graph', 'random')
SAVE_FILE=TRUE
} else {
runtype=args[1]
target=args[2]
outputpath=args[3]
MY_SELECTION <- args[4:length(args)]
SAVE_FILE=TRUE
}
worst_cases <- list(waters=0, waters_int=0, tmr=405669, micro_longint=0)
worst_case <- worst_cases[[target]]
if (is.null(worst_case)) {
worst_case = 0
}
#MY_COLORS=c("green","blue","red", "orange", "pink", "black")
MY_COLORS <- c("green", "blue", "red", "magenta", "orange", "cyan", "pink", "gray", "orange", "black", "yellow","brown")
BENCHDIR=sprintf("~/code/FRET/LibAFL/fuzzers/FRET/benchmark/%s",runtype)
BASENAMES=Filter(function(x) x!="" && substr(x,1,1)!='.',list.dirs(BENCHDIR,full.names=FALSE))
PATTERNS="%s.[0-9]*$"
#RIBBON='sd'
#RIBBON='span'
RIBBON='both'
DRAW_WC = worst_case > 0
LEGEND_POS="topright"
#LEGEND_POS="bottomright"
CONTINUE_LINE_TO_END=FALSE
# https://www.r-bloggers.com/2013/04/how-to-change-the-alpha-value-of-colours-in-r/
alpha <- function(col, alpha=1){
if(missing(col))
stop("Please provide a vector of colours.")
apply(sapply(col, col2rgb)/255, 2,
function(x)
rgb(x[1], x[2], x[3], alpha=alpha))
}
# Trimm a list of data frames to common length
trim_data <- function(input,len=NULL) {
if (is.null(len)) {
len <- min(sapply(input, function(v) dim(v)[1]))
}
return(lapply(input, function(d) slice_head(d,n=len)))
}
length_of_data <- function(input) {
min(sapply(input, function(v) dim(v)[1]))
}
# Takes a flat list
trace2maxline <- function(tr) {
maxline = tr
for (var in seq_len(length(maxline))[2:length(maxline)]) {
#if (maxline[var]>1000000000) {
# maxline[var]=maxline[var-1]
#} else {
maxline[var] = max(maxline[var],maxline[var-1])
#}
}
#plot(seq_len(length(maxline)),maxline,"l",xlab="Index",ylab="WOET")
return(maxline)
}
# Take a list of data frames, output same form but maxlines
data2maxlines <- function(tr) {
min_length <- min(sapply(tr, function(v) dim(v)[1]))
maxline <- tr
for (var in seq_len(length(tr))) {
maxline[[var]][[1]]=trace2maxline(tr[[var]][[1]])
}
return(maxline)
}
# Take a multi-column data frame, output same form but maxlines
frame2maxlines <- function(tr) {
for (var in seq_len(length(tr))) {
tr[[var]]=trace2maxline(tr[[var]])
}
return(tr)
}
trace2maxpoints <- function(tr) {
minval = tr[1,1]
collect = tr[1,]
for (i in seq_len(dim(tr)[1])) {
if (minval < tr[i,1]) {
collect = rbind(collect,tr[i,])
minval = tr[i,1]
}
}
tmp = tr[dim(tr)[1],]
tmp[1] = minval[1]
collect = rbind(collect,tmp)
return(collect)
}
sample_maxpoints <- function(tr,po) {
index = 1
collect=NULL
endpoint = dim(tr)[1]
for (p in po) {
if (p<=tr[1,2]) {
tmp = tr[index,]
tmp[2] = p
collect = rbind(collect, tmp)
} else if (p>=tr[endpoint,2]) {
tmp = tr[endpoint,]
tmp[2] = p
collect = rbind(collect, tmp)
} else {
for (i in seq(index,endpoint)-1) {
if (p >= tr[i,2] && p<tr[i+1,2]) {
tmp = tr[i,]
tmp[2] = p
collect = rbind(collect, tmp)
index = i
break
}
}
}
}
return(collect)
}
#https://www.r-bloggers.com/2012/01/parallel-r-loops-for-windows-and-linux/
all_runtypetables <- foreach (bn=BASENAMES) %do% {
runtypefiles <- list.files(file.path(BENCHDIR,bn),pattern=sprintf(PATTERNS,target),full.names = TRUE)
if (length(runtypefiles) > 0) {
runtypetables_reduced <- foreach(i=seq_len(length(runtypefiles))) %dopar% {
rtable = read.csv(runtypefiles[[i]], col.names=c(sprintf("%s%d",bn,i),sprintf("times%d",i)))
trace2maxpoints(rtable)
}
#runtypetables <- lapply(seq_len(length(runtypefiles)),
# function(i)read.csv(runtypefiles[[i]], col.names=c(sprintf("%s%d",bn,i),sprintf("times%d",i))))
#runtypetables_reduced <- lapply(runtypetables, trace2maxpoints)
runtypetables_reduced
#all_runtypetables = c(all_runtypetables, list(runtypetables_reduced))
}
}
all_runtypetables = all_runtypetables[lapply(all_runtypetables, length) > 0]
all_min_points = foreach(rtt=all_runtypetables,.combine = cbind) %do% {
bn = substr(names(rtt[[1]])[1],1,nchar(names(rtt[[1]])[1])-1)
ret = data.frame(min(unlist(lapply(rtt, function(v) v[dim(v)[1],2]))))
names(ret)[1] = bn
ret/(3600 * 1000)
}
all_max_points = foreach(rtt=all_runtypetables,.combine = cbind) %do% {
bn = substr(names(rtt[[1]])[1],1,nchar(names(rtt[[1]])[1])-1)
ret = data.frame(max(unlist(lapply(rtt, function(v) v[dim(v)[1],2]))))
names(ret)[1] = bn
ret/(3600 * 1000)
}
all_points = sort(unique(Reduce(c, lapply(all_runtypetables, function(v) Reduce(c, lapply(v, function(w) w[[2]]))))))
all_maxlines <- foreach (rtt=all_runtypetables) %do% {
bn = substr(names(rtt[[1]])[1],1,nchar(names(rtt[[1]])[1])-1)
runtypetables_sampled = foreach(v=rtt) %dopar% {
sample_maxpoints(v, all_points)[1]
}
#runtypetables_sampled = lapply(rtt, function(v) sample_maxpoints(v, all_points)[1])
tmp_frame <- Reduce(cbind, runtypetables_sampled)
statframe <- data.frame(rowMeans(tmp_frame),apply(tmp_frame, 1, sd),apply(tmp_frame, 1, min),apply(tmp_frame, 1, max), apply(tmp_frame, 1, median))
names(statframe) <- c(bn, sprintf("%s_sd",bn), sprintf("%s_min",bn), sprintf("%s_max",bn), sprintf("%s_med",bn))
#statframe[sprintf("%s_times",bn)] = all_points
round(statframe)
#all_maxlines = c(all_maxlines, list(round(statframe)))
}
one_frame<-data.frame(all_maxlines)
one_frame[length(one_frame)+1] <- all_points/(3600 * 1000)
names(one_frame)[length(one_frame)] <- 'time'
typenames = names(one_frame)[which(names(one_frame) != 'time')]
typenames = typenames[which(!endsWith(typenames, "_sd"))]
typenames = typenames[which(!endsWith(typenames, "_med"))]
ylow=min(one_frame[typenames])
yhigh=max(one_frame[typenames],worst_case)
typenames = typenames[which(!endsWith(typenames, "_min"))]
typenames = typenames[which(!endsWith(typenames, "_max"))]
ml2lines <- function(ml,lim) {
lines = NULL
last = 0
for (i in seq_len(dim(ml)[1])) {
if (!CONTINUE_LINE_TO_END && lim<ml[i,2]) {
break
}
lines = rbind(lines, cbind(X=last, Y=ml[i,1]))
lines = rbind(lines, cbind(X=ml[i,2], Y=ml[i,1]))
last = ml[i,2]
}
return(lines)
}
plotting <- function(selection, filename, MY_COLORS_) {
# filter out names of iters and sd cols
typenames = names(one_frame)[which(names(one_frame) != 'times')]
typenames = typenames[which(!endsWith(typenames, "_sd"))]
typenames = typenames[which(!endsWith(typenames, "_med"))]
typenames = typenames[which(!endsWith(typenames, "_min"))]
typenames = typenames[which(!endsWith(typenames, "_max"))]
typenames = selection[which(selection %in% typenames)]
if (length(typenames) == 0) {return()}
h_ = 500
w_ = h_*4/3
if (SAVE_FILE) {png(file=sprintf("%s%s_%s.png",outputpath,target,filename), width=w_, height=h_)}
par(mar=c(4,4,1,1))
par(oma=c(0,0,0,0))
plot(c(1,max(one_frame['time'])),c(ylow,yhigh), col='white', xlab="Time [h]", ylab="WORT [insn]", pch='.')
for (t in seq_len(length(typenames))) {
#proj = one_frame[seq(1, dim(one_frame)[1], by=max(1, length(one_frame[[1]])/(10*w_))),]
#points(proj[c('iters',typenames[t])], col=MY_COLORS_[t], pch='.')
avglines = ml2lines(one_frame[c(typenames[t],'time')],all_max_points[typenames[t]])
#lines(avglines, col=MY_COLORS_[t])
medlines = ml2lines(one_frame[c(sprintf("%s_med",typenames[t]),'time')],all_max_points[typenames[t]])
lines(medlines, col=MY_COLORS_[t], lty='solid')
milines = NULL
malines = NULL
milines = ml2lines(one_frame[c(sprintf("%s_min",typenames[t]),'time')],all_max_points[typenames[t]])
malines = ml2lines(one_frame[c(sprintf("%s_max",typenames[t]),'time')],all_max_points[typenames[t]])
if (exists("RIBBON") && ( RIBBON=='max' )) {
#lines(milines, col=MY_COLORS_[t], lty='dashed')
lines(malines, col=MY_COLORS_[t], lty='dashed')
#points(proj[c('iters',sprintf("%s_min",typenames[t]))], col=MY_COLORS_[t], pch='.')
#points(proj[c('iters',sprintf("%s_max",typenames[t]))], col=MY_COLORS_[t], pch='.')
}
if (exists("RIBBON") && RIBBON != '') {
for (i in seq_len(dim(avglines)[1]-1)) {
if (RIBBON=='both') {
# draw boxes
x_l <- milines[i,][['X']]
x_r <- milines[i+1,][['X']]
y_l <- milines[i,][['Y']]
y_h <- malines[i,][['Y']]
rect(x_l, y_l, x_r, y_h, col=alpha(MY_COLORS_[t], alpha=0.1), lwd=0)
}
if (FALSE && RIBBON=='span') {
# draw boxes
x_l <- milines[i,][['X']]
x_r <- milines[i+1,][['X']]
y_l <- milines[i,][['Y']]
y_h <- malines[i,][['Y']]
rect(x_l, y_l, x_r, y_h, col=alpha(MY_COLORS_[t], alpha=0.1), lwd=0)
}
#if (FALSE && RIBBON=='both' || RIBBON=='sd') {
# # draw sd
# x_l <- avglines[i,][['X']]
# x_r <- avglines[i+1,][['X']]
# y_l <- avglines[i,][['Y']]-one_frame[ceiling(i/2),][[sprintf("%s_sd",typenames[t])]]
# y_h <- avglines[i,][['Y']]+one_frame[ceiling(i/2),][[sprintf("%s_sd",typenames[t])]]
# if (x_r != x_l) {
# rect(x_l, y_l, x_r, y_h, col=alpha(MY_COLORS_[t], alpha=0.1), lwd=0)
# }
#}
#sd_ <- row[sprintf("%s_sd",typenames[t])][[1]]
#min_ <- row[sprintf("%s_min",typenames[t])][[1]]
#max_ <- row[sprintf("%s_max",typenames[t])][[1]]
#if (exists("RIBBON")) {
# switch (RIBBON,
# 'sd' = arrows(x_, y_-sd_, x_, y_+sd_, length=0, angle=90, code=3, col=alpha(MY_COLORS_[t], alpha=0.03)),
# 'both' = arrows(x_, y_-sd_, x_, y_+sd_, length=0, angle=90, code=3, col=alpha(MY_COLORS_[t], alpha=0.05)),
# 'span' = #arrows(x_, min_, x_, max_, length=0, angle=90, code=3, col=alpha(MY_COLORS_[t], alpha=0.03))
# )
#}
##arrows(x_, y_-sd_, x_, y_+sd_, length=0.05, angle=90, code=3, col=alpha(MY_COLORS[t], alpha=0.1))
}
}
}
leglines=typenames
if (DRAW_WC) {
lines(c(0,length(one_frame[[1]])),y=c(worst_case,worst_case), lty='dotted')
leglines=c(typenames, 'worst observed')
}
legend(LEGEND_POS, legend=leglines,#"topleft"
col=c(MY_COLORS_[1:length(typenames)],"black"),
lty=c(rep("solid",length(typenames)),"dotted"))
if (SAVE_FILE) {dev.off()}
}
stopCluster(cl)
par(mar=c(3.8,3.8,0,0))
par(oma=c(0,0,0,0))
#RIBBON='both'
#MY_SELECTION = c('state_int','generation100_int')
#MY_SELECTION = c('state_int','frafl_int')
if (exists("MY_SELECTION")) {
plotting(MY_SELECTION, 'custom', MY_COLORS[c(1,2)])
} else {
# MY_SELECTION=c('state', 'afl', 'random', 'feedlongest', 'feedgeneration', 'feedgeneration10')
#MY_SELECTION=c('state_int', 'afl_int', 'random_int', 'feedlongest_int', 'feedgeneration_int', 'feedgeneration10_int')
#MY_SELECTION=c('state', 'frAFL', 'statenohash', 'feedgeneration10')
#MY_SELECTION=c('state_int', 'frAFL_int', 'statenohash_int', 'feedgeneration10_int')
MY_SELECTION=typenames
RIBBON='both'
for (i in seq_len(length(MY_SELECTION))) {
n <- MY_SELECTION[i]
plotting(c(n), n, c(MY_COLORS[i]))
}
RIBBON='max'
plotting(MY_SELECTION,'all', MY_COLORS)
}
for (t in seq_len(length(typenames))) {
li = one_frame[dim(one_frame)[1],]
pear = (li[[typenames[[t]]]]-li[[sprintf("%s_med",typenames[[t]])]])/li[[sprintf("%s_sd",typenames[[t]])]]
print(sprintf("%s pearson: %g",typenames[[t]],pear))
}

View File

@ -0,0 +1,24 @@
kernel,main_function,input_symbol,input_size,return_function
mpeg2,mpeg2_main,mpeg2_oldorgframe,90112,mpeg2_return
audiobeam,audiobeam_main,audiobeam_input,11520,audiobeam_return
epic,epic_main,epic_image,4096,epic_return
dijkstra,dijkstra_main,dijkstra_AdjMatrix,10000,dijkstra_return
fft,fft_main,fft_twidtable,2046,fft_return
bsort,bsort_main,bsort_Array,400,bsort_return
insertsort,insertsort_main,insertsort_a,400,insertsort_return
g723_enc,g723_enc_main,g723_enc_INPUT,1024,g723_enc_return
rijndael_dec,rijndael_dec_main,rijndael_dec_data,32768,rijndael_dec_return
rijndael_enc,rijndael_enc_main,rijndael_enc_data,31369,rijndael_enc_return
huff_dec,huff_dec_main,huff_dec_encoded,419,huff_dec_return
huff_enc,huff_enc_main,huff_enc_plaintext,600,huff_enc_return
gsm_enc,gsm_enc_main,gsm_enc_pcmdata,6400,gsm_enc_return
tmr,main,FUZZ_INPUT,32,trigger_Qemu_break
tacle_rtos,prvStage0,FUZZ_INPUT,604,trigger_Qemu_break
lift,main_lift,FUZZ_INPUT,100,trigger_Qemu_break
waters,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break
watersv2,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break
waters_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break
watersv2_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break
micro_branchless,main_branchless,FUZZ_INPUT,4,trigger_Qemu_break
micro_int,main_int,FUZZ_INPUT,16,trigger_Qemu_break
micro_longint,main_micro_longint,FUZZ_INPUT,16,trigger_Qemu_break
1 kernel main_function input_symbol input_size return_function
2 mpeg2 mpeg2_main mpeg2_oldorgframe 90112 mpeg2_return
3 audiobeam audiobeam_main audiobeam_input 11520 audiobeam_return
4 epic epic_main epic_image 4096 epic_return
5 dijkstra dijkstra_main dijkstra_AdjMatrix 10000 dijkstra_return
6 fft fft_main fft_twidtable 2046 fft_return
7 bsort bsort_main bsort_Array 400 bsort_return
8 insertsort insertsort_main insertsort_a 400 insertsort_return
9 g723_enc g723_enc_main g723_enc_INPUT 1024 g723_enc_return
10 rijndael_dec rijndael_dec_main rijndael_dec_data 32768 rijndael_dec_return
11 rijndael_enc rijndael_enc_main rijndael_enc_data 31369 rijndael_enc_return
12 huff_dec huff_dec_main huff_dec_encoded 419 huff_dec_return
13 huff_enc huff_enc_main huff_enc_plaintext 600 huff_enc_return
14 gsm_enc gsm_enc_main gsm_enc_pcmdata 6400 gsm_enc_return
15 tmr main FUZZ_INPUT 32 trigger_Qemu_break
16 tacle_rtos prvStage0 FUZZ_INPUT 604 trigger_Qemu_break
17 lift main_lift FUZZ_INPUT 100 trigger_Qemu_break
18 waters main_waters FUZZ_INPUT 4096 trigger_Qemu_break
19 watersv2 main_waters FUZZ_INPUT 4096 trigger_Qemu_break
20 waters_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break
21 watersv2_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break
22 micro_branchless main_branchless FUZZ_INPUT 4 trigger_Qemu_break
23 micro_int main_int FUZZ_INPUT 16 trigger_Qemu_break
24 micro_longint main_micro_longint FUZZ_INPUT 16 trigger_Qemu_break

2
fuzzers/FRET/example/build.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
arm-none-eabi-gcc -ggdb -ffreestanding -nostartfiles -lgcc -T mps2_m3.ld -mcpu=cortex-m3 main.c startup.c -o example.elf

View File

@ -0,0 +1,38 @@
int BREAKPOINT() {
for (;;)
{
}
}
int LLVMFuzzerTestOneInput(unsigned int* Data, unsigned int Size) {
//if (Data[3] == 0) {while(1){}} // cause a timeout
for (int i=0; i<Size; i++) {
// if (Data[i] > 0xFFd0 && Data[i] < 0xFFFF) {return 1;} // cause qemu to crash
for (int j=i+1; j<Size; j++) {
if (Data[j] == 0) {continue;}
if (Data[j]>Data[i]) {
int tmp = Data[i];
Data[i]=Data[j];
Data[j]=tmp;
if (Data[i] <= 100) {j--;}
}
}
}
return BREAKPOINT();
}
unsigned int FUZZ_INPUT[] = {
101,201,700,230,860,
234,980,200,340,678,
230,134,900,236,900,
123,800,123,658,607,
246,804,567,568,207,
407,246,678,457,892,
834,456,878,246,699,
854,234,844,290,125,
324,560,852,928,910,
790,853,345,234,586,
};
int main() {
LLVMFuzzerTestOneInput(FUZZ_INPUT, 50);
}

View File

@ -0,0 +1,143 @@
/*
* FreeRTOS V202112.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
MEMORY
{
RAM (xrw) : ORIGIN = 0x00000000, LENGTH = 4M
/* Originally */
/* FLASH (xr) : ORIGIN = 0x00000000, LENGTH = 4M */
/* RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4M */
}
ENTRY(Reset_Handler)
_Min_Heap_Size = 0x300000 ; /* Required amount of heap. */
_Min_Stack_Size = 0x4000 ; /* Required amount of stack. */
M_VECTOR_RAM_SIZE = (16 + 48) * 4;
_estack = ORIGIN(RAM) + LENGTH(RAM);
SECTIONS
{
.isr_vector :
{
__vector_table = .;
KEEP(*(.isr_vector))
. = ALIGN(4);
} > RAM /* FLASH */
.text :
{
. = ALIGN(4);
*(.text*)
KEEP (*(.init))
KEEP (*(.fini))
KEEP(*(.eh_frame))
*(.rodata*)
. = ALIGN(4);
_etext = .;
} > RAM /* FLASH */
.ARM.extab :
{
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >RAM /* FLASH */
.ARM :
{
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end = .;
. = ALIGN(4);
} >RAM /* FLASH */
.interrupts_ram :
{
. = ALIGN(4);
__VECTOR_RAM__ = .;
__interrupts_ram_start__ = .;
. += M_VECTOR_RAM_SIZE;
. = ALIGN(4);
__interrupts_ram_end = .;
} > RAM
_sidata = LOADADDR(.data);
.data : /* AT ( _sidata ) */
{
. = ALIGN(4);
_sdata = .;
*(.data*)
. = ALIGN(4);
_edata = .;
} > RAM /* RAM AT > FLASH */
.uninitialized (NOLOAD):
{
. = ALIGN(32);
__uninitialized_start = .;
*(.uninitialized)
KEEP(*(.keep.uninitialized))
. = ALIGN(32);
__uninitialized_end = .;
} > RAM
.bss :
{
. = ALIGN(4);
_sbss = .;
__bss_start__ = _sbss;
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
__bss_end__ = _ebss;
} >RAM
.heap :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
_heap_bottom = .;
. = . + _Min_Heap_Size;
_heap_top = .;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - _Min_Stack_Size;
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= _heap_top, "region RAM overflowed with stack")
}

View File

@ -0,0 +1,114 @@
/*
* FreeRTOS V202112.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
typedef unsigned int uint32_t;
extern int main();
extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss;
/* Prevent optimization so gcc does not replace code with memcpy */
__attribute__( ( optimize( "O0" ) ) )
__attribute__( ( naked ) )
void Reset_Handler( void )
{
/* set stack pointer */
__asm volatile ( "ldr r0, =_estack" );
__asm volatile ( "mov sp, r0" );
/* copy .data section from flash to RAM */
// Not needed for this example, see linker script
// for( uint32_t * src = &_sidata, * dest = &_sdata; dest < &_edata; )
// {
// *dest++ = *src++;
// }
/* zero out .bss section */
for( uint32_t * dest = &_sbss; dest < &_ebss; )
{
*dest++ = 0;
}
/* jump to board initialisation */
void _start( void );
_start();
}
const uint32_t * isr_vector[] __attribute__( ( section( ".isr_vector" ) ) ) =
{
( uint32_t * ) &_estack,
( uint32_t * ) &Reset_Handler, /* Reset -15 */
0, /* NMI_Handler -14 */
0, /* HardFault_Handler -13 */
0, /* MemManage_Handler -12 */
0, /* BusFault_Handler -11 */
0, /* UsageFault_Handler -10 */
0, /* reserved */
0, /* reserved */
0, /* reserved */
0, /* reserved -6 */
0, /* SVC_Handler -5 */
0, /* DebugMon_Handler -4 */
0, /* reserved */
0, /* PendSV handler -2 */
0, /* SysTick_Handler -1 */
0, /* uart0 receive 0 */
0, /* uart0 transmit */
0, /* uart1 receive */
0, /* uart1 transmit */
0, /* uart 2 receive */
0, /* uart 2 transmit */
0, /* GPIO 0 combined interrupt */
0, /* GPIO 2 combined interrupt */
0, /* Timer 0 */
0, /* Timer 1 */
0, /* Dial Timer */
0, /* SPI0 SPI1 */
0, /* uart overflow 1, 2,3 */
0, /* Ethernet 13 */
};
__attribute__( ( naked ) ) void exit(__attribute__((unused)) int status )
{
/* Force qemu to exit using ARM Semihosting */
__asm volatile (
"mov r1, r0\n"
"cmp r1, #0\n"
"bne .notclean\n"
"ldr r1, =0x20026\n" /* ADP_Stopped_ApplicationExit, a clean exit */
".notclean:\n"
"movs r0, #0x18\n" /* SYS_EXIT */
"bkpt 0xab\n"
"end: b end\n"
);
}
void _start( void )
{
main( );
exit( 0 );
}

25
fuzzers/FRET/fuzzer.sh Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
cd "$parent_path"
[ -n "$1" -a "$1" != "+" -a -z "$KERNEL" ] && export KERNEL="$1"
[ -n "$2" -a "$2" != "+" -a -z "$FUZZ_MAIN" ] && export FUZZ_MAIN="$2"
[ -n "$3" -a "$3" != "+" -a -z "$FUZZ_INPUT" ] && export FUZZ_INPUT="$3"
[ -n "$4" -a "$4" != "+" -a -z "$FUZZ_INPUT_LEN" ] && export FUZZ_INPUT_LEN="$4"
[ -n "$5" -a "$5" != "+" -a -z "$BREAKPOINT" ] && export BREAKPOINT="$5"
[ -n "$6" -a "$6" != "+" -a -z "$FUZZ_ITERS" ] && export FUZZ_ITERS="$6"
[ -n "$7" -a "$7" != "+" -a -z "$TIME_DUMP" ] && export TIME_DUMP="$7"
[ -n "$8" -a "$8" != "+" -a -z "$CASE_DUMP" ] && export CASE_DUMP="$8"
[ -n "$9" -a "$9" != "+" -a -z "$DO_SHOWMAP" ] && export DO_SHOWMAP="$9"
[ -n "${10}" -a "${10}" != "+" -a -z "$SHOWMAP_TEXTINPUT" ] && export SHOWMAP_TEXTINPUT="${10}"
[ -n "${11}" -a "${11}" != "+" -a -z "$TRACE_DUMP" ] && export TRACE_DUMP="${11}"
[ -z "$FUZZER" ] && export FUZZER=target/debug/fret
set +e
$FUZZER -icount shift=4,align=off,sleep=off -machine mps2-an385 -monitor null -kernel $KERNEL -serial null -nographic -S -semihosting --semihosting-config enable=on,target=native -snapshot -drive if=none,format=qcow2,file=dummy.qcow2
if [ "$exitcode" = "101" ]
then
exit 101
else
exit 0
fi

344
fuzzers/FRET/src/clock.rs Normal file
View File

@ -0,0 +1,344 @@
use hashbrown::{hash_map::Entry, HashMap};
use libafl::{
bolts::{
current_nanos,
rands::StdRand,
tuples::{tuple_list},
},
executors::{ExitKind},
fuzzer::{StdFuzzer},
inputs::{BytesInput, HasTargetBytes},
observers::{Observer,VariableMapObserver},
state::{StdState, HasNamedMetadata},
Error,
observers::ObserversTuple, prelude::UsesInput, impl_serdeany,
};
use serde::{Deserialize, Serialize};
use std::{cell::UnsafeCell, cmp::max, env, fs::OpenOptions, io::Write, time::Instant};
use libafl::bolts::tuples::Named;
use libafl_qemu::{
emu,
emu::Emulator,
executor::QemuExecutor,
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
};
use libafl::events::EventFirer;
use libafl::state::HasClientPerfMonitor;
use libafl::inputs::Input;
use libafl::feedbacks::Feedback;
use libafl::SerdeAny;
use libafl::state::HasMetadata;
use libafl::corpus::testcase::Testcase;
use core::{fmt::Debug, time::Duration};
// use libafl::feedbacks::FeedbackState;
// use libafl::state::HasFeedbackStates;
use libafl::bolts::tuples::MatchName;
use std::time::{SystemTime, UNIX_EPOCH};
pub static mut FUZZ_START_TIMESTAMP : SystemTime = UNIX_EPOCH;
//========== Metadata
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
pub struct QemuIcountMetadata {
runtime: u64,
}
/// Metadata for [`QemuClockIncreaseFeedback`]
#[derive(Debug, Serialize, Deserialize, SerdeAny)]
pub struct MaxIcountMetadata {
pub max_icount_seen: u64,
pub name: String,
}
// impl FeedbackState for MaxIcountMetadata
// {
// fn reset(&mut self) -> Result<(), Error> {
// self.max_icount_seen = 0;
// Ok(())
// }
// }
impl Named for MaxIcountMetadata
{
#[inline]
fn name(&self) -> &str {
self.name.as_str()
}
}
impl MaxIcountMetadata
{
/// Create new `MaxIcountMetadata`
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
max_icount_seen: 0,
name: name.to_string(),
}
}
}
impl Default for MaxIcountMetadata {
fn default() -> Self {
Self::new("MaxClock")
}
}
/// A piece of metadata tracking all icounts
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
pub struct IcHist (pub Vec<(u64, u128)>, pub (u64,u128));
//========== Observer
/// A simple observer, just overlooking the runtime of the target.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct QemuClockObserver {
name: String,
start_tick: u64,
end_tick: u64,
}
impl QemuClockObserver {
/// Creates a new [`QemuClockObserver`] with the given name.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: name.to_string(),
start_tick: 0,
end_tick: 0,
}
}
/// Gets the runtime for the last execution of this target.
#[must_use]
pub fn last_runtime(&self) -> u64 {
self.end_tick - self.start_tick
}
}
impl<S> Observer<S> for QemuClockObserver
where
S: UsesInput + HasMetadata,
{
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
// Only remember the pre-run ticks if presistent mode ist used
#[cfg(not(feature = "snapshot_restore"))]
unsafe {
self.start_tick=emu::icount_get_raw();
self.end_tick=self.start_tick;
}
// unsafe {
// println!("clock pre {}",emu::icount_get_raw());
// }
Ok(())
}
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
unsafe { self.end_tick = emu::icount_get_raw() };
// println!("clock post {}", self.end_tick);
// println!("Number of Ticks: {} <- {} {}",self.end_tick - self.start_tick, self.end_tick, self.start_tick);
let metadata =_state.metadata_mut();
let hist = metadata.get_mut::<IcHist>();
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
match hist {
None => {
metadata.insert(IcHist(vec![(self.end_tick - self.start_tick, timestamp)],
(self.end_tick - self.start_tick, timestamp)));
}
Some(v) => {
v.0.push((self.end_tick - self.start_tick, timestamp));
if (v.1.0 < self.end_tick-self.start_tick) {
v.1 = (self.end_tick - self.start_tick, timestamp);
}
if v.0.len() >= 100 {
if let Ok(td) = env::var("TIME_DUMP") {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open(td).expect("Could not open timedump");
let newv : Vec<(u64, u128)> = Vec::with_capacity(100);
for i in std::mem::replace(&mut v.0, newv).into_iter() {
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
}
} else {
// If we don't write out values we don't need to remember them at all
v.0.clear();
}
}
}
}
Ok(())
}
}
impl Named for QemuClockObserver {
#[inline]
fn name(&self) -> &str {
&self.name
}
}
impl Default for QemuClockObserver {
fn default() -> Self {
Self {
name: String::from("clock"),
start_tick: 0,
end_tick: 0,
}
}
}
//========== Feedback
/// Nop feedback that annotates execution time in the new testcase, if any
/// for this Feedback, the testcase is never interesting (use with an OR).
/// It decides, if the given [`QemuClockObserver`] value of a run is interesting.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ClockTimeFeedback {
exec_time: Option<Duration>,
name: String,
}
impl<S> Feedback<S> for ClockTimeFeedback
where
S: UsesInput + HasClientPerfMonitor + HasMetadata,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
// TODO Replace with match_name_type when stable
let observer = observers.match_name::<QemuClockObserver>(self.name()).unwrap();
self.exec_time = Some(Duration::from_nanos(observer.last_runtime() << 4)); // Assume a somewhat realistic multiplier of clock, it does not matter
Ok(false)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata(
&mut self,
_state: &mut S,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> {
*testcase.exec_time_mut() = self.exec_time;
self.exec_time = None;
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.exec_time = None;
Ok(())
}
}
impl Named for ClockTimeFeedback {
#[inline]
fn name(&self) -> &str {
self.name.as_str()
}
}
impl ClockTimeFeedback {
/// Creates a new [`ClockFeedback`], deciding if the value of a [`QemuClockObserver`] with the given `name` of a run is interesting.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
exec_time: None,
name: name.to_string(),
}
}
/// Creates a new [`ClockFeedback`], deciding if the given [`QemuClockObserver`] value of a run is interesting.
#[must_use]
pub fn new_with_observer(observer: &QemuClockObserver) -> Self {
Self {
exec_time: None,
name: observer.name().to_string(),
}
}
}
/// A [`Feedback`] rewarding increasing the execution cycles on Qemu.
#[derive(Debug)]
pub struct QemuClockIncreaseFeedback {
name: String,
}
impl<S> Feedback<S> for QemuClockIncreaseFeedback
where
S: UsesInput + HasNamedMetadata + HasClientPerfMonitor + Debug,
{
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let observer = _observers.match_name::<QemuClockObserver>("clock")
.expect("QemuClockObserver not found");
let clock_state = state
.named_metadata_mut()
.get_mut::<MaxIcountMetadata>(&self.name)
.unwrap();
if observer.last_runtime() > clock_state.max_icount_seen {
// println!("Clock improving {}",observer.last_runtime());
clock_state.max_icount_seen = observer.last_runtime();
return Ok(true);
}
Ok(false)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
// testcase.metadata_mut().insert(QemuIcountMetadata{runtime: self.last_runtime});
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
}
impl Named for QemuClockIncreaseFeedback {
#[inline]
fn name(&self) -> &str {
&self.name
}
}
impl QemuClockIncreaseFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {name: String::from(name)}
}
}
impl Default for QemuClockIncreaseFeedback {
fn default() -> Self {
Self::new("MaxClock")
}
}

715
fuzzers/FRET/src/fuzzer.rs Normal file
View File

@ -0,0 +1,715 @@
//! A fuzzer using qemu in systemmode for binary-only coverage of kernels
//!
use core::time::Duration;
use std::{env, path::PathBuf, process::{self, abort}, io::{Read, Write}, fs::{self, OpenOptions}, cmp::{min, max}, mem::transmute_copy, collections::btree_map::Range};
use libafl::{
bolts::{
core_affinity::Cores,
current_nanos,
launcher::Launcher,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list,
AsSlice,
},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
events::EventConfig,
executors::{ExitKind, TimeoutExecutor},
feedback_or,
feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor,
observers::{VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
state::{HasCorpus, StdState, HasMetadata, HasNamedMetadata},
Error,
prelude::{SimpleMonitor, SimpleEventManager, AsMutSlice, RandBytesGenerator, Generator, SimpleRestartingEventManager, HasBytesVec, minimizer::TopRatedsMetadata, havoc_mutations, StdScheduledMutator, HitcountsMapObserver}, Evaluator, stages::StdMutationalStage,
};
use libafl_qemu::{
edges, edges::QemuEdgeCoverageHelper, elf::EasyElf, emu::Emulator, GuestPhysAddr, QemuExecutor,
QemuHooks, Regs, QemuInstrumentationFilter, GuestAddr,
emu::libafl_qemu_set_native_breakpoint, emu::libafl_qemu_remove_native_breakpoint,
};
use rand::{SeedableRng, StdRng, Rng};
use crate::{
clock::{QemuClockObserver, ClockTimeFeedback, QemuClockIncreaseFeedback, IcHist, FUZZ_START_TIMESTAMP},
qemustate::QemuStateRestoreHelper,
systemstate::{helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{SysMapFeedback, SysGraphFeedbackState, GraphMaximizerCorpusScheduler}, schedulers::{LongestTraceScheduler, GenerationScheduler}}, worst::{TimeMaximizerCorpusScheduler, ExecTimeIncFeedback, TimeStateMaximizerCorpusScheduler, AlwaysTrueFeedback},
mutational::MyStateStage,
mutational::{MINIMUM_INTER_ARRIVAL_TIME},
};
use std::time::{SystemTime, UNIX_EPOCH};
pub static mut RNG_SEED: u64 = 1;
pub static mut LIMIT : u32 = u32::MAX;
pub const MAX_NUM_INTERRUPT: usize = 32;
pub const DO_NUM_INTERRUPT: usize = 32;
pub static mut MAX_INPUT_SIZE: usize = 32;
/// Read ELF program headers to resolve physical load addresses.
fn virt2phys(vaddr: GuestPhysAddr, tab: &EasyElf) -> GuestPhysAddr {
let ret;
for i in &tab.goblin().program_headers {
if i.vm_range().contains(&vaddr.try_into().unwrap()) {
ret = vaddr - TryInto::<GuestPhysAddr>::try_into(i.p_vaddr).unwrap()
+ TryInto::<GuestPhysAddr>::try_into(i.p_paddr).unwrap();
return ret - (ret % 2);
}
}
return vaddr;
}
extern "C" {
static mut libafl_interrupt_offsets : [u32; 32];
static mut libafl_num_interrupts : usize;
}
pub fn fuzz() {
unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();}
let mut starttime = std::time::Instant::now();
if let Ok(s) = env::var("FUZZ_SIZE") {
str::parse::<usize>(&s).expect("FUZZ_SIZE was not a number");
};
// Hardcoded parameters
let timeout = Duration::from_secs(10);
let broker_port = 1337;
let cores = Cores::from_cmdline("1").unwrap();
let corpus_dirs = [PathBuf::from("./corpus")];
let objective_dir = PathBuf::from("./crashes");
let mut elf_buffer = Vec::new();
let elf = EasyElf::from_file(
env::var("KERNEL").expect("KERNEL env not set"),
&mut elf_buffer,
)
.unwrap();
// the main address where the fuzzer starts
// if this is set for freeRTOS it has an influence on where the data will have to be written,
// since the startup routine copies the data segemnt to it's virtual address
let main_addr = elf
.resolve_symbol(&env::var("FUZZ_MAIN").unwrap_or_else(|_| "FUZZ_MAIN".to_owned()), 0);
if let Some(main_addr) = main_addr {
println!("main address = {:#x}", main_addr);
}
let input_addr = elf
.resolve_symbol(
&env::var("FUZZ_INPUT").unwrap_or_else(|_| "FUZZ_INPUT".to_owned()),
0,
)
.expect("Symbol or env FUZZ_INPUT not found") as GuestPhysAddr;
let input_addr = virt2phys(input_addr,&elf) as GuestPhysAddr;
println!("FUZZ_INPUT @ {:#x}", input_addr);
let test_length_ptr = elf
.resolve_symbol("FUZZ_LENGTH", 0).map(|x| x as GuestPhysAddr);
let test_length_ptr = Option::map_or(test_length_ptr, None, |x| Some(virt2phys(x,&elf)));
let input_counter_ptr = elf
.resolve_symbol(&env::var("FUZZ_POINTER").unwrap_or_else(|_| "FUZZ_POINTER".to_owned()), 0)
.map(|x| x as GuestPhysAddr);
let input_counter_ptr = Option::map_or(input_counter_ptr, None, |x| Some(virt2phys(x,&elf)));
#[cfg(feature = "systemstate")]
let curr_tcb_pointer = elf // loads to the address specified in elf, without respecting program headers
.resolve_symbol("pxCurrentTCB", 0)
.expect("Symbol pxCurrentTCBC not found");
// let curr_tcb_pointer = virt2phys(curr_tcb_pointer,&elf);
#[cfg(feature = "systemstate")]
println!("TCB pointer at {:#x}", curr_tcb_pointer);
#[cfg(feature = "systemstate")]
let task_queue_addr = elf
.resolve_symbol("pxReadyTasksLists", 0)
.expect("Symbol pxReadyTasksLists not found");
// let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin());
#[cfg(feature = "systemstate")]
println!("Task Queue at {:#x}", task_queue_addr);
#[cfg(feature = "systemstate")]
let svh = elf
.resolve_symbol("xPortPendSVHandler", 0)
.expect("Symbol xPortPendSVHandler not found");
// let svh=virt2phys(svh, &elf);
// let svh = elf
// .resolve_symbol("vPortEnterCritical", 0)
// .expect("Symbol vPortEnterCritical not found");
#[cfg(feature = "systemstate")]
let app_start = elf
.resolve_symbol("__APP_CODE_START__", 0)
.expect("Symbol __APP_CODE_START__ not found");
#[cfg(feature = "systemstate")]
let app_end = elf
.resolve_symbol("__APP_CODE_END__", 0)
.expect("Symbol __APP_CODE_END__ not found");
#[cfg(feature = "systemstate")]
let app_range = app_start..app_end;
#[cfg(feature = "systemstate")]
dbg!(app_range.clone());
let breakpoint = elf
.resolve_symbol(
&env::var("BREAKPOINT").unwrap_or_else(|_| "BREAKPOINT".to_owned()),
0,
)
.expect("Symbol or env BREAKPOINT not found");
println!("Breakpoint address = {:#x}", breakpoint);
unsafe {
libafl_num_interrupts = 0;
}
if let Ok(input_len) = env::var("FUZZ_INPUT_LEN") {
unsafe {MAX_INPUT_SIZE = str::parse::<usize>(&input_len).expect("FUZZ_INPUT_LEN was not a number");}
}
unsafe {dbg!(MAX_INPUT_SIZE);}
if let Ok(seed) = env::var("SEED_RANDOM") {
unsafe {RNG_SEED = str::parse::<u64>(&seed).expect("SEED_RANDOM must be an integer.");}
}
let mut run_client = |state: Option<_>, mut mgr, _core_id| {
// Initialize QEMU
let args: Vec<String> = env::args().collect();
let env: Vec<(String, String)> = env::vars().collect();
let emu = Emulator::new(&args, &env);
if let Some(main_addr) = main_addr {
unsafe {
libafl_qemu_set_native_breakpoint(main_addr);
emu.run();
libafl_qemu_remove_native_breakpoint(main_addr);
}
}
unsafe { libafl_qemu_set_native_breakpoint(breakpoint); }// BREAKPOINT
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let mut len = buf.len();
unsafe {
#[cfg(feature = "fuzz_int")]
{
let mut start_tick : u32 = 0;
for i in 0..DO_NUM_INTERRUPT {
let mut t : [u8; 4] = [0,0,0,0];
if len > (i+1)*4 {
for j in 0 as usize..4 as usize {
t[j]=buf[i*4+j];
}
if i == 0 || true {
unsafe {start_tick = u32::from_le_bytes(t) % LIMIT;}
} else {
start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t)));
}
libafl_interrupt_offsets[i] = start_tick;
libafl_num_interrupts = i+1;
}
}
if buf.len() > libafl_num_interrupts*4 {
buf = &buf[libafl_num_interrupts*4..];
len = buf.len();
}
// println!("Load: {:?}", libafl_interrupt_offsets[0..libafl_num_interrupts].to_vec());
}
if len > MAX_INPUT_SIZE {
buf = &buf[0..MAX_INPUT_SIZE];
len = MAX_INPUT_SIZE;
}
emu.write_phys_mem(input_addr, buf);
if let Some(s) = test_length_ptr {
emu.write_phys_mem(s as u64, &len.to_le_bytes())
}
emu.run();
// If the execution stops at any point other then the designated breakpoint (e.g. a breakpoint on a panic method) we consider it a crash
let mut pcs = (0..emu.num_cpus())
.map(|i| emu.cpu_from_index(i))
.map(|cpu| -> Result<u32, String> { cpu.read_reg(Regs::Pc) });
match pcs
.find(|pc| (breakpoint..breakpoint + 5).contains(pc.as_ref().unwrap_or(&0)))
{
Some(_) => ExitKind::Ok,
None => ExitKind::Crash,
}
}
};
// Create an observation channel using the coverage map
let edges = unsafe { &mut edges::EDGES_MAP };
let edges_counter = unsafe { &mut edges::MAX_EDGES_NUM };
let edges_observer = VariableMapObserver::new("edges", edges, edges_counter);
#[cfg(feature = "observer_hitcounts")]
let edges_observer = HitcountsMapObserver::new(edges_observer);
// Create an observation channel to keep track of the execution time
let clock_time_observer = QemuClockObserver::new("clocktime");
let systemstate_observer = QemuSystemStateObserver::new();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!(
// Time feedback, this one does not need a feedback state
ClockTimeFeedback::new_with_observer(&clock_time_observer)
);
#[cfg(feature = "feed_genetic")]
let mut feedback = feedback_or!(
feedback,
AlwaysTrueFeedback::new()
);
#[cfg(feature = "feed_afl")]
let mut feedback = feedback_or!(
feedback,
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new_tracking(&edges_observer, true, true)
);
#[cfg(feature = "feed_longest")]
let mut feedback = feedback_or!(
// afl feedback needs to be activated first for MapIndexesMetadata
feedback,
// Feedback to reward any input which increses the execution time
ExecTimeIncFeedback::new()
);
#[cfg(all(feature = "systemstate",not(any(feature = "feed_systemgraph",feature = "feed_systemtrace"))))]
let mut feedback = feedback_or!(
feedback,
DumpSystraceFeedback::with_dump(env::var("TRACE_DUMP").ok().map(PathBuf::from))
);
#[cfg(feature = "feed_systemtrace")]
let mut feedback = feedback_or!(
feedback,
// AlwaysTrueFeedback::new(),
NovelSystemStateFeedback::default()
);
#[cfg(feature = "feed_systemgraph")]
let mut feedback = feedback_or!(
feedback,
SysMapFeedback::default()
);
// A feedback to choose if an input is a solution or not
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {
StdState::new(
// RNG
unsafe {StdRand::with_seed(RNG_SEED) },
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(objective_dir.clone()).unwrap(),
// States of the feedbacks.
// The feedbacks can report the data that should persist in the State.
&mut feedback,
// Same for objective feedbacks
&mut objective,
)
.unwrap()
});
// A minimization+queue policy to get testcasess from the corpus
#[cfg(not(any(feature = "feed_afl",feature = "feed_systemgraph",feature = "feed_systemtrace", feature = "feed_genetic")))]
let scheduler = QueueScheduler::new();
#[cfg(all(feature = "feed_afl",not(any(feature = "feed_systemgraph",feature = "feed_systemtrace"))))]
let scheduler = TimeMaximizerCorpusScheduler::new(QueueScheduler::new());
#[cfg(feature = "feed_systemtrace")]
let scheduler = LongestTraceScheduler::new(TimeStateMaximizerCorpusScheduler::new(QueueScheduler::new()));
#[cfg(feature = "feed_systemgraph")]
let scheduler = GraphMaximizerCorpusScheduler::new(QueueScheduler::new());
#[cfg(feature = "feed_genetic")]
let scheduler = GenerationScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(not(feature = "systemstate"))]
let qhelpers = tuple_list!(
QemuEdgeCoverageHelper::default(),
QemuStateRestoreHelper::new()
);
#[cfg(feature = "systemstate")]
let qhelpers = tuple_list!(
QemuEdgeCoverageHelper::default(),
QemuStateRestoreHelper::new(),
QemuSystemStateHelper::new(svh,curr_tcb_pointer,task_queue_addr,input_counter_ptr,app_range.clone())
);
let mut hooks = QemuHooks::new(&emu,qhelpers);
#[cfg(not(feature = "systemstate"))]
let observer_list = tuple_list!(edges_observer, clock_time_observer);
#[cfg(feature = "systemstate")]
let observer_list = tuple_list!(edges_observer, clock_time_observer, systemstate_observer);
// Create a QEMU in-process executor
let executor = QemuExecutor::new(
&mut hooks,
&mut harness,
observer_list,
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create QemuExecutor");
// Wrap the executor to keep track of the timeout
let mut executor = TimeoutExecutor::new(executor, timeout);
let mutations = havoc_mutations();
// Setup an havoc mutator with a mutational stage
let mutator = StdScheduledMutator::new(mutations);
// #[cfg(not(all(feature = "feed_systemtrace", feature = "fuzz_int")))]
// let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// #[cfg(all(feature = "feed_systemtrace", feature = "fuzz_int"))]
#[cfg(feature = "fuzz_int")]
let mut stages = tuple_list!(StdMutationalStage::new(mutator),MyStateStage::new());
#[cfg(not(feature = "fuzz_int"))]
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
if env::var("DO_SHOWMAP").is_ok() {
let s = &env::var("DO_SHOWMAP").unwrap();
let show_input = if s=="-" {
let mut buf = Vec::<u8>::new();
std::io::stdin().read_to_end(&mut buf).expect("Could not read Stdin");
buf
} else if s=="$" {
env::var("SHOWMAP_TEXTINPUT").expect("SHOWMAP_TEXTINPUT not set").as_bytes().to_owned()
} else {
fs::read(s).expect("Input file for DO_SHOWMAP can not be read")
};
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, BytesInput::new(show_input))
.unwrap();
if let Ok(td) = env::var("TIME_DUMP") {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open(td).expect("Could not open timedump");
if let Some(ichist) = state.metadata_mut().get_mut::<IcHist>() {
for i in ichist.0.drain(..) {
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
}
}
}
} else {
if let Ok(_) = env::var("SEED_RANDOM") {
unsafe {
let mut rng = StdRng::seed_from_u64(RNG_SEED);
for i in 0..100 {
let inp = BytesInput::new(vec![rng.gen::<u8>(); MAX_INPUT_SIZE]);
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, inp).unwrap();
}
}
}
else if let Ok(sf) = env::var("SEED_DIR") {
state
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[PathBuf::from(&sf)])
.unwrap_or_else(|_| {
println!("Failed to load initial corpus at {:?}", &corpus_dirs);
process::exit(0);
});
println!("We imported {} inputs from seedfile.", state.corpus().count());
} else if state.corpus().count() < 1 {
state
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &corpus_dirs)
.unwrap_or_else(|_| {
println!("Failed to load initial corpus at {:?}", &corpus_dirs);
process::exit(0);
});
println!("We imported {} inputs from disk.", state.corpus().count());
}
match env::var("FUZZ_ITERS") {
Err(_) => {
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.unwrap();
},
Ok(t) => {
println!("Iterations {}",t);
let num = str::parse::<u64>(&t).expect("FUZZ_ITERS was not a number");
if let Ok(s) = env::var("FUZZ_RANDOM") { unsafe {
if s.contains("watersv2_int") {
println!("V2");
LIMIT=7000000;
} else {
println!("V1");
LIMIT=5000000;
}
println!("Random Fuzzing, ignore corpus");
// let mut generator = RandBytesGenerator::new(MAX_INPUT_SIZE);
let target_duration = Duration::from_secs(num);
let start_time = std::time::Instant::now();
let mut rng = StdRng::seed_from_u64(RNG_SEED);
while start_time.elapsed() < target_duration {
// let inp = generator.generate(&mut state).unwrap();
// libafl's generator is too slow
let inp = BytesInput::new(vec![rng.gen::<u8>(); MAX_INPUT_SIZE]);
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, inp).unwrap();
}
}} else {
// fuzzer
// .fuzz_loop_for_duration(&mut stages, &mut executor, &mut state, &mut mgr, Duration::from_secs(num))
// .unwrap();
fuzzer
.fuzz_loop_until(&mut stages, &mut executor, &mut state, &mut mgr, starttime.checked_add(Duration::from_secs(num)).unwrap())
.unwrap();
#[cfg(feature = "run_until_saturation")]
{
{
let mut dumper = |marker : String| {
if let Ok(td) = env::var("TIME_DUMP") {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open(td).expect("Could not open timedump");
if let Some(ichist) = state.metadata_mut().get_mut::<IcHist>() {
for i in ichist.0.drain(..) {
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
}
}
}
if let Ok(td) = env::var("CASE_DUMP") {
println!("Dumping worst case to {:?}", td);
let corpus = state.corpus();
let mut worst = Duration::new(0,0);
let mut worst_input = None;
for i in 0..corpus.count() {
let tc = corpus.get(i).expect("Could not get element from corpus").borrow();
if worst < tc.exec_time().expect("Testcase missing duration") {
worst_input = Some(tc.input().as_ref().unwrap().bytes().to_owned());
worst = tc.exec_time().expect("Testcase missing duration");
}
}
match worst_input {
Some(wi) => {
// let cd = format!("{}.case",&td);
let mut cd = td.clone();
cd.push_str(&marker);
fs::write(&cd,wi).expect("Failed to write worst corpus element");
},
None => (),
}
#[cfg(feature = "feed_systemgraph")]
{
let mut gd = String::from(&td);
gd.push_str(&format!(".graph{}", marker));
if let Some(md) = state.named_metadata_mut().get_mut::<SysGraphFeedbackState>("SysMap") {
fs::write(&gd,ron::to_string(&md).expect("Failed to serialize graph")).expect("Failed to write graph");
}
}
{
let mut gd = String::from(&td);
if let Some(md) = state.metadata_mut().get_mut::<TopRatedsMetadata>() {
let mut uniq: Vec<usize> = md.map.values().map(|x| x.clone()).collect();
uniq.sort();
uniq.dedup();
gd.push_str(&format!(".{}.toprated{}", uniq.len(), marker));
fs::write(&gd,ron::to_string(&md.map).expect("Failed to serialize metadata")).expect("Failed to write graph");
}
}
}
};
dumper(format!(".iter_{}",t));
}
println!("Start running until saturation");
let mut last = state.metadata().get::<IcHist>().unwrap().1;
while SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis() < last.1 + Duration::from_secs(10800).as_millis() {
starttime=starttime.checked_add(Duration::from_secs(30)).unwrap();
fuzzer
.fuzz_loop_until(&mut stages, &mut executor, &mut state, &mut mgr, starttime)
.unwrap();
let after = state.metadata().get::<IcHist>().unwrap().1;
if after.0 > last.0 {
last=after;
}
if let Ok(td) = env::var("CASE_DUMP") {
println!("Dumping worst case to {:?}", td);
let corpus = state.corpus();
let mut worst = Duration::new(0,0);
let mut worst_input = None;
for i in 0..corpus.count() {
let tc = corpus.get(i).expect("Could not get element from corpus").borrow();
if worst < tc.exec_time().expect("Testcase missing duration") {
worst_input = Some(tc.input().as_ref().unwrap().bytes().to_owned());
worst = tc.exec_time().expect("Testcase missing duration");
}
}
match worst_input {
Some(wi) => {
// let cd = format!("{}.case",&td);
let cd = td.clone();
fs::write(&cd,wi).expect("Failed to write worst corpus element");
},
None => (),
}
#[cfg(feature = "feed_systemgraph")]
{
let mut gd = String::from(&td);
gd.push_str(".graph" );
if let Some(md) = state.named_metadata_mut().get_mut::<SysGraphFeedbackState>("SysMap") {
fs::write(&gd,ron::to_string(&md).expect("Failed to serialize graph")).expect("Failed to write graph");
}
}
{
let mut gd = String::from(&td);
if let Some(md) = state.metadata_mut().get_mut::<TopRatedsMetadata>() {
let mut uniq: Vec<usize> = md.map.values().map(|x| x.clone()).collect();
uniq.sort();
uniq.dedup();
gd.push_str(&format!(".{}.toprated", uniq.len()));
fs::write(&gd,ron::to_string(&md.map).expect("Failed to serialize metadata")).expect("Failed to write graph");
}
}
}
}
}
}
if let Ok(td) = env::var("TIME_DUMP") {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open(td).expect("Could not open timedump");
if let Some(ichist) = state.metadata_mut().get_mut::<IcHist>() {
for i in ichist.0.drain(..) {
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
}
}
}
if let Ok(td) = env::var("CASE_DUMP") {
println!("Dumping worst case to {:?}", td);
let corpus = state.corpus();
let mut worst = Duration::new(0,0);
let mut worst_input = None;
for i in 0..corpus.count() {
let tc = corpus.get(i).expect("Could not get element from corpus").borrow();
if worst < tc.exec_time().expect("Testcase missing duration") {
worst_input = Some(tc.input().as_ref().unwrap().bytes().to_owned());
worst = tc.exec_time().expect("Testcase missing duration");
}
}
match worst_input {
Some(wi) => {
// let cd = format!("{}.case",&td);
let cd = td.clone();
fs::write(&cd,wi).expect("Failed to write worst corpus element");
},
None => (),
}
#[cfg(feature = "feed_systemgraph")]
{
let mut gd = String::from(&td);
gd.push_str(".graph");
if let Some(md) = state.named_metadata_mut().get_mut::<SysGraphFeedbackState>("SysMap") {
fs::write(&gd,ron::to_string(&md).expect("Failed to serialize graph")).expect("Failed to write graph");
}
}
{
let mut gd = String::from(&td);
if let Some(md) = state.metadata_mut().get_mut::<TopRatedsMetadata>() {
let mut uniq: Vec<usize> = md.map.values().map(|x| x.clone()).collect();
uniq.sort();
uniq.dedup();
gd.push_str(&format!(".{}.toprated", uniq.len()));
fs::write(&gd,ron::to_string(&md.map).expect("Failed to serialize metadata")).expect("Failed to write graph");
}
}
}
},
}
}
#[cfg(not(feature = "singlecore"))]
return Ok(());
};
// Special case where no fuzzing happens, but standard input is dumped
if let Ok(input_dump) = env::var("DUMP_SEED") {
// Initialize QEMU
let args: Vec<String> = env::args().collect();
let env: Vec<(String, String)> = env::vars().collect();
let emu = Emulator::new(&args, &env);
if let Some(main_addr) = main_addr {
unsafe { libafl_qemu_set_native_breakpoint(main_addr); }// BREAKPOINT
}
unsafe {
emu.run();
let mut buf = [0u8].repeat(MAX_INPUT_SIZE);
emu.read_phys_mem(input_addr, buf.as_mut_slice());
let dir = env::var("SEED_DIR").map_or("./corpus".to_string(), |x| x);
let filename = if input_dump == "" {"input"} else {&input_dump};
println!("Dumping input to: {}/{}",&dir,filename);
fs::write(format!("{}/{}",&dir,filename), buf).expect("could not write input dump");
}
return
}
#[cfg(feature = "singlecore")]
{
let monitor = SimpleMonitor::new(|s| println!("{}", s));
#[cfg(not(feature = "restarting"))]
{
let mgr = SimpleEventManager::new(monitor);
run_client(None, mgr, 0);
}
#[cfg(feature = "restarting")]
{
let mut shmem_provider = StdShMemProvider::new().unwrap();
let (state, mut mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider)
{
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
Ok(res) => res,
Err(err) => match err {
Error::ShuttingDown => {
return;
}
_ => {
panic!("Failed to setup the restarter: {}", err);
}
},
};
run_client(state, mgr, 0);
}
}
// else -> multicore
#[cfg(not(feature = "singlecore"))]
{
// The shared memory allocator
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
// The stats reporter for the broker
let monitor = MultiMonitor::new(|s| println!("{}", s));
// Build and run a Launcher
match Launcher::builder()
.shmem_provider(shmem_provider)
.broker_port(broker_port)
.configuration(EventConfig::from_build_id())
.monitor(monitor)
.run_client(&mut run_client)
.cores(&cores)
// .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),
}
}
}

13
fuzzers/FRET/src/lib.rs Normal file
View File

@ -0,0 +1,13 @@
#![feature(is_sorted)]
#[cfg(target_os = "linux")]
mod fuzzer;
#[cfg(target_os = "linux")]
mod clock;
#[cfg(target_os = "linux")]
mod qemustate;
#[cfg(target_os = "linux")]
pub mod systemstate;
#[cfg(target_os = "linux")]
mod mutational;
#[cfg(target_os = "linux")]
mod worst;

24
fuzzers/FRET/src/main.rs Normal file
View File

@ -0,0 +1,24 @@
#![feature(is_sorted)]
//! A libfuzzer-like fuzzer using qemu for binary-only coverage
#[cfg(target_os = "linux")]
mod fuzzer;
#[cfg(target_os = "linux")]
mod clock;
#[cfg(target_os = "linux")]
mod qemustate;
#[cfg(target_os = "linux")]
mod systemstate;
#[cfg(target_os = "linux")]
mod worst;
#[cfg(target_os = "linux")]
mod mutational;
#[cfg(target_os = "linux")]
pub fn main() {
fuzzer::fuzz();
}
#[cfg(not(target_os = "linux"))]
pub fn main() {
panic!("qemu-user and libafl_qemu is only supported on linux!");
}

View File

@ -0,0 +1,240 @@
//| The [`MutationalStage`] is the default stage used during fuzzing.
//! For the current input, it will perform a range of random mutations, and then run them in the executor.
use core::marker::PhantomData;
use std::cmp::{max, min};
use libafl::{
bolts::rands::Rand,
corpus::{Corpus, self},
fuzzer::Evaluator,
mark_feature_time,
stages::{Stage},
start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasRand, UsesState, HasMetadata},
Error, prelude::{HasBytesVec, UsesInput, new_hash_feedback, StdRand, RandomSeed, MutationResult, Mutator},
};
use crate::{systemstate::{FreeRTOSSystemStateMetadata, RefinedFreeRTOSSystemState}, fuzzer::DO_NUM_INTERRUPT, clock::IcHist};
pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4);
//======================= Custom mutator
/// The default mutational stage
#[derive(Clone, Debug, Default)]
pub struct MyStateStage<E, EM, Z> {
#[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, Z)>,
}
impl<E, EM, Z> MyStateStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{
pub fn new() -> Self {
Self { phantom: PhantomData }
}
}
impl<E, EM, Z> Stage<E, EM, Z> for MyStateStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
<Z::State as UsesInput>::Input: HasBytesVec
{
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Self::State,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error> {
let mut _input = state
.corpus()
.get(corpus_idx)?
.borrow_mut().clone();
let mut newinput = _input.input_mut().as_mut().unwrap().clone();
// let mut tmpinput = _input.input_mut().as_mut().unwrap().clone();
let mut do_rerun = false;
{
// need our own random generator, because borrowing rules
let mut myrand = StdRand::new();
let mut target_bytes : Vec<u8> = vec![];
{
let input = _input.input_mut().as_ref().unwrap();
let tmp = &mut state.rand_mut();
myrand.set_seed(tmp.next());
target_bytes = input.bytes().to_vec();
}
// produce a slice of absolute interrupt times
let mut interrupt_offsets : [u32; 32] = [0u32; 32];
let mut num_interrupts : usize = 0;
{
let mut start_tick : u32 = 0;
for i in 0..DO_NUM_INTERRUPT {
let mut t : [u8; 4] = [0,0,0,0];
if target_bytes.len() > (i+1)*4 {
for j in 0 as usize..4 as usize {
t[j]=target_bytes[i*4+j];
}
if i == 0 || true {
start_tick = u32::from_le_bytes(t);
} else {
start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t)));
}
interrupt_offsets[i] = start_tick;
num_interrupts = i+1;
}
}
}
interrupt_offsets.sort();
// println!("Vor Mutator: {:?}", interrupt_offsets[0..num_interrupts].to_vec());
// let num_i = min(target_bytes.len() / 4, DO_NUM_INTERRUPT);
let mut suffix = target_bytes.split_off(4 * num_interrupts);
let mut prefix : Vec<[u8; 4]> = vec![];
// let mut suffix : Vec<u8> = vec![];
#[cfg(feature = "feed_systemtrace")]
{
let tmp = _input.metadata().get::<FreeRTOSSystemStateMetadata>();
if tmp.is_some() {
let trace = tmp.expect("FreeRTOSSystemStateMetadata not found");
// calculate hits and identify snippets
let mut last_m = false;
let mut marks : Vec<(&RefinedFreeRTOSSystemState, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
for i in 0..trace.inner.len() {
let curr = &trace.inner[i];
let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64)));
if m {
marks.push((curr, i, 1));
// println!("1: {}",curr.current_task.task_name);
} else if last_m {
marks.push((curr, i, 2));
// println!("2: {}",curr.current_task.task_name);
} else {
marks.push((curr, i, 0));
}
last_m = m;
}
for i in 0..num_interrupts {
// bounds based on minimum inter-arrival time
let mut lb = 0;
let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32");
if i > 0 {
lb = u32::saturating_add(interrupt_offsets[i-1],MINIMUM_INTER_ARRIVAL_TIME);
}
if i < num_interrupts-1 {
ub = u32::saturating_sub(interrupt_offsets[i+1],MINIMUM_INTER_ARRIVAL_TIME);
}
// get old hit and handler
let old_hit = marks.iter().filter(
|x| x.0.start_tick < (interrupt_offsets[i] as u64) && (interrupt_offsets[i] as u64) < x.0.end_tick
).next();
let old_handler = match old_hit {
Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 {
Some(marks[s.1+1])
} else {None},
None => None
};
// find reachable alternatives
let alternatives : Vec<_> = marks.iter().filter(|x|
x.2 != 2 &&
(
x.0.start_tick < (lb as u64) && (lb as u64) < x.0.end_tick
|| x.0.start_tick < (ub as u64) && (ub as u64) < x.0.end_tick )
).collect();
// in cases there are no alternatives
if alternatives.len() == 0 {
if old_hit.is_none() {
// choose something random
let untouched : Vec<_> = marks.iter().filter(
|x| x.2 == 0
).collect();
if untouched.len() > 0 {
let tmp = interrupt_offsets[i];
let choice = myrand.choose(untouched);
interrupt_offsets[i] = myrand.between(choice.0.start_tick, choice.0.end_tick)
.try_into().expect("tick > u32");
do_rerun = true;
}
// println!("no alternatives, choose random i: {} {} -> {}",i,tmp,interrupt_offsets[i]);
continue;
} else {
// do nothing
// println!("no alternatives, do nothing i: {} {}",i,interrupt_offsets[i]);
continue;
}
}
let replacement = myrand.choose(alternatives);
if (old_hit.map_or(false, |x| x == replacement)) {
// use the old value
// println!("chose old value, do nothing i: {} {}",i,interrupt_offsets[i]);
continue;
} else {
let extra = if (old_hit.map_or(false, |x| x.1 < replacement.1)) {
// move futher back, respect old_handler
old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick)
} else { 0 };
let tmp = interrupt_offsets[i];
interrupt_offsets[i] = (myrand.between(replacement.0.start_tick,
replacement.0.end_tick) + extra).try_into().expect("ticks > u32");
// println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
do_rerun = true;
}
}
let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
numbers.sort();
// println!("Mutator: {:?}", numbers);
let mut start : u32 = 0;
// for i in 0..numbers.len() {
// let tmp = numbers[i];
// numbers[i] = numbers[i]-start;
// start = tmp;
// }
for i in 0..numbers.len() {
prefix.push(u32::to_le_bytes(numbers[i]));
}
}
}
#[cfg(not(feature = "feed_systemtrace"))]
{
let metadata = state.metadata();
let hist = metadata.get::<IcHist>().unwrap();
let maxtick : u64 = hist.1.0;
// let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
let mut numbers : Vec<u32> = vec![];
for i in 0..num_interrupts {
prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32")));
}
}
let mut n : Vec<u8> = vec![];
n = [prefix.concat(), suffix].concat();
newinput.bytes_mut().clear();
newinput.bytes_mut().append(&mut n);
}
// InterruptShifterMutator::mutate(&mut mymut, state, &mut input, 0)?;
if do_rerun {
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, newinput)?;
}
Ok(())
}
}
impl<E, EM, Z> UsesState for MyStateStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{
type State = Z::State;
}

View File

@ -0,0 +1,96 @@
use libafl::prelude::UsesInput;
use libafl_qemu::CPUArchState;
use libafl_qemu::Emulator;
use libafl_qemu::FastSnapshot;
use libafl_qemu::QemuExecutor;
use libafl_qemu::QemuHelper;
use libafl_qemu::QemuHelperTuple;
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
use libafl_qemu::QemuHooks;
use libafl_qemu::{
emu,
};
// TODO be thread-safe maybe with https://amanieu.github.io/thread_local-rs/thread_local/index.html
#[derive(Debug)]
pub struct QemuStateRestoreHelper {
has_snapshot: bool,
use_snapshot: bool,
saved_cpu_states: Vec<CPUArchState>,
fastsnap: Option<FastSnapshot>
}
impl QemuStateRestoreHelper {
#[must_use]
pub fn new() -> Self {
Self {
has_snapshot: false,
use_snapshot: true,
saved_cpu_states: vec![],
fastsnap: None
}
}
}
impl Default for QemuStateRestoreHelper {
fn default() -> Self {
Self::new()
}
}
impl<S> QemuHelper<S> for QemuStateRestoreHelper
where
S: UsesInput,
{
const HOOKS_DO_SIDE_EFFECTS: bool = true;
fn init_hooks<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
where
QT: QemuHelperTuple<S>,
{
}
fn first_exec<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
where
QT: QemuHelperTuple<S>,
{
}
fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input) {
// unsafe { println!("snapshot post {}",emu::icount_get_raw()) };
}
fn pre_exec(&mut self, emulator: &Emulator, _input: &S::Input) {
// only restore in pre-exec, to preserve the post-execution state for inspection
#[cfg(feature = "snapshot_restore")]
{
#[cfg(feature = "snapshot_fast")]
match self.fastsnap {
Some(s) => emulator.restore_fast_snapshot(s),
None => {self.fastsnap = Some(emulator.create_fast_snapshot(true));},
}
#[cfg(not(feature = "snapshot_fast"))]
if !self.has_snapshot {
emulator.save_snapshot("Start", true);
self.has_snapshot = true;
}
else
{
emulator.load_snapshot("Start", true);
}
}
#[cfg(not(feature = "snapshot_restore"))]
if !self.has_snapshot {
self.saved_cpu_states = (0..emulator.num_cpus())
.map(|i| emulator.cpu_from_index(i).save_state())
.collect();
self.has_snapshot = true;
} else {
for (i, s) in self.saved_cpu_states.iter().enumerate() {
emulator.cpu_from_index(i).restore_state(s);
}
}
// unsafe { println!("snapshot pre {}",emu::icount_get_raw()) };
}
}

View File

@ -0,0 +1,299 @@
use libafl::SerdeAny;
use libafl::bolts::ownedref::OwnedSlice;
use libafl::inputs::BytesInput;
use libafl::prelude::UsesInput;
use libafl::state::HasNamedMetadata;
use std::path::PathBuf;
use crate::clock::QemuClockObserver;
use libafl::corpus::Testcase;
use libafl::bolts::tuples::MatchName;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::hash::Hash;
use libafl::events::EventFirer;
use libafl::state::HasClientPerfMonitor;
use libafl::feedbacks::Feedback;
use libafl::bolts::tuples::Named;
use libafl::Error;
use hashbrown::HashMap;
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
use serde::{Deserialize, Serialize};
use super::RefinedFreeRTOSSystemState;
use super::FreeRTOSSystemStateMetadata;
use super::observers::QemuSystemStateObserver;
use petgraph::prelude::DiGraph;
use petgraph::graph::NodeIndex;
use petgraph::Direction;
use std::cmp::Ordering;
//============================= Feedback
/// Shared Metadata for a systemstateFeedback
#[derive(Debug, Serialize, Deserialize, SerdeAny, Clone, Default)]
pub struct SystemStateFeedbackState
{
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
longest: Vec<RefinedFreeRTOSSystemState>,
}
impl Named for SystemStateFeedbackState
{
#[inline]
fn name(&self) -> &str {
"systemstate"
}
}
// impl FeedbackState for systemstateFeedbackState
// {
// fn reset(&mut self) -> Result<(), Error> {
// self.longest.clear();
// self.known_traces.clear();
// Ok(())
// }
// }
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct NovelSystemStateFeedback
{
last_trace: Option<Vec<RefinedFreeRTOSSystemState>>,
// known_traces: HashMap<u64,(u64,usize)>,
}
impl<S> Feedback<S> for NovelSystemStateFeedback
where
S: UsesInput + HasClientPerfMonitor + HasNamedMetadata,
{
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>
{
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
.expect("QemuSystemStateObserver not found");
let clock_observer = observers.match_name::<QemuClockObserver>("clocktime") //TODO not fixed
.expect("QemuClockObserver not found");
let feedbackstate = match state
.named_metadata_mut()
.get_mut::<SystemStateFeedbackState>("systemstate") {
Some(s) => s,
None => {
let n=SystemStateFeedbackState::default();
state.named_metadata_mut().insert(n, "systemstate");
state.named_metadata_mut().get_mut::<SystemStateFeedbackState>("systemstate").unwrap()
}
};
// let feedbackstate = state
// .feedback_states_mut()
// .match_name_mut::<systemstateFeedbackState>("systemstate")
// .unwrap();
// Do Stuff
let mut hasher = DefaultHasher::new();
observer.last_run.hash(&mut hasher);
let somehash = hasher.finish();
let mut is_novel = false;
let mut takes_longer = false;
match feedbackstate.known_traces.get_mut(&somehash) {
None => {
is_novel = true;
feedbackstate.known_traces.insert(somehash,(1,clock_observer.last_runtime(),observer.last_run.len()));
}
Some(s) => {
s.0+=1;
if s.1 < clock_observer.last_runtime() {
s.1 = clock_observer.last_runtime();
takes_longer = true;
}
}
}
if observer.last_run.len() > feedbackstate.longest.len() {
feedbackstate.longest=observer.last_run.clone();
}
self.last_trace = Some(observer.last_run.clone());
// if (!is_novel) { println!("not novel") };
Ok(is_novel | takes_longer)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
let a = self.last_trace.take();
match a {
Some(s) => testcase.metadata_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
None => (),
}
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.last_trace = None;
Ok(())
}
}
impl Named for NovelSystemStateFeedback
{
#[inline]
fn name(&self) -> &str {
"systemstate"
}
}
//=============================
pub fn match_traces(target: &Vec<RefinedFreeRTOSSystemState>, last: &Vec<RefinedFreeRTOSSystemState>) -> bool {
let mut ret = true;
if target.len() > last.len() {return false;}
for i in 0..target.len() {
ret &= target[i].current_task.task_name==last[i].current_task.task_name;
}
ret
}
pub fn match_traces_name(target: &Vec<String>, last: &Vec<RefinedFreeRTOSSystemState>) -> bool {
let mut ret = true;
if target.len() > last.len() {return false;}
for i in 0..target.len() {
ret &= target[i]==last[i].current_task.task_name;
}
ret
}
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct HitSystemStateFeedback
{
target: Option<Vec<String>>,
}
impl<S> Feedback<S> for HitSystemStateFeedback
where
S: UsesInput + HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>
{
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
.expect("QemuSystemStateObserver not found");
// Do Stuff
match &self.target {
Some(s) => {
// #[cfg(debug_assertions)] eprintln!("Hit systemstate Feedback trigger");
Ok(match_traces_name(s, &observer.last_run))
},
None => Ok(false),
}
}
}
impl Named for HitSystemStateFeedback
{
#[inline]
fn name(&self) -> &str {
"hit_systemstate"
}
}
impl HitSystemStateFeedback {
pub fn new(target: Option<Vec<RefinedFreeRTOSSystemState>>) -> Self {
Self {target: target.map(|x| x.into_iter().map(|y| y.current_task.task_name).collect())}
}
}
//=========================== Debugging Feedback
/// A [`Feedback`] meant to dump the system-traces for debugging. Depends on [`QemuSystemStateObserver`]
#[derive(Debug)]
pub struct DumpSystraceFeedback
{
dumpfile: Option<PathBuf>,
dump_metadata: bool,
last_trace: Option<Vec<RefinedFreeRTOSSystemState>>,
}
impl<S> Feedback<S> for DumpSystraceFeedback
where
S: UsesInput + HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>
{
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
.expect("QemuSystemStateObserver not found");
let names : Vec<String> = observer.last_run.iter().map(|x| x.current_task.task_name.clone()).collect();
match &self.dumpfile {
Some(s) => {
std::fs::write(s,ron::to_string(&observer.last_run).expect("Error serializing hashmap")).expect("Can not dump to file");
self.dumpfile = None
},
None => if !self.dump_metadata {println!("{:?}\n{:?}",observer.last_run,names);}
};
if self.dump_metadata {self.last_trace=Some(observer.last_run.clone());}
Ok(!self.dump_metadata)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
if !self.dump_metadata {return Ok(());}
let a = self.last_trace.take();
match a {
Some(s) => testcase.metadata_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
None => (),
}
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.last_trace = None;
Ok(())
}
}
impl Named for DumpSystraceFeedback
{
#[inline]
fn name(&self) -> &str {
"Dumpsystemstate"
}
}
impl DumpSystraceFeedback
{
/// Creates a new [`DumpSystraceFeedback`]
#[must_use]
pub fn new() -> Self {
Self {dumpfile: None, dump_metadata: false, last_trace: None}
}
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
Self {dumpfile: dumpfile, dump_metadata: false, last_trace: None}
}
pub fn metadata_only() -> Self {
Self {dumpfile: None, dump_metadata: true, last_trace: None}
}
}

View File

@ -0,0 +1,122 @@
#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals,deref_nullptr)]
use serde::{Deserialize, Serialize};
// Manual Types
use libafl_qemu::Emulator;
/*========== Start of generated Code =============*/
pub type char_ptr = ::std::os::raw::c_uint;
pub type ListItem_t_ptr = ::std::os::raw::c_uint;
pub type StackType_t_ptr = ::std::os::raw::c_uint;
pub type void_ptr = ::std::os::raw::c_uint;
pub type tskTaskControlBlock_ptr = ::std::os::raw::c_uint;
pub type xLIST_ptr = ::std::os::raw::c_uint;
pub type xLIST_ITEM_ptr = ::std::os::raw::c_uint;
/* automatically generated by rust-bindgen 0.59.2 */
pub type __uint8_t = ::std::os::raw::c_uchar;
pub type __uint16_t = ::std::os::raw::c_ushort;
pub type __uint32_t = ::std::os::raw::c_uint;
pub type StackType_t = u32;
pub type UBaseType_t = ::std::os::raw::c_uint;
pub type TickType_t = u32;
#[repr(C)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
pub struct xLIST_ITEM {
pub xItemValue: TickType_t,
pub pxNext: xLIST_ITEM_ptr,
pub pxPrevious: xLIST_ITEM_ptr,
pub pvOwner: void_ptr,
pub pvContainer: xLIST_ptr,
}
pub type ListItem_t = xLIST_ITEM;
#[repr(C)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
pub struct xMINI_LIST_ITEM {
pub xItemValue: TickType_t,
pub pxNext: xLIST_ITEM_ptr,
pub pxPrevious: xLIST_ITEM_ptr,
}
pub type MiniListItem_t = xMINI_LIST_ITEM;
#[repr(C)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
pub struct xLIST {
pub uxNumberOfItems: UBaseType_t,
pub pxIndex: ListItem_t_ptr,
pub xListEnd: MiniListItem_t,
}
pub type List_t = xLIST;
pub type TaskHandle_t = tskTaskControlBlock_ptr;
pub const eTaskState_eRunning: eTaskState = 0;
pub const eTaskState_eReady: eTaskState = 1;
pub const eTaskState_eBlocked: eTaskState = 2;
pub const eTaskState_eSuspended: eTaskState = 3;
pub const eTaskState_eDeleted: eTaskState = 4;
pub const eTaskState_eInvalid: eTaskState = 5;
pub type eTaskState = ::std::os::raw::c_uint;
#[repr(C)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
pub struct xTASK_STATUS {
pub xHandle: TaskHandle_t,
pub pcTaskName: char_ptr,
pub xTaskNumber: UBaseType_t,
pub eCurrentState: eTaskState,
pub uxCurrentPriority: UBaseType_t,
pub uxBasePriority: UBaseType_t,
pub ulRunTimeCounter: u32,
pub pxStackBase: StackType_t_ptr,
pub usStackHighWaterMark: u16,
}
pub type TaskStatus_t = xTASK_STATUS;
#[repr(C)]
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
pub struct tskTaskControlBlock {
pub pxTopOfStack: StackType_t_ptr,
pub xStateListItem: ListItem_t,
pub xEventListItem: ListItem_t,
pub uxPriority: UBaseType_t,
pub pxStack: StackType_t_ptr,
pub pcTaskName: [::std::os::raw::c_char; 10usize],
pub uxBasePriority: UBaseType_t,
pub uxMutexesHeld: UBaseType_t,
pub ulNotifiedValue: [u32; 1usize],
pub ucNotifyState: [u8; 1usize],
pub ucStaticallyAllocated: u8,
pub ucDelayAborted: u8,
}
pub type tskTCB = tskTaskControlBlock;
pub type TCB_t = tskTCB;
/*========== End of generated Code =============*/
pub trait emu_lookup {
fn lookup(emu: &Emulator, addr: ::std::os::raw::c_uint) -> Self;
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum rtos_struct {
TCB_struct(TCB_t),
List_struct(List_t),
List_Item_struct(ListItem_t),
List_MiniItem_struct(MiniListItem_t),
}
#[macro_export]
macro_rules! impl_emu_lookup {
($struct_name:ident) => {
impl $crate::systemstate::freertos::emu_lookup for $struct_name {
fn lookup(emu: &Emulator, addr: ::std::os::raw::c_uint) -> $struct_name {
let mut tmp : [u8; std::mem::size_of::<$struct_name>()] = [0u8; std::mem::size_of::<$struct_name>()];
unsafe {
emu.read_mem(addr.into(), &mut tmp);
std::mem::transmute::<[u8; std::mem::size_of::<$struct_name>()], $struct_name>(tmp)
}
}
}
};
}
impl_emu_lookup!(TCB_t);
impl_emu_lookup!(List_t);
impl_emu_lookup!(ListItem_t);
impl_emu_lookup!(MiniListItem_t);
impl_emu_lookup!(void_ptr);
impl_emu_lookup!(TaskStatus_t);

View File

@ -0,0 +1,604 @@
use libafl::SerdeAny;
/// Feedbacks organizing SystemStates as a graph
use libafl::inputs::HasBytesVec;
use libafl::bolts::rands::RandomSeed;
use libafl::bolts::rands::StdRand;
use libafl::mutators::Mutator;
use libafl::mutators::MutationResult;
use libafl::prelude::HasTargetBytes;
use libafl::prelude::UsesInput;
use libafl::state::HasNamedMetadata;
use libafl::state::UsesState;
use core::marker::PhantomData;
use libafl::state::HasCorpus;
use libafl::state::HasSolutions;
use libafl::state::HasRand;
use crate::worst::MaxExecsLenFavFactor;
use libafl::schedulers::MinimizerScheduler;
use libafl::bolts::HasRefCnt;
use libafl::bolts::AsSlice;
use libafl::bolts::ownedref::OwnedSlice;
use libafl::inputs::BytesInput;
use std::path::PathBuf;
use crate::clock::QemuClockObserver;
use libafl::corpus::Testcase;
use libafl::bolts::tuples::MatchName;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::hash::Hash;
use libafl::events::EventFirer;
use libafl::state::HasClientPerfMonitor;
use libafl::feedbacks::Feedback;
use libafl::bolts::tuples::Named;
use libafl::Error;
use hashbrown::HashMap;
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
use serde::{Deserialize, Serialize};
use super::RefinedFreeRTOSSystemState;
use super::FreeRTOSSystemStateMetadata;
use super::observers::QemuSystemStateObserver;
use petgraph::prelude::DiGraph;
use petgraph::graph::NodeIndex;
use petgraph::Direction;
use std::cmp::Ordering;
use libafl::bolts::rands::Rand;
//============================= Data Structures
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
pub struct VariantTuple
{
pub start_tick: u64,
pub end_tick: u64,
input_counter: u32,
pub input: Vec<u8>, // in the end any kind of input are bytes, regardless of type and lifetime
}
impl VariantTuple {
fn from(other: &RefinedFreeRTOSSystemState,input: Vec<u8>) -> Self {
VariantTuple{
start_tick: other.start_tick,
end_tick: other.end_tick,
input_counter: other.input_counter,
input: input,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct SysGraphNode
{
base: RefinedFreeRTOSSystemState,
pub variants: Vec<VariantTuple>,
}
impl SysGraphNode {
fn from(base: RefinedFreeRTOSSystemState, input: Vec<u8>) -> Self {
SysGraphNode{variants: vec![VariantTuple::from(&base, input)], base:base }
}
/// unites the variants of this value with another, draining the other if the bases are equal
fn unite(&mut self, other: &mut SysGraphNode) -> bool {
if self!=other {return false;}
self.variants.append(&mut other.variants);
self.variants.dedup();
return true;
}
/// add a Varint from a [`RefinedFreeRTOSSystemState`]
fn unite_raw(&mut self, other: &RefinedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
if &self.base!=other {return false;}
self.variants.push(VariantTuple::from(other, input.clone()));
self.variants.dedup();
return true;
}
/// add a Varint from a [`RefinedFreeRTOSSystemState`], if it's interesting
fn unite_interesting(&mut self, other: &RefinedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
if &self.base!=other {return false;}
let interesting =
self.variants.iter().all(|x| x.end_tick-x.start_tick<other.end_tick-other.start_tick) || // longest variant
self.variants.iter().all(|x| x.end_tick-x.start_tick>other.end_tick-other.start_tick) || // shortest variant
self.variants.iter().all(|x| x.input_counter>other.input_counter) || // longest input
self.variants.iter().all(|x| x.input_counter<other.input_counter); // shortest input
if interesting {
let var = VariantTuple::from(other, input.clone());
self.variants.push(var);
}
return interesting;
}
pub fn get_taskname(&self) -> &str {
&self.base.current_task.task_name
}
pub fn get_input_counts(&self) -> Vec<u32> {
self.variants.iter().map(|x| x.input_counter).collect()
}
}
impl PartialEq for SysGraphNode {
fn eq(&self, other: &SysGraphNode) -> bool {
self.base==other.base
}
}
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct SysGraphMetadata {
pub inner: Vec<NodeIndex>,
indices: Vec<usize>,
tcref: isize,
}
impl SysGraphMetadata {
pub fn new(inner: Vec<NodeIndex>) -> Self{
Self {indices: inner.iter().map(|x| x.index()).collect(), inner: inner, tcref: 0}
}
}
impl AsSlice for SysGraphMetadata {
/// Convert the slice of system-states to a slice of hashes over enumerated states
fn as_slice(&self) -> &[usize] {
self.indices.as_slice()
}
type Entry = usize;
}
impl HasRefCnt for SysGraphMetadata {
fn refcnt(&self) -> isize {
self.tcref
}
fn refcnt_mut(&mut self) -> &mut isize {
&mut self.tcref
}
}
libafl::impl_serdeany!(SysGraphMetadata);
pub type GraphMaximizerCorpusScheduler<CS> =
MinimizerScheduler<CS, MaxExecsLenFavFactor<<CS as UsesState>::State>,SysGraphMetadata>;
//============================= Graph Feedback
/// Improved System State Graph
#[derive(Serialize, Deserialize, Clone, Debug, Default, SerdeAny)]
pub struct SysGraphFeedbackState
{
pub graph: DiGraph<SysGraphNode, ()>,
entrypoint: NodeIndex,
exit: NodeIndex,
name: String,
}
impl SysGraphFeedbackState
{
pub fn new() -> Self {
let mut graph = DiGraph::<SysGraphNode, ()>::new();
let mut entry = SysGraphNode::default();
entry.base.current_task.task_name="Start".to_string();
let mut exit = SysGraphNode::default();
exit.base.current_task.task_name="End".to_string();
let entry = graph.add_node(entry);
let exit = graph.add_node(exit);
Self {graph: graph, entrypoint: entry, exit: exit, name: String::from("SysMap")}
}
fn insert(&mut self, list: Vec<RefinedFreeRTOSSystemState>, input: &Vec<u8>) {
let mut current_index = self.entrypoint;
for n in list {
let mut done = false;
for i in self.graph.neighbors_directed(current_index, Direction::Outgoing) {
if n == self.graph[i].base {
done = true;
current_index = i;
break;
}
}
if !done {
let j = self.graph.add_node(SysGraphNode::from(n,input.clone()));
self.graph.add_edge(current_index, j, ());
current_index = j;
}
}
}
/// Try adding a system state path from a [Vec<RefinedFreeRTOSSystemState>], return true if the path was interesting
fn update(&mut self, list: &Vec<RefinedFreeRTOSSystemState>, input: &Vec<u8>) -> (bool, Vec<NodeIndex>) {
let mut current_index = self.entrypoint;
let mut novel = false;
let mut trace : Vec<NodeIndex> = vec![current_index];
for n in list {
let mut matching : Option<NodeIndex> = None;
for i in self.graph.neighbors_directed(current_index, Direction::Outgoing) {
let tmp = &self.graph[i];
if n == &tmp.base {
matching = Some(i);
current_index = i;
break;
}
}
match matching {
None => {
novel = true;
let j = self.graph.add_node(SysGraphNode::from(n.clone(),input.clone()));
self.graph.add_edge(current_index, j, ());
current_index = j;
},
Some(i) => {
novel |= self.graph[i].unite_interesting(&n, input);
}
}
trace.push(current_index);
}
self.graph.update_edge(current_index, self.exit, ()); // every path ends in the exit noded
return (novel, trace);
}
}
impl Named for SysGraphFeedbackState
{
#[inline]
fn name(&self) -> &str {
&self.name
}
}
impl SysGraphFeedbackState
{
fn reset(&mut self) -> Result<(), Error> {
self.graph.clear();
let mut entry = SysGraphNode::default();
entry.base.current_task.task_name="Start".to_string();
let mut exit = SysGraphNode::default();
exit.base.current_task.task_name="End".to_string();
self.entrypoint = self.graph.add_node(entry);
self.exit = self.graph.add_node(exit);
Ok(())
}
}
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct SysMapFeedback
{
name: String,
last_trace: Option<Vec<NodeIndex>>,
}
impl SysMapFeedback {
pub fn new() -> Self {
Self {name: String::from("SysMapFeedback"), last_trace: None }
}
}
impl<S> Feedback<S> for SysMapFeedback
where
S: UsesInput + HasClientPerfMonitor + HasNamedMetadata,
S::Input: HasTargetBytes,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
_manager: &mut EM,
_input: &S::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
.expect("QemuSystemStateObserver not found");
let feedbackstate = match state
.named_metadata_mut()
.get_mut::<SysGraphFeedbackState>("SysMap") {
Some(s) => s,
None => {
let n=SysGraphFeedbackState::default();
state.named_metadata_mut().insert(n, "SysMap");
state.named_metadata_mut().get_mut::<SysGraphFeedbackState>("SysMap").unwrap()
}
};
let ret = feedbackstate.update(&observer.last_run, &observer.last_input);
self.last_trace = Some(ret.1);
Ok(ret.0)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
let a = self.last_trace.take();
match a {
Some(s) => testcase.metadata_mut().insert(SysGraphMetadata::new(s)),
None => (),
}
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.last_trace = None;
Ok(())
}
}
impl Named for SysMapFeedback
{
#[inline]
fn name(&self) -> &str {
&self.name
}
}
//============================= Mutators
//=============================== Snippets
// pub struct RandGraphSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// phantom: PhantomData<(I, S)>,
// }
// impl<I, S> RandGraphSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// pub fn new() -> Self {
// RandGraphSnippetMutator{phantom: PhantomData}
// }
// }
// impl<I, S> Mutator<I, S> for RandGraphSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// fn mutate(
// &mut self,
// state: &mut S,
// input: &mut I,
// _stage_idx: i32
// ) -> Result<MutationResult, Error>
// {
// // need our own random generator, because borrowing rules
// let mut myrand = StdRand::new();
// let tmp = &mut state.rand_mut();
// myrand.set_seed(tmp.next());
// drop(tmp);
// let feedbackstate = state
// .feedback_states()
// .match_name::<SysGraphFeedbackState>("SysMap")
// .unwrap();
// let g = &feedbackstate.graph;
// let tmp = state.metadata().get::<SysGraphMetadata>();
// if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
// return Ok(MutationResult::Skipped);
// }
// let trace =tmp.expect("SysGraphMetadata not found");
// // follow the path, extract snippets from last reads, find common snippets.
// // those are likley keys parts. choose random parts from other sibling traces
// let sibling_inputs : Vec<&Vec<u8>>= g[*trace.inner.last().unwrap()].variants.iter().map(|x| &x.input).collect();
// let mut snippet_collector = vec![];
// let mut per_input_counters = HashMap::<&Vec<u8>,usize>::new(); // ugly workaround to track multiple inputs
// for t in &trace.inner {
// let node = &g[*t];
// let mut per_node_snippets = HashMap::<&Vec<u8>,&[u8]>::new();
// for v in &node.variants {
// match per_input_counters.get_mut(&v.input) {
// None => {
// if sibling_inputs.iter().any(|x| *x==&v.input) { // only collect info about siblin inputs from target
// per_input_counters.insert(&v.input, v.input_counter.try_into().unwrap());
// }
// },
// Some(x) => {
// let x_u = *x;
// if x_u<v.input_counter as usize {
// *x=v.input_counter as usize;
// per_node_snippets.insert(&v.input,&v.input[x_u..v.input_counter as usize]);
// }
// }
// }
// }
// snippet_collector.push(per_node_snippets);
// }
// let mut new_input : Vec<u8> = vec![];
// for c in snippet_collector {
// new_input.extend_from_slice(myrand.choose(c).1);
// }
// for i in new_input.iter().enumerate() {
// input.bytes_mut()[i.0]=*i.1;
// }
// Ok(MutationResult::Mutated)
// }
// fn post_exec(
// &mut self,
// _state: &mut S,
// _stage_idx: i32,
// _corpus_idx: Option<usize>
// ) -> Result<(), Error> {
// Ok(())
// }
// }
// impl<I, S> Named for RandGraphSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// fn name(&self) -> &str {
// "RandGraphSnippetMutator"
// }
// }
// //=============================== Snippets
// pub struct RandInputSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// phantom: PhantomData<(I, S)>,
// }
// impl<I, S> RandInputSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// pub fn new() -> Self {
// RandInputSnippetMutator{phantom: PhantomData}
// }
// }
// impl<I, S> Mutator<I, S> for RandInputSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// fn mutate(
// &mut self,
// state: &mut S,
// input: &mut I,
// _stage_idx: i32
// ) -> Result<MutationResult, Error>
// {
// // need our own random generator, because borrowing rules
// let mut myrand = StdRand::new();
// let tmp = &mut state.rand_mut();
// myrand.set_seed(tmp.next());
// drop(tmp);
// let feedbackstate = state
// .feedback_states()
// .match_name::<SysGraphFeedbackState>("SysMap")
// .unwrap();
// let g = &feedbackstate.graph;
// let tmp = state.metadata().get::<SysGraphMetadata>();
// if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
// return Ok(MutationResult::Skipped);
// }
// let trace = tmp.expect("SysGraphMetadata not found");
// let mut collection : Vec<Vec<u8>> = Vec::new();
// let mut current_pointer : usize = 0;
// for t in &trace.inner {
// let node = &g[*t];
// for v in &node.variants {
// if v.input == input.bytes() {
// if v.input_counter > current_pointer.try_into().unwrap() {
// collection.push(v.input[current_pointer..v.input_counter as usize].to_owned());
// current_pointer = v.input_counter as usize;
// }
// break;
// }
// }
// }
// let index_to_mutate = myrand.below(collection.len() as u64) as usize;
// for i in 0..collection[index_to_mutate].len() {
// collection[index_to_mutate][i] = myrand.below(0xFF) as u8;
// }
// for i in collection.concat().iter().enumerate() {
// input.bytes_mut()[i.0]=*i.1;
// }
// Ok(MutationResult::Mutated)
// }
// fn post_exec(
// &mut self,
// _state: &mut S,
// _stage_idx: i32,
// _corpus_idx: Option<usize>
// ) -> Result<(), Error> {
// Ok(())
// }
// }
// impl<I, S> Named for RandInputSnippetMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// fn name(&self) -> &str {
// "RandInputSnippetMutator"
// }
// }
// //=============================== Suffix
// pub struct RandGraphSuffixMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// phantom: PhantomData<(I, S)>,
// }
// impl<I, S> RandGraphSuffixMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// pub fn new() -> Self {
// RandGraphSuffixMutator{phantom: PhantomData}
// }
// }
// impl<I, S> Mutator<I, S> for RandGraphSuffixMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// fn mutate(
// &mut self,
// state: &mut S,
// input: &mut I,
// _stage_idx: i32
// ) -> Result<MutationResult, Error>
// {
// // need our own random generator, because borrowing rules
// let mut myrand = StdRand::new();
// let tmp = &mut state.rand_mut();
// myrand.set_seed(tmp.next());
// drop(tmp);
// let feedbackstate = state
// .feedback_states()
// .match_name::<SysGraphFeedbackState>("SysMap")
// .unwrap();
// let g = &feedbackstate.graph;
// let tmp = state.metadata().get::<SysGraphMetadata>();
// if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
// return Ok(MutationResult::Skipped);
// }
// let trace =tmp.expect("SysGraphMetadata not found");
// // follow the path, extract snippets from last reads, find common snippets.
// // those are likley keys parts. choose random parts from other sibling traces
// let inp_c_end = g[*trace.inner.last().unwrap()].base.input_counter;
// let mut num_to_reverse = myrand.below(trace.inner.len().try_into().unwrap());
// for t in trace.inner.iter().rev() {
// let int_c_prefix = g[*t].base.input_counter;
// if int_c_prefix < inp_c_end {
// num_to_reverse-=1;
// if num_to_reverse<=0 {
// let mut new_input=input.bytes()[..(int_c_prefix as usize)].to_vec();
// let mut ext : Vec<u8> = (int_c_prefix..inp_c_end).map(|_| myrand.next().to_le_bytes()).flatten().collect();
// new_input.append(&mut ext);
// for i in new_input.iter().enumerate() {
// if input.bytes_mut().len()>i.0 {
// input.bytes_mut()[i.0]=*i.1;
// }
// else { break };
// }
// break;
// }
// }
// }
// Ok(MutationResult::Mutated)
// }
// fn post_exec(
// &mut self,
// _state: &mut S,
// _stage_idx: i32,
// _corpus_idx: Option<usize>
// ) -> Result<(), Error> {
// Ok(())
// }
// }
// impl<I, S> Named for RandGraphSuffixMutator<I, S>
// where
// I: Input + HasBytesVec,
// S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
// {
// fn name(&self) -> &str {
// "RandGraphSuffixMutator"
// }
// }

View File

@ -0,0 +1,209 @@
use std::cell::UnsafeCell;
use std::io::Write;
use std::ops::Range;
use libafl::prelude::UsesInput;
use libafl_qemu::Emulator;
use libafl_qemu::GuestAddr;
use libafl_qemu::QemuHooks;
use libafl_qemu::edges::QemuEdgesMapMetadata;
use libafl_qemu::emu;
use libafl_qemu::hooks;
use crate::systemstate::RawFreeRTOSSystemState;
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
use crate::systemstate::NUM_PRIOS;
use super::freertos::TCB_t;
use super::freertos::rtos_struct::List_Item_struct;
use super::freertos::rtos_struct::*;
use super::freertos;
use libafl_qemu::{
helper::{QemuHelper, QemuHelperTuple},
// edges::SAVED_JUMP,
};
//============================= Struct definitions
pub static mut INTR_OFFSET : Option<u64> = None;
pub static mut INTR_DONE : bool = true;
// only used when inputs are injected
pub static mut NEXT_INPUT : Vec<u8> = Vec::new();
//============================= Qemu Helper
/// A Qemu Helper with reads FreeRTOS specific structs from Qemu whenever certain syscalls occur, also inject inputs
#[derive(Debug)]
pub struct QemuSystemStateHelper {
kerneladdr: u32,
tcb_addr: u32,
ready_queues: u32,
input_counter: Option<u64>,
app_range: Range<u32>,
}
impl QemuSystemStateHelper {
#[must_use]
pub fn new(
kerneladdr: u32,
tcb_addr: u32,
ready_queues: u32,
input_counter: Option<u64>,
app_range: Range<u32>,
) -> Self {
QemuSystemStateHelper {
kerneladdr,
tcb_addr: tcb_addr,
ready_queues: ready_queues,
input_counter: input_counter,
app_range,
}
}
}
impl<S> QemuHelper<S> for QemuSystemStateHelper
where
S: UsesInput,
{
fn first_exec<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
where
QT: QemuHelperTuple<S>,
{
_hooks.instruction(self.kerneladdr, exec_syscall_hook::<QT, S>, false);
#[cfg(feature = "trace_abbs")]
_hooks.jmps(Some(gen_jmp_is_syscall::<QT, S>), Some(trace_api_call::<QT, S>));
}
// TODO: refactor duplicate code
fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {
unsafe {
CURRENT_SYSTEMSTATE_VEC.clear();
let p = LAST_API_CALL.with(|x| x.get());
*p = None;
}
}
fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input) {
trigger_collection(emulator, self)
}
}
#[inline]
fn trigger_collection(emulator: &Emulator, h: &QemuSystemStateHelper) {
let listbytes : u32 = u32::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
let mut systemstate = RawFreeRTOSSystemState::default();
unsafe {
// TODO: investigate why can_do_io is not set sometimes, as this is just a workaround
let c = emulator.cpu_from_index(0);
let can_do_io = (*c.raw_ptr()).can_do_io;
(*c.raw_ptr()).can_do_io = 1;
systemstate.qemu_tick = emu::icount_get_raw();
(*c.raw_ptr()).can_do_io = can_do_io;
}
let mut buf : [u8; 4] = [0,0,0,0];
match h.input_counter {
Some(s) => unsafe { emulator.read_phys_mem(s, &mut buf); },
None => (),
};
systemstate.input_counter = u32::from_le_bytes(buf);
let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr);
if curr_tcb_addr == 0 {
return;
};
systemstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
unsafe {
LAST_API_CALL.with(|x|
match *x.get() {
Some(s) => {
systemstate.last_pc = Some(s.0 as u64);
},
None => (),
}
);
}
// println!("{:?}",std::str::from_utf8(&current_tcb.pcTaskName));
for i in 0..NUM_PRIOS {
let target : u32 = listbytes*u32::try_from(i).unwrap()+h.ready_queues;
systemstate.prio_ready_lists[i] = freertos::emu_lookup::lookup(emulator, target);
// println!("List at {}: {:?}",target, systemstate.prio_ready_lists[i]);
let mut next_index = systemstate.prio_ready_lists[i].pxIndex;
for _j in 0..systemstate.prio_ready_lists[i].uxNumberOfItems {
// always jump over the xListEnd marker
if (target..target+listbytes).contains(&next_index) {
let next_item : freertos::MiniListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
let new_next_index=next_item.pxNext;
systemstate.dumping_ground.insert(next_index,List_MiniItem_struct(next_item));
next_index = new_next_index;
}
let next_item : freertos::ListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
// println!("Item at {}: {:?}",next_index,next_item);
assert_eq!(next_item.pvContainer,target);
let new_next_index=next_item.pxNext;
let next_tcb : TCB_t= freertos::emu_lookup::lookup(emulator,next_item.pvOwner);
// println!("TCB at {}: {:?}",next_item.pvOwner,next_tcb);
systemstate.dumping_ground.insert(next_item.pvOwner,TCB_struct(next_tcb.clone()));
systemstate.dumping_ground.insert(next_index,List_Item_struct(next_item));
next_index=new_next_index;
}
// Handle edge case where the end marker was not included yet
if (target..target+listbytes).contains(&next_index) {
let next_item : freertos::MiniListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
systemstate.dumping_ground.insert(next_index,List_MiniItem_struct(next_item));
}
}
unsafe { CURRENT_SYSTEMSTATE_VEC.push(systemstate); }
}
pub fn exec_syscall_hook<QT, S>(
hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>,
_pc: u32,
)
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
let emulator = hooks.emulator();
let h = hooks.helpers().match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
trigger_collection(emulator, h);
}
thread_local!(static LAST_API_CALL : UnsafeCell<Option<(GuestAddr,GuestAddr)>> = UnsafeCell::new(None));
pub fn gen_jmp_is_syscall<QT, S>(
hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>,
src: GuestAddr,
dest: GuestAddr,
) -> Option<u64>
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
if let Some(h) = hooks.helpers().match_first_type::<QemuSystemStateHelper>() {
if h.app_range.contains(&src) && !h.app_range.contains(&dest) {
// println!("New jmp {:x} {:x}", src, dest);
return Some(1);
}
}
return None;
}
pub fn trace_api_call<QT, S>(
_hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>,
src: GuestAddr, dest: GuestAddr, id: u64
)
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
unsafe {
let p = LAST_API_CALL.with(|x| x.get());
*p = Some((src,dest));
// print!("*");
}
}

View File

@ -0,0 +1,167 @@
//! systemstate referes to the State of a FreeRTOS fuzzing target
use std::collections::hash_map::DefaultHasher;
use libafl::bolts::HasRefCnt;
use libafl::bolts::AsSlice;
use std::hash::Hasher;
use std::hash::Hash;
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use freertos::TCB_t;
pub mod freertos;
pub mod helpers;
pub mod observers;
pub mod feedbacks;
pub mod graph;
pub mod schedulers;
// #[cfg(feature = "fuzz_interrupt")]
// pub const IRQ_INPUT_BYTES_NUMBER : u32 = 2; // Offset for interrupt bytes
// #[cfg(not(feature = "fuzz_interrupt"))]
// pub const IRQ_INPUT_BYTES_NUMBER : u32 = 0; // Offset for interrupt bytes
// pub const IRQ_INPUT_OFFSET : u32 = 347780; // Tick offset for app code start
// Constants
const NUM_PRIOS: usize = 5;
//============================= Struct definitions
/// Raw info Dump from Qemu
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct RawFreeRTOSSystemState {
qemu_tick: u64,
current_tcb: TCB_t,
prio_ready_lists: [freertos::List_t; NUM_PRIOS],
dumping_ground: HashMap<u32,freertos::rtos_struct>,
input_counter: u32,
last_pc: Option<u64>,
}
/// List of system state dumps from QemuHelpers
static mut CURRENT_SYSTEMSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![];
/// A reduced version of freertos::TCB_t
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct RefinedTCB {
pub task_name: String,
pub priority: u32,
pub base_priority: u32,
mutexes_held: u32,
notify_value: u32,
notify_state: u8,
}
impl Hash for RefinedTCB {
fn hash<H: Hasher>(&self, state: &mut H) {
self.task_name.hash(state);
self.priority.hash(state);
self.mutexes_held.hash(state);
#[cfg(not(feature = "no_hash_state"))]
self.notify_state.hash(state);
// self.notify_value.hash(state);
}
}
impl RefinedTCB {
pub fn from_tcb(input: &TCB_t) -> Self {
unsafe {
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
Self {
task_name: name,
priority: input.uxPriority,
base_priority: input.uxBasePriority,
mutexes_held: input.uxMutexesHeld,
notify_value: input.ulNotifiedValue[0],
notify_state: input.ucNotifyState[0],
}
}
}
pub fn from_tcb_owned(input: TCB_t) -> Self {
unsafe {
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
Self {
task_name: name,
priority: input.uxPriority,
base_priority: input.uxBasePriority,
mutexes_held: input.uxMutexesHeld,
notify_value: input.ulNotifiedValue[0],
notify_state: input.ucNotifyState[0],
}
}
}
}
/// Refined information about the states an execution transitioned between
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct RefinedFreeRTOSSystemState {
pub start_tick: u64,
pub end_tick: u64,
last_pc: Option<u64>,
input_counter: u32,
pub current_task: RefinedTCB,
ready_list_after: Vec<RefinedTCB>,
}
impl PartialEq for RefinedFreeRTOSSystemState {
fn eq(&self, other: &Self) -> bool {
self.current_task == other.current_task && self.ready_list_after == other.ready_list_after &&
self.last_pc == other.last_pc
}
}
impl Hash for RefinedFreeRTOSSystemState {
fn hash<H: Hasher>(&self, state: &mut H) {
self.current_task.hash(state);
self.ready_list_after.hash(state);
// self.last_pc.hash(state);
}
}
impl RefinedFreeRTOSSystemState {
fn get_time(&self) -> u64 {
self.end_tick-self.start_tick
}
}
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct FreeRTOSSystemStateMetadata {
pub inner: Vec<RefinedFreeRTOSSystemState>,
trace_length: usize,
indices: Vec<usize>, // Hashed enumeration of States
tcref: isize,
}
impl FreeRTOSSystemStateMetadata {
pub fn new(inner: Vec<RefinedFreeRTOSSystemState>) -> Self{
let tmp = inner.iter().enumerate().map(|x| compute_hash(x) as usize).collect();
Self {trace_length: inner.len(), inner: inner, indices: tmp, tcref: 0}
}
}
pub fn compute_hash<T>(obj: T) -> u64
where
T: Hash
{
let mut s = DefaultHasher::new();
obj.hash(&mut s);
s.finish()
}
impl AsSlice for FreeRTOSSystemStateMetadata {
/// Convert the slice of system-states to a slice of hashes over enumerated states
fn as_slice(&self) -> &[usize] {
self.indices.as_slice()
}
type Entry = usize;
}
impl HasRefCnt for FreeRTOSSystemStateMetadata {
fn refcnt(&self) -> isize {
self.tcref
}
fn refcnt_mut(&mut self) -> &mut isize {
&mut self.tcref
}
}
libafl::impl_serdeany!(FreeRTOSSystemStateMetadata);

View File

@ -0,0 +1,133 @@
// use crate::systemstate::IRQ_INPUT_BYTES_NUMBER;
use libafl::prelude::{ExitKind, AsSlice};
use libafl::{inputs::HasTargetBytes, prelude::UsesInput};
use libafl::bolts::HasLen;
use libafl::bolts::tuples::Named;
use libafl::Error;
use libafl::observers::Observer;
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use super::{
CURRENT_SYSTEMSTATE_VEC,
RawFreeRTOSSystemState,
RefinedTCB,
RefinedFreeRTOSSystemState,
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
};
//============================= Observer
/// The Qemusystemstate Observer retrieves the systemstate
/// that will get updated by the target.
#[derive(Serialize, Deserialize, Debug, Default)]
#[allow(clippy::unsafe_derive_deserialize)]
pub struct QemuSystemStateObserver
{
pub last_run: Vec<RefinedFreeRTOSSystemState>,
pub last_input: Vec<u8>,
name: String,
}
impl<S> Observer<S> for QemuSystemStateObserver
where
S: UsesInput,
S::Input : HasTargetBytes,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
unsafe {CURRENT_SYSTEMSTATE_VEC.clear(); }
Ok(())
}
#[inline]
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
unsafe {self.last_run = refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC);}
self.last_input=_input.target_bytes().as_slice().to_owned();
Ok(())
}
}
impl Named for QemuSystemStateObserver
{
#[inline]
fn name(&self) -> &str {
self.name.as_str()
}
}
impl HasLen for QemuSystemStateObserver
{
#[inline]
fn len(&self) -> usize {
self.last_run.len()
}
}
impl QemuSystemStateObserver {
pub fn new() -> Self {
Self{last_run: vec![], last_input: vec![], name: "systemstate".to_string()}
}
}
//============================= Parsing helpers
/// Parse a List_t containing TCB_t into Vec<TCB_t> from cache. Consumes the elements from cache
fn tcb_list_to_vec_cached(list: List_t, dump: &mut HashMap<u32,rtos_struct>) -> Vec<TCB_t>
{
let mut ret : Vec<TCB_t> = Vec::new();
if list.uxNumberOfItems == 0 {return ret;}
let last_list_item = match dump.remove(&list.pxIndex).expect("List_t entry was not in Hashmap") {
List_Item_struct(li) => li,
List_MiniItem_struct(mli) => match dump.remove(&mli.pxNext).expect("MiniListItem pointer invaild") {
List_Item_struct(li) => li,
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
},
_ => panic!("List_t entry was not a ListItem"),
};
let mut next_index = last_list_item.pxNext;
let last_tcb = match dump.remove(&last_list_item.pvOwner).expect("ListItem Owner not in Hashmap") {
TCB_struct(t) => t,
_ => panic!("List content does not equal type"),
};
for _ in 0..list.uxNumberOfItems-1 {
let next_list_item = match dump.remove(&next_index).expect("List_t entry was not in Hashmap") {
List_Item_struct(li) => li,
List_MiniItem_struct(mli) => match dump.remove(&mli.pxNext).expect("MiniListItem pointer invaild") {
List_Item_struct(li) => li,
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
},
_ => panic!("List_t entry was not a ListItem"),
};
match dump.remove(&next_list_item.pvOwner).expect("ListItem Owner not in Hashmap") {
TCB_struct(t) => {ret.push(t)},
_ => panic!("List content does not equal type"),
}
next_index=next_list_item.pxNext;
}
ret.push(last_tcb);
ret
}
/// Drains a List of raw SystemStates to produce a refined trace
fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> Vec<RefinedFreeRTOSSystemState> {
let mut ret = Vec::<RefinedFreeRTOSSystemState>::new();
let mut start_tick : u64 = 0;
for mut i in input.drain(..) {
let mut collector = Vec::<RefinedTCB>::new();
for j in i.prio_ready_lists.into_iter().rev() {
let mut tmp = tcb_list_to_vec_cached(j,&mut i.dumping_ground).iter().map(|x| RefinedTCB::from_tcb(x)).collect();
collector.append(&mut tmp);
}
ret.push(RefinedFreeRTOSSystemState {
current_task: RefinedTCB::from_tcb_owned(i.current_tcb),
start_tick: start_tick,
end_tick: i.qemu_tick,
ready_list_after: collector,
input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
last_pc: i.last_pc,
});
start_tick=i.qemu_tick;
}
return ret;
}

View File

@ -0,0 +1,267 @@
//! The Minimizer schedulers are a family of corpus schedulers that feed the fuzzer
//! with testcases only from a subset of the total corpus.
use core::{marker::PhantomData};
use std::{cmp::{max, min}, mem::swap, borrow::BorrowMut};
use serde::{Deserialize, Serialize};
use libafl::{
bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt},
corpus::{Corpus, Testcase},
inputs::UsesInput,
schedulers::{Scheduler, TestcaseScore, minimizer::DEFAULT_SKIP_NON_FAVORED_PROB },
state::{HasCorpus, HasMetadata, HasRand, UsesState, State},
Error, SerdeAny, prelude::HasLen,
};
use crate::worst::MaxTimeFavFactor;
use super::FreeRTOSSystemStateMetadata;
/// A state metadata holding a map of favoreds testcases for each map entry
#[derive(Debug, Serialize, Deserialize, SerdeAny, Default)]
pub struct LongestTracesMetadata {
/// map index -> corpus index
pub max_trace_length: usize,
}
impl LongestTracesMetadata {
fn new(l : usize) -> Self {
Self {max_trace_length: l}
}
}
/// The [`MinimizerScheduler`] employs a genetic algorithm to compute a subset of the
/// corpus that exercise all the requested features (e.g. all the coverage seen so far)
/// prioritizing [`Testcase`]`s` using [`TestcaseScore`]
#[derive(Debug, Clone)]
pub struct LongestTraceScheduler<CS> {
base: CS,
skip_non_favored_prob: u64,
}
impl<CS> UsesState for LongestTraceScheduler<CS>
where
CS: UsesState,
{
type State = CS::State;
}
impl<CS> Scheduler for LongestTraceScheduler<CS>
where
CS: Scheduler,
CS::State: HasCorpus + HasMetadata + HasRand,
{
/// Add an entry to the corpus and return its index
fn on_add(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> {
let l = state.corpus()
.get(idx)?
.borrow()
.metadata()
.get::<FreeRTOSSystemStateMetadata>().map_or(0, |x| x.trace_length);
self.get_update_trace_length(state,l);
self.base.on_add(state, idx)
}
/// Replaces the testcase at the given idx
fn on_replace(
&self,
state: &mut CS::State,
idx: usize,
testcase: &Testcase<<CS::State as UsesInput>::Input>,
) -> Result<(), Error> {
let l = state.corpus()
.get(idx)?
.borrow()
.metadata()
.get::<FreeRTOSSystemStateMetadata>().map_or(0, |x| x.trace_length);
self.get_update_trace_length(state, l);
self.base.on_replace(state, idx, testcase)
}
/// Removes an entry from the corpus, returning M if M was present.
fn on_remove(
&self,
state: &mut CS::State,
idx: usize,
testcase: &Option<Testcase<<CS::State as UsesInput>::Input>>,
) -> Result<(), Error> {
self.base.on_remove(state, idx, testcase)?;
Ok(())
}
/// Gets the next entry
fn next(&self, state: &mut CS::State) -> Result<usize, Error> {
let mut idx = self.base.next(state)?;
while {
let l = state.corpus()
.get(idx)?
.borrow()
.metadata()
.get::<FreeRTOSSystemStateMetadata>().map_or(0, |x| x.trace_length);
let m = self.get_update_trace_length(state,l);
state.rand_mut().below(m) > l as u64
} && state.rand_mut().below(100) < self.skip_non_favored_prob
{
idx = self.base.next(state)?;
}
Ok(idx)
}
}
impl<CS> LongestTraceScheduler<CS>
where
CS: Scheduler,
CS::State: HasCorpus + HasMetadata + HasRand,
{
pub fn get_update_trace_length(&self, state: &mut CS::State, par: usize) -> u64 {
// Create a new top rated meta if not existing
if let Some(td) = state.metadata_mut().get_mut::<LongestTracesMetadata>() {
let m = max(td.max_trace_length, par);
td.max_trace_length = m;
m as u64
} else {
state.add_metadata(LongestTracesMetadata::new(par));
par as u64
}
}
pub fn new(base: CS) -> Self {
Self {
base,
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
}
}
}
//==========================================================================================
/// A state metadata holding a map of favoreds testcases for each map entry
#[derive(Debug, Serialize, Deserialize, SerdeAny, Default)]
pub struct GeneticMetadata {
pub current_gen: Vec<(usize, f64)>,
pub current_cursor: usize,
pub next_gen: Vec<(usize, f64)>,
pub gen: usize
}
impl GeneticMetadata {
fn new(current_gen: Vec<(usize, f64)>, next_gen: Vec<(usize, f64)>) -> Self {
Self {current_gen, current_cursor: 0, next_gen, gen: 0}
}
}
#[derive(Debug, Clone)]
pub struct GenerationScheduler<S> {
phantom: PhantomData<S>,
gen_size: usize,
}
impl<S> UsesState for GenerationScheduler<S>
where
S: UsesInput,
{
type State = S;
}
impl<S> Scheduler for GenerationScheduler<S>
where
S: HasCorpus + HasMetadata,
S::Input: HasLen,
{
/// get first element in current gen,
/// if current_gen is empty, swap lists, sort by FavFactor, take top k and return first
fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
let mut to_remove : Vec<(usize, f64)> = vec![];
let mut to_return : usize = 0;
let c = state.corpus().count();
let gm = state.metadata_mut().get_mut::<GeneticMetadata>().expect("Corpus Scheduler empty");
// println!("index: {} curr: {:?} next: {:?} gen: {} corp: {}", gm.current_cursor, gm.current_gen.len(), gm.next_gen.len(), gm.gen,
// c);
match gm.current_gen.get(gm.current_cursor) {
Some(c) => {
gm.current_cursor+=1;
// println!("normal next: {}", (*c).0);
return Ok((*c).0)
},
None => {
swap(&mut to_remove, &mut gm.current_gen);
swap(&mut gm.next_gen, &mut gm.current_gen);
gm.current_gen.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
// gm.current_gen.reverse();
if gm.current_gen.len() == 0 {panic!("Corpus is empty");}
let d : Vec<(usize, f64)> = gm.current_gen.drain(min(gm.current_gen.len(), self.gen_size)..).collect();
to_remove.extend(d);
// move all indices to the left, since all other indices will be deleted
gm.current_gen.sort_by(|a,b| a.0.cmp(&(*b).0)); // in order of the corpus index
for i in 0..gm.current_gen.len() {
gm.current_gen[i] = (i, gm.current_gen[i].1);
}
to_return = gm.current_gen.get(0).unwrap().0;
gm.current_cursor=1;
gm.gen+=1;
}
};
// removing these elements will move all indices left by to_remove.len()
to_remove.sort_by(|x,y| x.0.cmp(&(*y).0));
to_remove.reverse();
for i in to_remove {
state.corpus_mut().remove(i.0).unwrap();
}
// println!("switch next: {to_return}");
return Ok(to_return);
}
/// Add the new input to the next generation
fn on_add(
&self,
state: &mut Self::State,
idx: usize
) -> Result<(), Error> {
// println!("On Add {idx}");
let mut tc = state.corpus_mut().get(idx).unwrap().borrow_mut().clone();
let ff = MaxTimeFavFactor::compute(&mut tc, state).unwrap();
if let Some(gm) = state.metadata_mut().get_mut::<GeneticMetadata>() {
gm.next_gen.push((idx,ff));
} else {
state.add_metadata(GeneticMetadata::new(vec![], vec![(idx,ff)]));
}
Ok(())
}
fn on_replace(
&self,
_state: &mut Self::State,
_idx: usize,
_prev: &Testcase<<Self::State as UsesInput>::Input>
) -> Result<(), Error> {
// println!("On Replace {_idx}");
Ok(())
}
fn on_remove(
&self,
state: &mut Self::State,
idx: usize,
_testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>
) -> Result<(), Error> {
// println!("On Remove {idx}");
if let Some(gm) = state.metadata_mut().get_mut::<GeneticMetadata>() {
gm.next_gen = gm.next_gen.drain(..).into_iter().filter(|x| (*x).0 != idx).collect::<Vec<(usize, f64)>>();
gm.current_gen = gm.current_gen.drain(..).into_iter().filter(|x| (*x).0 != idx).collect::<Vec<(usize, f64)>>();
} else {
state.add_metadata(GeneticMetadata::new(vec![], vec![]));
}
Ok(())
}
}
impl<S> GenerationScheduler<S>
{
pub fn new() -> Self {
Self {
phantom: PhantomData,
gen_size: 100,
}
}
}

381
fuzzers/FRET/src/worst.rs Normal file
View File

@ -0,0 +1,381 @@
use core::fmt::Debug;
use core::cmp::Ordering::{Greater,Less,Equal};
use libafl::inputs::BytesInput;
use libafl::inputs::HasTargetBytes;
use libafl::feedbacks::MapIndexesMetadata;
use libafl::corpus::Testcase;
use libafl::prelude::{UsesInput, AsSlice};
use core::marker::PhantomData;
use libafl::schedulers::{MinimizerScheduler, TestcaseScore};
use std::path::PathBuf;
use std::fs;
use hashbrown::{HashMap};
use libafl::observers::ObserversTuple;
use libafl::executors::ExitKind;
use libafl::events::EventFirer;
use libafl::state::{HasClientPerfMonitor, HasCorpus, UsesState};
use libafl::inputs::Input;
use libafl::feedbacks::Feedback;
use libafl::state::HasMetadata;
use libafl_qemu::edges::QemuEdgesMapMetadata;
use libafl::observers::MapObserver;
use serde::{Deserialize, Serialize};
use std::cmp;
use libafl::{
bolts::{
tuples::Named,
HasLen,
},
observers::Observer,
Error,
};
use crate::clock::QemuClockObserver;
use crate::systemstate::FreeRTOSSystemStateMetadata;
//=========================== Scheduler
pub type TimeMaximizerCorpusScheduler<CS> =
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>, MapIndexesMetadata>;
/// Multiply the testcase size with the execution time.
/// This favors small and quick testcases.
#[derive(Debug, Clone)]
pub struct MaxTimeFavFactor<S>
where
S: HasCorpus + HasMetadata,
S::Input: HasLen,
{
phantom: PhantomData<S>,
}
impl<S> TestcaseScore<S> for MaxTimeFavFactor<S>
where
S: HasCorpus + HasMetadata,
S::Input: HasLen,
{
fn compute(entry: &mut Testcase<<S as UsesInput>::Input>, state: &S) -> Result<f64, Error> {
// TODO maybe enforce entry.exec_time().is_some()
let et = entry.exec_time().expect("testcase.exec_time is needed for scheduler");
let tns : i64 = et.as_nanos().try_into().expect("failed to convert time");
Ok(-tns as f64)
}
}
pub type LenTimeMaximizerCorpusScheduler<CS> =
MinimizerScheduler<CS, MaxExecsLenFavFactor<<CS as UsesState>::State>, MapIndexesMetadata>;
pub type TimeStateMaximizerCorpusScheduler<CS> =
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>, FreeRTOSSystemStateMetadata>;
/// Multiply the testcase size with the execution time.
/// This favors small and quick testcases.
#[derive(Debug, Clone)]
pub struct MaxExecsLenFavFactor<S>
where
S: HasCorpus + HasMetadata,
S::Input: HasLen,
{
phantom: PhantomData<S>,
}
impl<S> TestcaseScore<S> for MaxExecsLenFavFactor<S>
where
S: HasCorpus + HasMetadata,
S::Input: HasLen,
{
fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
let execs_per_hour = (3600.0/entry.exec_time().expect("testcase.exec_time is needed for scheduler").as_secs_f64());
let execs_times_length_per_hour = execs_per_hour*entry.cached_len()? as f64;
Ok(execs_times_length_per_hour)
}
}
//===================================================================
/// A Feedback reporting if the Input consists of strictly decreasing bytes.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SortedFeedback {
}
impl<S> Feedback<S> for SortedFeedback
where
S: UsesInput + HasClientPerfMonitor,
S::Input: HasTargetBytes,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let t = _input.target_bytes();
let tmp = t.as_slice();
if tmp.len()<32 {return Ok(false);}
let tmp = Vec::<u8>::from(&tmp[0..32]);
// tmp.reverse();
if tmp.is_sorted_by(|a,b| match a.partial_cmp(b).unwrap_or(Less) {
Less => Some(Greater),
Equal => Some(Greater),
Greater => Some(Less),
}) {return Ok(true)};
return Ok(false);
}
}
impl Named for SortedFeedback {
#[inline]
fn name(&self) -> &str {
"Sorted"
}
}
impl SortedFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new() -> Self {
Self {}
}
}
impl Default for SortedFeedback {
fn default() -> Self {
Self::new()
}
}
//===================================================================
/// A Feedback which expects a certain minimum execution time
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExecTimeReachedFeedback
{
target_time: u64,
}
impl<S> Feedback<S> for ExecTimeReachedFeedback
where
S: UsesInput + HasClientPerfMonitor,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let observer = observers.match_name::<QemuClockObserver>("clock")
.expect("QemuClockObserver not found");
Ok(observer.last_runtime() >= self.target_time)
}
}
impl Named for ExecTimeReachedFeedback
{
#[inline]
fn name(&self) -> &str {
"ExecTimeReachedFeedback"
}
}
impl ExecTimeReachedFeedback
where
{
/// Creates a new [`ExecTimeReachedFeedback`]
#[must_use]
pub fn new(target_time : u64) -> Self {
Self {target_time: target_time}
}
}
pub static mut EXEC_TIME_COLLECTION : Vec<u32> = Vec::new();
/// A Noop Feedback which records a list of all execution times
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExecTimeCollectorFeedback
{
}
impl<S> Feedback<S> for ExecTimeCollectorFeedback
where
S: UsesInput + HasClientPerfMonitor,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let observer = observers.match_name::<QemuClockObserver>("clock")
.expect("QemuClockObserver not found");
unsafe { EXEC_TIME_COLLECTION.push(observer.last_runtime().try_into().unwrap()); }
Ok(false)
}
}
impl Named for ExecTimeCollectorFeedback
{
#[inline]
fn name(&self) -> &str {
"ExecTimeCollectorFeedback"
}
}
impl ExecTimeCollectorFeedback
where
{
/// Creates a new [`ExecTimeCollectorFeedback`]
#[must_use]
pub fn new() -> Self {
Self {}
}
}
/// Shared Metadata for a SysStateFeedback
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct ExecTimeCollectorFeedbackState
{
collection: Vec<u32>,
}
impl Named for ExecTimeCollectorFeedbackState
{
#[inline]
fn name(&self) -> &str {
"ExecTimeCollectorFeedbackState"
}
}
//===================================================================
/// A Feedback which expects a certain minimum execution time
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ExecTimeIncFeedback
{
longest_time: u64,
last_is_longest: bool
}
impl<S> Feedback<S> for ExecTimeIncFeedback
where
S: UsesInput + HasClientPerfMonitor,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let observer = observers.match_name::<QemuClockObserver>("clocktime")
.expect("QemuClockObserver not found");
if observer.last_runtime() > self.longest_time {
self.longest_time = observer.last_runtime();
self.last_is_longest = true;
Ok(true)
} else {
self.last_is_longest = false;
Ok(false)
}
}
fn append_metadata(
&mut self,
_state: &mut S,
testcase: &mut Testcase<<S as UsesInput>::Input>,
) -> Result<(), Error> {
#[cfg(feature = "feed_afl")]
if self.last_is_longest {
let mim : Option<&mut MapIndexesMetadata>= testcase.metadata_mut().get_mut();
// pretend that the longest input alone excercises some non-existing edge, to keep it relevant
mim.unwrap().list.push(usize::MAX);
};
Ok(())
}
}
impl Named for ExecTimeIncFeedback
{
#[inline]
fn name(&self) -> &str {
"ExecTimeReachedFeedback"
}
}
impl ExecTimeIncFeedback
where
{
/// Creates a new [`ExecTimeReachedFeedback`]
#[must_use]
pub fn new() -> Self {
Self {longest_time: 0, last_is_longest: false}
}
}
/// A Noop Feedback which records a list of all execution times
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AlwaysTrueFeedback
{
}
impl<S> Feedback<S> for AlwaysTrueFeedback
where
S: UsesInput + HasClientPerfMonitor,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
Ok(true)
}
}
impl Named for AlwaysTrueFeedback
{
#[inline]
fn name(&self) -> &str {
"AlwaysTrueFeedback"
}
}
impl AlwaysTrueFeedback
where
{
/// Creates a new [`ExecTimeCollectorFeedback`]
#[must_use]
pub fn new() -> Self {
Self {
}
}
}

View File

@ -1,11 +1,12 @@
[package] [package]
name = "baby_fuzzer" name = "baby_fuzzer"
version = "0.3.0" version = "0.7.1"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2018" edition = "2021"
[features] [features]
default = ["std"] default = ["std"]
tui = []
std = [] std = []
[profile.dev] [profile.dev]

View File

@ -5,3 +5,4 @@ This is a minimalistic example about how to create a libafl based fuzzer.
It runs on a single core until a crash occurs and then exits. It runs on a single core until a crash occurs and then exits.
The tested program is a simple Rust function without any instrumentation. The tested program is a simple Rust function without any instrumentation.
For real fuzzing, you will want to add some sort to add coverage or other feedback.

View File

@ -0,0 +1,70 @@
from pylibafl import libafl
# LIBRARY WRAPPER
def map_observer_wrapper(map_observer):
if type(map_observer).__name__ == "OwnedMapObserverI32":
return libafl.MapObserverI32.new_from_owned(map_observer)
def executor_wrapper(executor):
if type(executor).__name__ == "OwnedInProcessExecutorI32":
return libafl.ExecutorI32.new_from_inprocess(executor)
def monitor_wrapper(monitor):
if type(monitor).__name__ == "SimpleMonitor":
return libafl.Monitor.new_from_simple(monitor)
def event_manager_wrapper(event_manager):
if type(event_manager).__name__ == "SimpleEventManager":
return libafl.EventManagerI32.new_from_simple(event_manager)
def corpus_wrapper(corpus):
if type(corpus).__name__ == "InMemoryCorpus":
return libafl.Corpus.new_from_in_memory(corpus)
if type(corpus).__name__ == "OnDiskCorpus":
return libafl.Corpus.new_from_on_disk(corpus)
def rand_wrapper(rand):
if type(rand).__name__ == "StdRand":
return libafl.Rand.new_from_std(rand)
def stage_wrapper(stage):
if type(stage).__name__ == "StdScheduledHavocMutationsStageI32":
return libafl.StageI32.new_from_std_scheduled(stage)
# CODE WRITTEN BY USER
def harness(inp):
if len(inp.hex()) >= 2 and inp.hex()[:2] == '61':
raise Exception("NOOOOOO =)")
map_observer = libafl.OwnedMapObserverI32("signals", [0] * 16)
feedback_state = libafl.MapFeedbackStateI32.with_observer(map_observer_wrapper(map_observer))
feedback = libafl.MaxMapFeedbackI32(feedback_state, map_observer_wrapper(map_observer))
state = libafl.StdStateI32(
rand_wrapper(libafl.StdRand.with_current_nanos()),
corpus_wrapper(libafl.InMemoryCorpus()),
corpus_wrapper(libafl.OnDiskCorpus("./crashes")),
feedback_state
)
monitor = libafl.SimpleMonitor()
mgr = libafl.SimpleEventManager(monitor_wrapper(monitor))
fuzzer = libafl.StdFuzzerI32(feedback)
executor = libafl.OwnedInProcessExecutorI32(harness, map_observer_wrapper(map_observer), fuzzer, state, event_manager_wrapper(mgr))
generator = libafl.RandPrintablesGeneratorI32(32)
state.generate_initial_inputs(fuzzer, executor_wrapper(executor), generator, event_manager_wrapper(mgr), 8)
stage = libafl.StdScheduledHavocMutationsStageI32.new_from_scheduled_havoc_mutations()
stage_tuple_list = libafl.StagesOwnedListI32(stage_wrapper(stage))
fuzzer.fuzz_loop(executor_wrapper(executor), state, event_manager_wrapper(mgr), stage_tuple_list)

View File

@ -1,18 +1,25 @@
use std::path::PathBuf; use std::path::PathBuf;
#[cfg(windows)]
use std::ptr::write_volatile;
#[cfg(feature = "tui")]
use libafl::monitors::tui::TuiMonitor;
#[cfg(not(feature = "tui"))]
use libafl::monitors::SimpleMonitor;
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler}, corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager, events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::StdState, state::StdState,
stats::SimpleStats,
}; };
/// Coverage map with explicit assignments due to the lack of instrumentation /// Coverage map with explicit assignments due to the lack of instrumentation
@ -26,14 +33,26 @@ fn signals_set(idx: usize) {
#[allow(clippy::similar_names)] #[allow(clippy::similar_names)]
pub fn main() { pub fn main() {
// The closure that we want to fuzz // The closure that we want to fuzz
let mut harness = |buf: &[u8]| { let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
signals_set(0); signals_set(0);
if !buf.is_empty() && buf[0] == b'a' { if !buf.is_empty() && buf[0] == b'a' {
signals_set(1); signals_set(1);
if buf.len() > 1 && buf[1] == b'b' { if buf.len() > 1 && buf[1] == b'b' {
signals_set(2); signals_set(2);
if buf.len() > 2 && buf[2] == b'c' { if buf.len() > 2 && buf[2] == b'c' {
panic!("=)"); #[cfg(unix)]
panic!("Artificial bug triggered =)");
// panic!() raises a STATUS_STACK_BUFFER_OVERRUN exception which cannot be caught by the exception handler.
// Here we make it raise STATUS_ACCESS_VIOLATION instead.
// Extending the windows exception handler is a TODO. Maybe we can refer to what winafl code does.
// https://github.com/googleprojectzero/winafl/blob/ea5f6b85572980bb2cf636910f622f36906940aa/winafl.c#L728
#[cfg(windows)]
unsafe {
write_volatile(0 as *mut u32, 0);
}
} }
} }
} }
@ -41,16 +60,14 @@ pub fn main() {
}; };
// Create an observation channel using the signals map // Create an observation channel using the signals map
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); let observer =
unsafe { StdMapObserver::new_from_ptr("signals", SIGNALS.as_mut_ptr(), SIGNALS.len()) };
// The state of the edges feedback.
let feedback_state = MapFeedbackState::with_observer(&observer);
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
let feedback = MaxMapFeedback::new(&feedback_state, &observer); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let objective = CrashFeedback::new(); let mut objective = CrashFeedback::new();
// create a State from scratch // create a State from scratch
let mut state = StdState::new( let mut state = StdState::new(
@ -62,19 +79,25 @@ pub fn main() {
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
// States of the feedbacks. // States of the feedbacks.
// They are the data related to the feedbacks that you want to persist in the State. // The feedbacks can report the data that should persist in the State.
tuple_list!(feedback_state), &mut feedback,
); // Same for objective feedbacks
&mut objective,
)
.unwrap();
// The Stats trait define how the fuzzer stats are reported to the user // The Monitor trait define how the fuzzer stats are displayed to the user
let stats = SimpleStats::new(|s| println!("{}", s)); #[cfg(not(feature = "tui"))]
let mon = SimpleMonitor::new(|s| println!("{}", s));
#[cfg(feature = "tui")]
let mon = TuiMonitor::new(String::from("Baby Fuzzer"), false);
// The event manager handle the various events generated during the fuzzing loop // The event manager handle the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus // such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(stats); let mut mgr = SimpleEventManager::new(mon);
// A queue policy to get testcasess from the corpus // A queue policy to get testcasess from the corpus
let scheduler = QueueCorpusScheduler::new(); let scheduler = QueueScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -0,0 +1 @@
libpng-*

View File

@ -0,0 +1,23 @@
[package]
name = "baby_fuzzer_gramatron"
version = "0.8.2"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2021"
[features]
default = ["std"]
std = []
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[dependencies]
libafl = { path = "../../libafl/" }
postcard = "0.7"

View File

@ -0,0 +1,15 @@
# Baby Gramatron
This fuzzer shows how to implement grammar-aware fuzzing. [Gramatron](https://github.com/HexHive/Gramatron) uses grammar automatons in conjunction with aggressive mutation operators to synthesize complex bug triggers. `auto.json` records grammar automaton of php,which is corresponding to `libafl::generators::Automaton`and serialized into `auto.postcard`. `libafl::generators::gramatron` will generate valid grammar sequences using `Automaton` and then pass them into `harness`. The function of `harness` is to print the original input.
When you use `cargo run`, You may see output as follows:
```
b=mlhs_node.isz(c,c, )
d=false.keyword__FILE__(c,b,a,b)
a=select.Jan(d)
a=first.literal( )
b=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,nil].DomainError(c)
next a
b=Oo.gsub(a,d,b)
d=0.hex( )
```

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,4 @@
fn pippo(v) { return "hello world " + v; }
var a = 666;
name = "scozzo" + a;
pippo(name);

View File

@ -0,0 +1,162 @@
#[cfg(windows)]
use std::ptr::write_volatile;
use std::{
fs,
io::{BufReader, Read},
path::{Path, PathBuf},
};
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer},
generators::{Automaton, GramatronGenerator},
inputs::GramatronInput,
monitors::SimpleMonitor,
mutators::{
GramatronRandomMutator, GramatronRecursionMutator, GramatronSpliceMutator,
StdScheduledMutator,
},
observers::StdMapObserver,
schedulers::QueueScheduler,
stages::mutational::StdMutationalStage,
state::StdState,
};
/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
/*
/// Assign a signal to the signals map
fn signals_set(idx: usize) {
unsafe { SIGNALS[idx] = 1 };
}
*/
fn read_automaton_from_file<P: AsRef<Path>>(path: P) -> Automaton {
let file = fs::File::open(path).unwrap();
let mut reader = BufReader::new(file);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer).unwrap();
postcard::from_bytes(&buffer).unwrap()
}
#[allow(clippy::similar_names)]
pub fn main() {
let mut bytes = vec![];
// The closure that we want to fuzz
let mut harness = |input: &GramatronInput| {
input.unparse(&mut bytes);
unsafe {
println!(">>> {}", std::str::from_utf8_unchecked(&bytes));
}
ExitKind::Ok
};
// Create an observation channel using the signals map
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new();
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
// States of the feedbacks.
// The feedbacks can report the data that should persist in the State.
&mut feedback,
// Same for objective feedbacks
&mut objective,
)
.unwrap();
// The Monitor trait define how the fuzzer stats are reported to the user
let monitor = SimpleMonitor::new(|s| println!("{}", s));
// The event manager handle the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(monitor);
// A queue policy to get testcasess from the corpus
let scheduler = QueueScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// Create the executor for an in-process function with just one observer
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(observer),
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create the Executor");
let automaton = read_automaton_from_file(PathBuf::from("auto.postcard"));
let mut generator = GramatronGenerator::new(&automaton);
// Use this code to profile the generator performance
/*
use libafl::generators::Generator;
use std::collections::HashSet;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
let mut set = HashSet::new();
let st = libafl::bolts::current_milliseconds();
let mut b = vec![];
let mut c = 0;
for _ in 0..100000 {
let i = generator.generate(&mut state).unwrap();
i.unparse(&mut b);
set.insert(calculate_hash(&b));
c += b.len();
}
println!("{} / {}", c, libafl::bolts::current_milliseconds() - st);
println!("{} / 100000", set.len());
return;
*/
// Generate 8 initial inputs
state
.generate_initial_inputs_forced(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8)
.expect("Failed to generate the initial corpus");
// Setup a mutational stage with a basic bytes mutator
let mutator = StdScheduledMutator::with_max_stack_pow(
tuple_list!(
GramatronRandomMutator::new(&generator),
GramatronRandomMutator::new(&generator),
GramatronRandomMutator::new(&generator),
GramatronSpliceMutator::new(),
GramatronSpliceMutator::new(),
GramatronRecursionMutator::new()
),
2,
);
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.expect("Error in the fuzzing loop");
}

View File

@ -0,0 +1 @@
libpng-*

Some files were not shown because too many files have changed in this diff Show More