Compare commits

...

1200 Commits

Author SHA1 Message Date
3a76844ab2 add targets 2024-11-12 07:55:00 +01:00
13abaef343 update snakefile 2024-11-11 15:59:54 +01:00
9b16edd1a4 rate-limit testcase printing 2024-11-11 15:56:42 +01:00
93c42cb3dc fix release-detection for api -> isr -> app, fix crash on empty trace 2024-11-11 15:56:13 +01:00
0e7de2d109 imports 2024-10-29 18:23:02 +01:00
f1affaabff impl RemovableScheduler for GenerationScheduler 2024-10-29 18:21:46 +01:00
0a6888d06a add pruning message 2024-10-29 18:10:16 +01:00
d88cefb894 add experimental corpus pruning 2024-10-29 18:08:18 +01:00
4d0ec2e427 typo 2024-10-29 16:01:25 +01:00
a613156a32 micro fixes 2024-10-29 15:59:15 +01:00
013f3db487 implement STGSnippetStage, fix missing metadata 2024-10-29 14:07:52 +01:00
3d0c0247b7 trace mem bytes read 2024-10-28 08:12:30 +01:00
d89d5e3e5e introduce JobInstance, TaskJob 2024-10-28 08:10:45 +01:00
d8a15adb1d move codepieces 2024-10-22 14:25:51 +02:00
c5c9a052e4 remove interval_name from interval, fix snakefile showmap 2024-10-22 09:05:21 +02:00
f9f59211fb do not use error as objective for showmap 2024-10-21 17:29:56 +02:00
a7f24da786 show function ranges 2024-10-21 17:14:14 +02:00
8417613cb2 save stats per abb 2024-10-21 17:13:38 +02:00
926ad96b8e print hash on graph nodes 2024-10-18 15:04:47 +02:00
d4e6de3e80 shrink moving average window size to ~5 min 2024-10-18 13:18:44 +02:00
735fc3e144 collect first n error inputs as objectives, fix configs 2024-10-18 13:08:13 +02:00
bf827c077f use moving average success rate for interrupt mutation frequency 2024-10-18 11:09:44 +02:00
3a126cb0a8 target_symbols.csv++ 2024-10-15 17:02:08 +02:00
875f87f0c6 fix detection of releases by api call 2024-10-15 16:22:42 +02:00
8f0e54053b WIP: try removing interrupts within min interarrival 2024-10-10 17:56:08 +02:00
2ca6fdf538 simplify stored execution times per testcase 2024-10-10 16:33:19 +02:00
bae801c620 remove shortcut from benchmark features 2024-10-10 15:24:54 +02:00
04cfa7cea2 report interrupt mutation statistics 2024-10-10 15:15:23 +02:00
7586c51f6f disable release warnings 2024-10-10 15:14:56 +02:00
6d197274dd snakemake: increase build efficiency 2024-10-10 15:14:13 +02:00
d4ee679d0e fix trace seection when no instance was found, comments++ 2024-10-09 16:16:12 +02:00
66a87835be feedback: ignore abbs outside select interval 2024-09-27 16:23:30 +02:00
5ffac514ca rework release detection with nested interrupts 2024-09-27 15:24:06 +02:00
fb3837f725 fix out of bounds interrupt mutation 2024-09-17 17:09:48 +02:00
a9ce2d787b fix flags 2024-09-16 15:58:19 +02:00
0d89787728 use smaller seeds for testing 2024-09-16 14:52:42 +02:00
5b662397be fix array index 2024-09-12 16:02:11 +02:00
b390315a5d fix ambiguity 2024-09-12 15:48:46 +02:00
26452d9a0d config generation 2024-09-12 13:43:53 +02:00
8165fd7cfc refactor interrupt mutation 2024-09-12 13:19:28 +02:00
835d1e1a79 seed 10k 2024-09-12 09:18:02 +02:00
e6cf64541d better seeding + trace cutout 2024-09-10 16:18:25 +02:00
6a98489e32 fixes++ 2024-09-10 11:22:46 +02:00
90acd4fc9f fix scripts 2024-09-10 11:11:37 +02:00
db037f5015 fix empty interrupt config 2024-09-10 10:45:37 +02:00
7896342ed9 fix target names 2024-09-10 10:40:52 +02:00
7139a94a1b adapt scripts 2024-09-09 16:07:03 +02:00
7ad2f6fa6b rename keys 2024-09-09 16:06:41 +02:00
5648faefa7 fix all_bins 2024-09-09 12:55:30 +02:00
3bb42150d3 unify fuzzing with and without interrupts 2024-09-09 12:51:23 +02:00
740ce09d31 configurable interrupt sources 2024-09-09 10:56:39 +02:00
288abeb6bf prepare multiple interrupt sources 2024-09-06 08:38:30 +02:00
ee737b9eb8 improve benchmark scripts and excution fixes 2024-09-05 09:55:21 +02:00
6929073069 update benchmark script 2024-09-02 16:26:58 +02:00
8adc1e2624 debug msg ++ 2024-09-02 15:53:59 +02:00
06b523fb9f fix release-resposne matching bug 2024-08-30 14:02:21 +02:00
a613a803ca detect job releases during race-conditions 2024-08-29 11:24:32 +02:00
2c00f82d39 fix task releases with nested interrupts 2024-08-28 14:16:03 +02:00
461731cc5a fix: fallback to 0 response-time if target job did not finish 2024-08-27 13:15:38 +02:00
0b4e9bdab7 add time helper function 2024-08-26 15:50:59 +02:00
11028d7aae change interrupt randomization rule 2024-08-26 15:46:11 +02:00
ae6b3c0650 maybe fix interrupt bytes not changing 2024-08-26 15:45:32 +02:00
8e885f6e85 fix some helper-scripts 2024-08-26 15:20:48 +02:00
9d83ddbd69 low prio warnings-- 2024-08-26 15:18:46 +02:00
c785e0db86 fix jobs with response==release 2024-08-26 15:18:46 +02:00
f14d486ccf skip mutation of 0 size inputs 2024-08-26 15:10:12 +02:00
a18a5f9bcf fix everything interesting 2024-08-26 15:10:12 +02:00
bd7ddaffbd fix releases 2024-08-20 12:20:55 +02:00
6995cd053b fix snakefile 2024-08-19 16:28:11 +02:00
e9fb73e65b WIP: per-task response times 2024-08-19 16:08:45 +02:00
bf7ad374a0 stupid bug fix
stupid bug fix
2024-08-19 10:22:31 +02:00
de9c0a6d1e WIP: input snippet mutation 2024-08-16 09:58:21 +02:00
3b6cd3bc45 fix bug causing skipped mutation when part size is 0 2024-08-15 09:38:52 +02:00
72f9de45d0 fix cargo.toml 2024-08-14 09:41:02 +02:00
46aa6cec0f reads behind config flag 2024-08-14 09:10:30 +02:00
b9f0151e87 repeat interrupt mutations 2024-08-14 08:55:23 +02:00
712ac137d7 logging and reporting 2024-08-14 08:50:34 +02:00
920a996d95 multipart seed reading 2024-08-14 08:42:33 +02:00
3db17ceb98 WIP: store memory reads 2024-08-12 15:31:56 +02:00
05c17d3159 report state space exporation 2024-08-12 12:07:31 +02:00
f8d9363e7e update snakefile 2024-08-04 09:46:39 +02:00
ade004cffb update targets 2024-08-04 09:40:53 +02:00
0e5bf879e4 fix try_force_new_branches 2024-07-04 12:49:09 +02:00
d569df29a3 build fixes 2024-07-02 09:34:56 +02:00
47724ad1c3 stg try_force_new_branches 2024-07-02 09:34:35 +02:00
810ec36115 refactor 2024-07-01 13:28:38 +02:00
77799f77a9 move cli parsing, use multibyteinput 2024-06-28 14:38:25 +02:00
acf9b04e70 remove unused code 2024-06-20 13:25:21 +02:00
6cb2be4408 add TimeProbMassScheduler 2024-06-20 10:15:01 +02:00
3a7c0da037 fast snapshots by default 2024-06-19 14:22:12 +02:00
5fad373199 update to 0.13.0 API 2024-06-19 13:30:36 +02:00
df7333b764 WIP: merge 2024-06-17 14:17:06 +02:00
a7becb403e update helper scripts 2024-06-17 10:31:48 +02:00
Valentin Huber
5a2652b984
Adding StdXObserver Docs (#2311)
* Adding StdXObserver Docs

* fixing docs

* code cleanup

* moving example

* improving exclusion rules

* adding impls for features

* adding test exclusions

* excluding miri from OS including tests

* fixing CI

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-06-14 19:41:21 +02:00
Dongjia "toka" Zhang
c3930b39fc
Fix CI (#2312) 2024-06-14 14:16:31 +02:00
b86ac4cac6 fix build 2024-06-14 14:06:21 +02:00
5e29f4b909 always dump error case during fuzzing 2024-06-14 14:00:09 +02:00
1146c2c1e5 two-way isr edges, graceful parsing error handling 2024-06-14 13:56:36 +02:00
lazymio
18a25d3b3d
Fix debug assert on map_state.num_covered_map_indexes (#2310) 2024-06-14 13:29:38 +02:00
Dongjia "toka" Zhang
c415b4d5f6
0.13.0 (#2253)
* 0.13

* z3

* capstone

* fixer

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-06-13 23:35:35 +02:00
clesmian
2265d672fc
Allow trailing comma in feedback macros (#2308)
Co-authored-by: Leon Weiß <leon.weiss@rub.de>
2024-06-13 23:35:20 +02:00
Dongjia "toka" Zhang
e12412fed6
Fix Stdout/err Observer? (#2301) 2024-06-13 13:33:36 +02:00
Aarnav
901572556f
Add support for cycling PowerSchedule on completion of a queue cycle in WeightedScheduler (#2300)
* add support for cycling PowerSchedule on completion of a queue cycle in WeightedScheduler

* improve doc

* make fn cycle_schedule private

* rename cycle_schedules to cycling_scheduler
2024-06-13 10:25:25 +01:00
Andrea Fioraldi
09faec15f4
Add libdesyscall (#1221)
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-06-12 11:28:31 +02:00
Dongjia "toka" Zhang
0ed295842b
Use filename for MmapShMemProvider (#2303)
* fixer

* comment

* a

* bb

* apple
2024-06-11 20:15:11 +02:00
mkravchik
03d8d2eb08
Fixing Frida ASAN tests on Windows (#2299)
* libafl_frida unit tests passing with ASAN

* Clippy+fmt

* Clippy

* Setup VS environment before building
2024-06-11 13:22:46 +02:00
Valentin Huber
df40db5ae8
Fix closing mmap on provider::release_shmem (#2298) 2024-06-10 17:59:51 +02:00
Dongjia "toka" Zhang
f4699ba385
Make adaptive serialization into default (#2296)
* no adaptive

* add another api

* allow unused
2024-06-09 00:10:30 +02:00
Dongjia "toka" Zhang
454176427b
Windows clippy (#2295)
* add

* real one

* fuck

* abc

* def

* ghi

* jkl

* fix

---------

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
2024-06-08 20:32:40 +02:00
Dominik Maier
93085782d6
Rename string stages to unicode stages for consistency (#2293) 2024-06-08 16:59:49 +01:00
Dongjia "toka" Zhang
e905743ef6
Update issue template(#2294) 2024-06-08 17:42:33 +02:00
Dongjia "toka" Zhang
30ae963c45
Fix CI (#2292)
* p

* a

* p

* a

* delete transfered

* b

* bring back transferred

* ??

* xx

* conditional

* ?

* debug

* a

* 🤬🤬🤬🤬🤬🤬🤬

* a

* a

* comment
2024-06-08 16:25:49 +01:00
Romain Malmain
8ef4e2aff0
Do not fmt little cms files (#2291) 2024-06-08 13:19:58 +01:00
Dominik Maier
ba84170777
Fix docs on crates.io for LibAFL_Frida, introduce auto-download feature (#2270)
* Fix docs on crates.io for LibAFL_Frida, introduce auto-download feature

* remove it more

* more testing

* more features

* more CI

* CI?

* CI?

* More fix?

* nicer

* More fix?

* test?

* more try?

* why?

* more more
2024-06-08 13:02:59 +01:00
Dongjia "toka" Zhang
e99fcad326
Run ./scripts/fmt_all.sh in CI (#2290)
* pppp

* fix

* xx

* add clang18

* fix

* chg

* purge existing clang..

* tmate

* trigger

* bruh

* finally..

* Don't fmt when not in cargo-fmt

* fix

* aaaaaa

* fuck
2024-06-08 01:41:39 +02:00
Dongjia "toka" Zhang
1e2fac6f53
abort() when the weakly defined LLVMFuzzerTestOneInput is linked(#2289) 2024-06-07 23:54:19 +02:00
Romain Malmain
14263b9c69
Rusty LibAFL fmt (#2271) 2024-06-07 23:41:50 +02:00
Marco Neumann
b1bec42044
fix: libafl_libfuzzer build script (#2282)
- features check was inverted
- print helpful message when `llvm-nm` wasn't found, which happens to be
  the case on _stable_

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-06-07 23:37:08 +02:00
Aarnav
477941e0e2
change Stability calculation formla to AFL++'s (#2275)
* change Stability calculation formla to AFL++'s

* clippy

* use MapFeedbackMetadata instead of recalculating filled entries in map

* calculate filled entries if MapFeedbackMetadata is not available

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-06-07 14:56:37 +02:00
Dongjia "toka" Zhang
2cc33464fa
Cleanup for #2280 (#2286)
* cleanup

* ppppp

* a

* b
2024-06-07 14:56:14 +02:00
Dongjia "toka" Zhang
1b008ae2e4
Delete 'static from libafl::events (#2285) 2024-06-07 13:45:36 +02:00
Kevin Phoenix
bc5ae151bc
libafl_qemu_build: Disable docs in user mode (#2272) 2024-06-06 18:57:13 +01:00
Aarnav
a455ad27a9
Fix WeightedScheduler reporting incorrect queue cylces (#2281)
* fix WeightedScheduler reporting incorrect queue cylces

* check if runs_in_cycle equals or greater instead of just equals

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-06-06 18:50:29 +01:00
Romain Malmain
af12b4ba24
LLmp hooks (#2280)
* llmp hooks

* separate llmp broker from inner state to allow doing more stuff
2024-06-06 16:07:55 +02:00
69d0c6f9bb build fix 2024-06-06 14:50:02 +02:00
b9e388d9d5 timeshift variable, handle nested isr+api, bump max_interrupts 2024-06-06 14:39:45 +02:00
Romain Malmain
399fbccea2
Closure builder for inner managers of centralized. (#2279)
* generic inner manager for centralized, with builder closures.

* moved options inside the function

* removed useless bound

* unused import

* remove useless clone bound.

* make clearer what is secondary node

* same inner manager for main and secondary

* fix example
2024-06-05 19:12:21 +02:00
Aarnav
7dd345d18c
Enforce max_input_size and min_input_size in Forkserver (#2273)
* enforce minimum and maximum input size for Forkserver's shared memory map and file based testcases

* explicit conversion to OwnedSlice

* clippy

* error if min_input_size > max_input_size when building forkserver
2024-06-05 16:16:30 +02:00
Dongjia "toka" Zhang
6373a1e1b3
Use Self::State as much as possible and remove unnecessary type bounds (#2263)
* use Self::State as much as possible

* makeing progress, little by little

* more

* add

* more and more

* more

* more

* mre

* fix

* a

* pp

* fix

* fix

* more

* version

* fix cargo fuzz
2024-06-05 15:16:43 +02:00
Dongjia "toka" Zhang
a7bb5196ea
Revert "Revert "Add always_interesting option to llmp mgr (#2262)" (#2274)" (#2278)
This reverts commit 620835a73f4a1163177d2b11b61625177c737cd5.
2024-06-05 15:10:32 +02:00
Dongjia "toka" Zhang
620835a73f
Revert "Add always_interesting option to llmp mgr (#2262)" (#2274)
This reverts commit 0f9c82f893b0bb8e91b78c5c17f8d1c8d452669e.
2024-06-04 18:53:01 +02:00
Dominik Maier
1556cba426
Update ratatui to 0.26 (#2269)
* Update ratatui to 0.26

* more build infos

* fix introspection
2024-06-03 15:23:12 +02:00
dependabot[bot]
2a82e9c40f
Update winsafe requirement from 0.0.20 to 0.0.21 (#2268)
Updates the requirements on [winsafe](https://github.com/rodrigocfd/winsafe) to permit the latest version.
- [Commits](https://github.com/rodrigocfd/winsafe/compare/v0.0.20...v0.0.21)

---
updated-dependencies:
- dependency-name: winsafe
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 14:27:21 +02:00
Dominik Maier
58c39680c9
Move Nautilus to LibAFL, remove AGPL dependencies (#2265)
* Copy choose method for unbounded iterators

* Add choose method for unbounded iterators

* Copy&paste in nautilus grammartec

* cargo

* fmt

* Initial Nautilus in LibAFL

* missing link

* clippy

* clippy

* more clippy

* docs

* docs

* more docs

* remove nautilus default

* fix doctest

* fmt

* less vec

* test

* less flakey

* clippy

* clippy
2024-06-03 14:18:52 +02:00
c7bf1be8b1 target_symbols.csv++ 2024-06-03 08:31:57 +02:00
Dongjia "toka" Zhang
0f9c82f893
Add always_interesting option to llmp mgr (#2262)
* always add

* change launcher...
2024-05-31 15:18:51 +02:00
Aarnav
7b90873305
introduce CustomFilenameToTestcaseFeedback (#2256)
* introduce CustomTestcaseFilenameFeedback

* rename CustomTestcaseFilenameFeedback to CustomFilenameToTestcaseFeedback

* rename custom_testcase_filename to custom_filename

---------

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
2024-05-30 19:05:53 +02:00
Romain Malmain
1102ea0fe7
Better RW errors for QEMU (#2260)
* better error for rw in qemu.

* fix python

* clippy

* Fix error in fuzzers

* Fix error in fuzzers

* fix systemmode error

* import
2024-05-30 15:14:17 +02:00
Dongjia "toka" Zhang
e912216a37
Add remove_from_all method to Corpus trait (#2259)
* add remove_from_all

* a

* a

* aaaaaaa

* make remove_from_all to remove
2024-05-30 11:53:32 +02:00
2cbd9de2eb change interrupt mutation 2024-05-29 15:49:52 +02:00
4c8a435cfd fix corpuscase dump 2024-05-29 12:32:34 +02:00
Mrmaxmeier
b96b9be674
tutorial fuzzer: switch lain fork to AFLplusplus/lain (#2257) 2024-05-28 20:45:18 +02:00
Mrmaxmeier
7fe43a28e8
fix duplicate package warning (#2258)
warning: skipping duplicate package `fuzzbench` found at `~/.cargo/git/checkouts/libafl-c33dc6f5ec2f7a70/058e15f/fuzzers/fuzzbench`
2024-05-28 20:45:04 +02:00
Addison Crump
058e15f547
Implement tuple mapping (#2247)
* implement tuple mapping

* docs, clippy magic

* clippy >:(

* rename for clarity
2024-05-28 18:11:41 +02:00
Romain Malmain
65af5a7f78
Fix libnyx, library upgrades (#2254)
* try this thing

* this?

* use new mmap signature in nix.

* fix import

* fix to work with addr2line v0.23.

* remove unused flag

* update strum also for dependency...

* clippy

* clippy

* update lain git hash

* bump many outdated crates

* fix hash
2024-05-28 17:15:08 +02:00
Dominik Maier
c3f67daefb
Fix nix update (#2252) (#2255) 2024-05-28 13:16:09 +02:00
Romain Malmain
963afc3e5c
Pre-commit hooks (#2241)
* add pre-commit hook.
example of hook with fmt check.

* Add `CONTRIBUTING.md`.
2024-05-28 11:45:13 +02:00
Aarnav
bce0f08294
Introduce feedbacks hit tracking for testcases (#2248)
* introduce feedbacks hit tracking for testcases

* make Testcase::hit_feedbacks into Cow<&str> instead of String
rename get_hit_feedbacks to append_hit_feedbacks
update documentation

* simplify ConstFeedback

* rename Feedback::last_result to prev_result

* impl TODO prev_result for NewHashFeedback, ListFeedback, TransferredFeedback, NautilusFeedback

* rename prev_result to last_result

* add docs

* introduce Objectives hit tracking

* update docs

* update Cargo.toml docs

* update docs

* track Feedbacks & Objectives hit in Fuzzer::add_input

* fmt

* clippy

* fix type error in OomFeedback::last_result

* impl last_result for AsanErrorsFeedback

* add track_hit_feedbacks as a feature to libafl_libfuzzer_runtime

* fix clippy

* change return type of Feedback::last_result to a Result

* remove expect in NewHashFeedback::is_interesting

* move Error::premature_last_result to libafl from libafl_bolts
2024-05-28 11:43:05 +02:00
dependabot[bot]
e4446b908c
Update nix requirement from 0.27 to 0.29 (#2252)
---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 11:42:46 +02:00
dependabot[bot]
2670049c2b
Update addr2line requirement from 0.22 to 0.23 (#2251)
Updates the requirements on [addr2line](https://github.com/gimli-rs/addr2line) to permit the latest version.
- [Changelog](https://github.com/gimli-rs/addr2line/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/addr2line/compare/0.22.0...0.23.0)

---
updated-dependencies:
- dependency-name: addr2line
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-28 11:42:34 +02:00
Romain Malmain
4d45100a63
Fix libafl_qemu.h (#2250)
* fix header for gcc

* fix comment
2024-05-28 11:39:24 +02:00
Valentin Huber
7c9bd1157c
Adding DiffExitKindFeedback (#2246)
* adding DiffExitKindFeedback

* refactoring

* fixing CI
2024-05-24 16:12:32 +02:00
Dongjia "toka" Zhang
e6eb6c48d2
LibAFL Dynamic Analysis (#2208)
* aa

* push

* push

* push

* claude ai

* push

* add

* add stuff

* upd

* rdm

* fix

* ci

* fix

* fix

* fixing

* feature

* revert

* no submodules

* ci
2024-05-24 14:43:27 +02:00
Dominik Maier
07dca4b59b
LibAFL_Libfuzzer: Add clippy warnings (#2244)
* clip

* More clippyness
2024-05-24 14:00:09 +02:00
Romain Malmain
5fbe2415e1
Generic QEMU snapshot checking (#2240)
* generic snapshot checking.
2024-05-23 22:57:13 +02:00
Dominik Maier
1fafaf6454
Make every Builder ::builder(), so BobTheBuilder::new() becomes BobThe::builder() (#2242)
* Make every builder ::builder()

* Fix no_std

* More

* Fix clippy, stuff

* More fun

* Make NopShMem do something

* Alloc

* more fmt

* Remove UB in tinyinst executor builder

* Make builder order not matter for tinyinst

* More better

* fix

* docs

* fmt

* more fmt

* clippy

* fix fixes

* tiny thing

* more betterg

* more more

* more builder

* more builder

* more nyx

* undo breaking clippy

* clip
2024-05-23 18:56:39 +02:00
35c99fba3a increase max abb count 2024-05-23 16:44:56 +02:00
Dominik Maier
b97a9a1398
Rename peek_next_free_id to peek_free_id (that it's the next is obvious) (#2243) 2024-05-23 15:44:32 +02:00
ffedc1fd41 revert changes to interrupt injection 2024-05-23 10:28:34 +02:00
7701fff969 config fix 2024-05-23 10:25:23 +02:00
de5c16e601 plot micro fixes 2024-05-23 10:16:28 +02:00
83e9a29d12 skip dumping every trace 2024-05-23 10:15:25 +02:00
Dominik Maier
e317ad045e
Introduce StageId (extends #2201) (#2239)
* Factor out `StageStack` from `StdState`

Refactoring for the sake of abstraction and maintainability.

Previously, the `stage_idx_stack` and `stage_depth` fields of
`StdState` had an implicit relationship to one another. This commit
reifies this relationship into a new `struct`. Its fields are hidden
from everything else in `StdState`. It `impl`s `HasCurrentStage` and
`HasNestedStageStatus`, which `impl`s now no longer have mutable access
to the whole state. The `impl`s for `StdState` just forward to these
ones.

Hopefully, this refactoring would make it easier to `impl State` for
other types in the future.

* Create `StageIdx` newtype

Like `CorpusId`, this is just a thin wrapper around `usize`.

* unused import

* Rename a few functions to be more about indices

* Rename Index to Id, fmt

* Move StageId around

---------

Co-authored-by: Langston Barrett <langston.barrett@gmail.com>
2024-05-23 00:53:26 +02:00
35716cc4be fix initial corpus 2024-05-22 22:36:00 +02:00
915da3fb42 fix config 2024-05-22 22:27:04 +02:00
5901e3d9c5 prioritize long tarces 2024-05-22 22:18:56 +02:00
bde16f8297 scheduler, mutator changes 2024-05-22 21:54:07 +02:00
c533b7e184 change interrupt injection timing, stg scheduler 2024-05-22 13:52:13 +02:00
Aarnav
1ed1c4eb31
Add peek function to Corpus (#2238)
* add peek function to Corpus

* send 0 as next peek in NopCorpus

* rename peek to peek_next_free_id

* fix clippy

* add peek_next_free_id to libafl_libfuzzer

* impl peek_next_free_id for ArtifactCorpus
2024-05-22 13:30:47 +02:00
cube0x8
4b67b55b29
Second round of usermode snapshot fixes (#2140)
* Added brk callback for snapshot. Added filter feature for snapshot

* cargo fmt

* clippy

* Update imports

* update bindings

* updated bindings

* Added additional check of brk syscall result

* change snapshot restore debug level from info to debug

* add warning comment

---------

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
2024-05-22 13:30:09 +02:00
Dongjia "toka" Zhang
336d7fcc4f
Refactor events/llmp.rs (#2234)
* push

* refactor

* FMT

* fixes

* aaaaaa

* done

* aa

* docdoc

* rename

* no std

* nautilus

* feature fix

* aa

---------

Co-authored-by: Your Name <you@example.com>
2024-05-22 12:58:44 +02:00
cube0x8
47d15ade81
Instrumentation filters remove generic bound (#2053)
* Removed S: UsesInput bound for HasInstrumentationFilter

* cargo fmt

* Removed S generic leftovers

* cargo fmt

* fix systemmode

* unused imports

* more verbose error.

* clippy

* debug test

* still debugging

* debug ci

* sudo

* debug

* debug

* debug

* add g++

* build-essential

* more deps...

* restore to sane state.

* remove useless comment.

---------

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
2024-05-22 12:58:10 +02:00
Dominik Maier
684b31279e
Add BytesSubInput to mutate sub-parts of a bytes-backed input (#2220)
* Add BytesSubMutator that allows us to mutate sub-parts of a bytes-backed input

* no_std

* fix string mutator

* make build

* Fix clippy on macOS

* Docs

* More docs

* Better docs

* --amend

* Renamed bsi to sub_input. Too much BSI

* More more

* balance backticks

* Make splicing usable with sub_input (not that it makes sense)

* More annotations

* more input annotations?

* Implement HasMutatorBytes for &mut Vec

* clippy

* Use a wrapper type instead

* Add wrapper type for Vec as well

* Remove the duplicate BytesInput... lol
2024-05-22 01:50:07 +02:00
5342812cf7 build fixes 2024-05-21 18:50:55 +02:00
71ff7487e6 add feature dependencies 2024-05-21 18:48:46 +02:00
54fa7cce62 add edge filter 2024-05-21 18:47:12 +02:00
b9b6e1fc12 fix snakefile 2024-05-21 18:33:15 +02:00
e9c27b3065 fixes timing, scheduler 2024-05-21 18:24:23 +02:00
2886aafb65 remove dead code, restructure features 2024-05-21 16:06:53 +02:00
Dongjia "toka" Zhang
19ef29ed60
New forkserver (#2213)
* step 1

* done

* cmplog?

* targets

* check if working and add env_logger

* typo
2024-05-21 15:20:28 +02:00
Valentin Huber
b7e10ca7af
Making StdOutObserver and StdErrObserver implement Observer (#2236)
* making stdout and stderr observers implement observer

* fixing imports
2024-05-21 13:19:02 +02:00
3ed8ccd0c7 exclude QemuSystemStateObserver when not needed 2024-05-21 13:03:55 +02:00
7d8717ff15 remove shortcut cases and assertions from state 2024-05-21 12:59:56 +02:00
87ddf4a77d work around rare non-started abbs 2024-05-21 12:43:03 +02:00
3444fdd8ec fix interrupt shifter, isr tracer 2024-05-21 12:32:00 +02:00
f13412c175 fix interrupt shifter 2024-05-21 09:03:11 +02:00
ede6cf48a4 fix build 2024-05-21 01:57:23 +02:00
5edb6e5677 fix snakefile 2024-05-21 01:51:54 +02:00
21c97c8484 WIP: fix isr_starter 2024-05-21 00:22:50 +02:00
Dominik Maier
123f508fcc
Clean up samplig_rate, add docs (#2228)
* Clean up samplig_rate, add docs

* clippy
2024-05-20 14:24:24 +02:00
dependabot[bot]
aa47a5c5e6
Update addr2line requirement from 0.21 to 0.22 (#2230)
Updates the requirements on [addr2line](https://github.com/gimli-rs/addr2line) to permit the latest version.
- [Changelog](https://github.com/gimli-rs/addr2line/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gimli-rs/addr2line/compare/0.21.0...0.22.0)

---
updated-dependencies:
- dependency-name: addr2line
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 14:21:37 +02:00
dependabot[bot]
d6827b5aa2
Update goblin requirement from 0.7 to 0.8 (#2232)
Updates the requirements on [goblin](https://github.com/m4b/goblin) to permit the latest version.
- [Changelog](https://github.com/m4b/goblin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/m4b/goblin/commits)

---
updated-dependencies:
- dependency-name: goblin
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 14:21:25 +02:00
dependabot[bot]
767f5dffec
Update erased-serde requirement from 0.3.21 to 0.4.5 (#2233)
Updates the requirements on [erased-serde](https://github.com/dtolnay/erased-serde) to permit the latest version.
- [Release notes](https://github.com/dtolnay/erased-serde/releases)
- [Commits](https://github.com/dtolnay/erased-serde/compare/0.3.21...0.4.5)

---
updated-dependencies:
- dependency-name: erased-serde
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 14:19:22 +02:00
b9d6f41ac6 WIP: deprecate graph and use STG 2024-05-20 10:54:43 +02:00
s1341
864c2259e7
launcher: add launch_delay option (#2227)
* launcher: add launch_delay option

* Centralized too

* Use in test

* Undo

* Windows too

* Format

* Fix cfg guard
2024-05-20 10:06:33 +03:00
s1341
f324c60b02
Add testcase sampling rate (#2226)
* fuzzer: Add with_sampling_rate

* Format

* Fix clippy
2024-05-20 09:34:31 +03:00
Sharad Khanna
79f3b69fa8
Fix hook_func and implement deinit (#2180)
* Hook fix

* Implement deinit to pass tests

* Fix aarch64 errors as well as signficantly speed up startup on macos

* fmt

* Fix cmplog_rt

* Fix windows ci

* ci fix 2

* Fix clippy

* Revert hook implementation to new impl

* Add nolinkage option for hooks and fix some comments

* fmt

* Move hooking mechanism to entirely static mut

* fmt

* Fix clippy

* fix windows

* fmt

* Overall the function hook macro to ensure that the original function is correct and not the same function in a different library. Also change static muts to OnceLock
2024-05-20 07:41:44 +03:00
Dominik Maier
6a9ea73865
Confuse clippy less (#2223) 2024-05-20 04:03:23 +02:00
Dominik Maier
117741e1b1
Run Clippy on macOS (#2222)
* macos clippy

* Fix clippy on macOS
2024-05-20 02:58:42 +02:00
dependabot[bot]
cc71979826
Update hostname requirement from ^0.3 to ^0.4 (#2206)
Updates the requirements on [hostname](https://github.com/svartalf/hostname) to permit the latest version.
- [Release notes](https://github.com/svartalf/hostname/releases)
- [Changelog](https://github.com/svartalf/hostname/blob/master/CHANGELOG.md)
- [Commits](https://github.com/svartalf/hostname/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: hostname
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-05-20 02:32:36 +02:00
Dominik Maier
30f65512d8
Remove unused dependencies (#2221)
* Remove unused dependencies

* Add guard
2024-05-20 02:30:53 +02:00
Romain Malmain
2e5e2056b2
Faster fmt_all.sh (#2218)
* parallel fmt

* fix shellcheck

* fix shellcheck

* add check mode
2024-05-19 20:07:38 +02:00
Dominik Maier
31e1eee96e
Rename CurrentCorpusIdx -> CurrentCorpusId (#2216)
* Rename CurrentCorpusIdx -> CurrentCorpusId

* why ripgrep do you not find these

* ripgrep, why?
2024-05-19 18:12:45 +02:00
Dominik Maier
cf01d04151
Report 100% stability if no unstable edges are found (extends #2215) (#2217)
* Report 100% stability if no unstable edges are found

* Use metadtata

---------

Co-authored-by: sadeli413 <sadeli0x19d@gmail.com>
2024-05-19 14:41:28 +02:00
Romain Malmain
dfd3b3278e
QEMU command system refactoring (#2189)
* implemented generic command builder

* Added builder to `Emulator`.
2024-05-18 20:43:56 +02:00
cube0x8
3a087301ac
Fixed infinite loop on SyncDiskStage (#2193)
* Fixed infinite loop on SyncDiskStage

* cargo fmt

* added debug messages

* Add left to sync to metadata. Replace HashSet with Vec

* added check on state metadata to not crash in case it's None (start fuzzing without files to sync)

* fmt & clippy

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-05-18 20:25:38 +02:00
Max Ammann
6040133080
Use MultiMonitor when fuzzing in non-forking mode (#2192) 2024-05-18 20:24:41 +02:00
dependabot[bot]
8d54ee2c80
Update pyo3-build-config requirement from 0.18 to 0.21 (#2205)
Updates the requirements on [pyo3-build-config](https://github.com/pyo3/pyo3) to permit the latest version.
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.18.0...v0.21.2)

---
updated-dependencies:
- dependency-name: pyo3-build-config
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-05-18 20:22:35 +02:00
Aarnav
baf07445e4
add AFL stage names for calibration, colorization, power and sync stages (#2209)
* add AFL stage names for calibration, colorization, power and sync stages

* clippy

* add missing name field in sync stage

* use consts instead of hardcoding in functions.
change set_name to with_name for PowerMutationalStage
remove irrelevant fn transforming

* make AFL++ name default for all stages
2024-05-18 14:49:38 +02:00
Dongjia "toka" Zhang
22d8e92b08
Ci fix (#2212)
* bbb

* ccc
2024-05-18 13:42:03 +02:00
Dongjia "toka" Zhang
f8f9da2a15
Trying to fix CI (#2211)
* test

* aaa

* 4.38

* 4.37
2024-05-18 00:13:11 +02:00
8f652f754c WIP: complet rework of STG 2024-05-17 15:57:44 +02:00
Dongjia "toka" Zhang
d05adf7f6e
Delete leftover println! (#2203) 2024-05-17 13:35:38 +02:00
dependabot[bot]
0777873aae
Update prometheus-client requirement from 0.21 to 0.22 (#2197)
Updates the requirements on [prometheus-client](https://github.com/prometheus/client_rust) to permit the latest version.
- [Release notes](https://github.com/prometheus/client_rust/releases)
- [Changelog](https://github.com/prometheus/client_rust/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_rust/compare/v0.21.0...v0.22.2)

---
updated-dependencies:
- dependency-name: prometheus-client
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 14:27:37 +02:00
Dongjia "toka" Zhang
e31658b914
Change when to setup the ctrl c handler. (#2198)
* copy

* fmt

* aa

* a

* Goodbye z3, i hope i won't build you forever

* doc

* fmt

* fix

* aa
2024-05-16 14:27:14 +02:00
dependabot[bot]
41d41f25bf
Update reqwest requirement from 0.11 to 0.12 (#2196)
Updates the requirements on [reqwest](https://github.com/seanmonstar/reqwest) to permit the latest version.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.11.0...v0.12.4)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 14:11:52 +02:00
dependabot[bot]
7cf821bd82
Update toml requirement from 0.4.2 to 0.8.13 (#2195)
---
updated-dependencies:
- dependency-name: toml
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 14:06:53 +02:00
dependabot[bot]
b871037e70
Update cargo_toml requirement from 0.16 to 0.20 (#2194)
Updates the requirements on [cargo_toml](https://gitlab.com/lib.rs/cargo_toml) to permit the latest version.
- [Commits](https://gitlab.com/lib.rs/cargo_toml/compare/v0.16.1...v0.20.2)

---
updated-dependencies:
- dependency-name: cargo_toml
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-16 14:06:37 +02:00
Dominik Maier
34ec907456
Fix libafl_sugar docs build (#2188)
* Fix libafl_sugar docs build

* doc redoc

* fmt
2024-05-16 00:19:09 +02:00
Dongjia "toka" Zhang
c7303ace53
Static analysis pass (#2178)
* copy

* fmt

* aa

* a

* Goodbye z3, i hope i won't build you forever

* doc

* fmt
2024-05-15 16:50:20 +02:00
dependabot[bot]
6fe888d2bb
Update libloading requirement from 0.7 to 0.8 (#2183)
Updates the requirements on [libloading](https://github.com/nagisa/rust_libloading) to permit the latest version.
- [Commits](https://github.com/nagisa/rust_libloading/compare/0.7.0...0.8.3)

---
updated-dependencies:
- dependency-name: libloading
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 15:18:52 +02:00
dependabot[bot]
70333aaf94
Update typed-builder requirement from 0.16 to 0.18 (#2184)
---
updated-dependencies:
- dependency-name: typed-builder
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 15:18:14 +02:00
dependabot[bot]
e70b23fc6b
Update serde_yaml requirement from 0.8 to 0.9 (#2185)
Updates the requirements on [serde_yaml](https://github.com/dtolnay/serde-yaml) to permit the latest version.
- [Release notes](https://github.com/dtolnay/serde-yaml/releases)
- [Commits](https://github.com/dtolnay/serde-yaml/compare/0.8.0...0.9.34)

---
updated-dependencies:
- dependency-name: serde_yaml
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 15:17:38 +02:00
dependabot[bot]
167d25c3af
Update winsafe requirement from 0.0.18 to 0.0.20 (#2186)
Updates the requirements on [winsafe](https://github.com/rodrigocfd/winsafe) to permit the latest version.
- [Commits](https://github.com/rodrigocfd/winsafe/compare/v0.0.18...v0.0.20)

---
updated-dependencies:
- dependency-name: winsafe
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 15:17:17 +02:00
Sönke
e14eb26e8b
Add client_stats to OnDiskJSONMonitor (#2181) 2024-05-15 01:54:27 +02:00
Romain Malmain
b127f0579d
Regenerate QEMU binding stubs only for newer versions of the nightly compiler (#2177)
* Regenerate binding stubs only for newer versions of the nightly compiler.

* fmt

* clippy
2024-05-15 01:42:59 +02:00
s1341
19087f3dab
Windows frida support (#1607)
* WIP: windows frida

* frida-windows: fix hooks not present on windows

* windows: allow building using cargo xwin

* frida-windows: fmrt

* frida-windows: cleanup and allow asan/drcov on windows

* frida-windows: fmt

* frida-windows: fix clippy

* frida-windows: handle unknown exceptions gracefully

* frida-windows: rework shadow mapping algo

* frida-windows: add hook functions

* frida-windows: hook functions; fix stack register

* minibsod: enable for windows

* check_shadow: fix edge casees

* asan_rt: rework and add hooks for windows

* inprocess: add minibsod on windows

* Fix warnings

* minibsod: disable test on windows

* WIP: HookRuntime

* Cleanup after merge

* Bump frida-gum version

* Fix conflict marker; update frida

* Make winsafe windows-specific

* Fmt

* Format

* Better detection of clang++ (using cc)

* Make AsanErrors crate public so we can use it in tests

* Add helper to get immediate of operand

* Use HookRuntime to hook asan functions

Tests now passing

* fmt

* Implement recurisve jmp resolve

* Fix reversed logic

* windows_hooks: Don't die if functions are already replaced

* Allow utils to work on windows

* Enable allocator hooking on windows

* Warnings; add trace to free

* Make ASAN tests run windows (with cargo xwin compilation)

* Fmt

* clang-format

* clang-format

* Add more tests

* Fix partial range access bug in unpoisoning/shadow_check

* Merge main

* Fix check_shadow and implement unit tests

* Fix hooking and PC retrieval

* WIP: Working gdiplus fuzzing with frida-ASAN, no false positives

* LibAFL Frida asan_rt and hook_rt fixes for frida_windows (#2095)

* Introduce aarch64

* MacOS fix - MemoryAreas is broken on MacOS and just loops

* Introduce working aarch64 ASAN check

* Implement large blob

* Fix hook_rt for arm64

* Fix poison/unpoison

* Fix shadow check

* Update x86-64

* Fix aarch64 unused import

* Remove extraneous println statement

* merge main

* Fixes

* alloc: add tests, pass the tests

* HookRuntime before AsanRuntime, and don't Asan if Hooked

* hook_rt: Fixes

* Frida windows check shadow fix (#2159)

* Fix check_shadow and add additional tests

* add some additional documentation

* Revert to Interceptor based hooks

* fixes

* format

* Get rid of hook_rt; fixes

* clang-format

* clang-format

* Fix with_threshold

* fixes

* fix build.rs

* fmt

* Fix offset to RDI on stack

* Fix clippy

* Fix build.rs

* clippy

* hook MapViewOfFile

* fmt

* fix

* clippy

* clippy

* Missing brace

* fix

* Clippy

* fomrrat

* fix i64 cast

* clippy exclude

* too many lines

* Undo merge fails

* fmt

* move debug print

* Fix some frida things

* Remove unused frida_to_cs fn for aarch64

* name

* Don't touch libafl_qemu

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
Co-authored-by: Sharad Khanna <sharad@mineo333.dev>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
2024-05-14 10:45:56 +02:00
dependabot[bot]
dce0761b11
Update capstone requirement from 0.11.0 to 0.12.0 (#2170)
Updates the requirements on [capstone](https://github.com/capstone-rust/capstone-rs) to permit the latest version.
- [Release notes](https://github.com/capstone-rust/capstone-rs/releases)
- [Changelog](https://github.com/capstone-rust/capstone-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/capstone-rust/capstone-rs/compare/capstone-v0.11.0...capstone-v0.12.0)

---
updated-dependencies:
- dependency-name: capstone
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-05-13 21:09:02 +02:00
dependabot[bot]
9fa5f72080
Update serial_test requirement from 2 to 3 (#2171)
Updates the requirements on [serial_test](https://github.com/palfrey/serial_test) to permit the latest version.
- [Release notes](https://github.com/palfrey/serial_test/releases)
- [Commits](https://github.com/palfrey/serial_test/compare/v2.0.0...v3.1.1)

---
updated-dependencies:
- dependency-name: serial_test
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-05-13 20:59:46 +02:00
dependabot[bot]
5662105e75
Update which requirement from 4.4 to 6.0 (#2172)
Updates the requirements on [which](https://github.com/harryfei/which-rs) to permit the latest version.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/harryfei/which-rs/compare/4.4.0...6.0.1)

---
updated-dependencies:
- dependency-name: which
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-05-13 20:59:36 +02:00
Dominik Maier
667ce328fc
Fix MacOS CI race condition (#2176) 2024-05-13 20:57:45 +02:00
Dominik Maier
6b76b6ea98
Revert "Update zip requirement from 0.6 to 1.2 (#2169)" (#2174)
This reverts commit c621a5e4753ad6bce4b02084971d14d6d6b4e02a.
2024-05-13 20:25:54 +02:00
Romain Malmain
b0d95676f9
Fix regex fixing generated bindings for QEMU (#2163)
* Fix regex fixing generated bindings

* Do not write 2 times bindings to filesystem

* Update stub bindings

* fmt

* clippy

* fmt

* use `unsafe extern "C"` instead of `extern "C"`.
2024-05-13 17:41:56 +02:00
dependabot[bot]
c621a5e475
Update zip requirement from 0.6 to 1.2 (#2169)
Updates the requirements on [zip](https://github.com/zip-rs/zip2) to permit the latest version.
- [Release notes](https://github.com/zip-rs/zip2/releases)
- [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zip-rs/zip2/compare/v0.6.4...v1.2.3)

---
updated-dependencies:
- dependency-name: zip
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 17:22:16 +02:00
Dongjia "toka" Zhang
7a464c4c87
Dependabot (#2168) 2024-05-13 17:21:00 +02:00
Dongjia "toka" Zhang
bf4d1de7cd
Remove observer_stdout/observer_stderr from Observer trait (#2167)
* stuff

* upd

* cargo test

* doc

* fmt

* nyx stuff
2024-05-13 17:10:55 +02:00
Dominik Maier
5872d24021
Clippy for apple after #2162 (#2166) 2024-05-13 14:30:09 +02:00
Romain Malmain
edb6b509c2
Generate stub bindings less aggressively. (#2164)
Emit warning when using runtime files for an incompatible architecture.
2024-05-13 11:58:19 +02:00
David CARLIER
1cf3df665a
Switch MiniBSOD to mach crate for Apple (#2162) 2024-05-12 18:37:11 +02:00
Kevin Phoenix
3328f06de4
Add qemu runtime defs for aarch64 (#2151) 2024-05-12 15:39:55 +02:00
Langston Barrett
f17a45dcc3
bolts: Fix feature name in assert (serde{,any}_autoreg) (#2160) 2024-05-12 13:20:03 +02:00
Dongjia "toka" Zhang
7c9ac6d4b5
Revert "Adding ExitCodeObserver and ExitSignalObserver (#2138)" (#2157)
This reverts commit ee7dafae4100397698e5266465919bfdbc40af51.
2024-05-08 15:26:07 +02:00
Valentin Huber
ee7dafae41
Adding ExitCodeObserver and ExitSignalObserver (#2138)
* Adding ExitCodeObserver and ExitStatusObserver

* Introducing ExitKind::Interrupted
2024-05-08 15:17:24 +02:00
Addison Crump
614b149cae
Fix cfg uses across codebase (#2154)
* start fixup of cfgs

* whoops

* remaining issues

* maybe fixup macos

* apparently that is ios code?

* fix no_std

* Re-enable tcp_compression

* fix tcp broker

* remove tcp_debug flag

* fmt

* clippy

* less unwrap while we're at it

* doc

* add back pub star uses for libafl_qemu

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
2024-05-08 14:31:10 +02:00
Max Ammann
f6d2eaacb4
Fix libafl_libfuzzer's compatibility with LLVM 14 (#2136)
* Always use Rust's nm instead of host system one

* Fix formatting

* Fix formatting
2024-05-08 13:53:12 +02:00
ba3850cf4d remove stg feedback from systemstate flag 2024-05-08 12:49:40 +02:00
3f9a2ed6c0 trace executed abbs, instead of states 2024-05-08 12:30:10 +02:00
David CARLIER
695efeab42
bolts: Fix minibsod build on apple (#2155) 2024-05-08 05:31:13 +02:00
Dominik Maier
c97c8cf83e
Rename Handler -> Handled, various other cleanups after #2142 (#2152)
* Handle name cleanup after #2142

* Handleable -> CanBeHandled

* CanBeHandled -> Handled

* clippy

* forgot one

* Handled more
2024-05-07 19:23:13 +02:00
Addison Crump
c1a55982b6
Stable type_eq (#2150)
* stable type eq

* whoops, wrong section

* satiate clippy

* remove extraneous comment

* explain

* bonus inline
2024-05-07 17:09:15 +02:00
Dongjia "toka" Zhang
e7e820868c
Change special exitcode from 137 to 9 in simple.rs too (#2153) 2024-05-07 14:31:19 +02:00
Romain Malmain
bed500471a
QEMU generic memory iterator (#2148)
* QEMU generic memory iterator + Refactoring

* Generic Memory Iterator (systemmode only for now): It is now possible to iterator over memory ranges, independently of the address kind

* Refactoring or Emulator / Qemu structures: they are now handled separately in different files

* Refactoring of Exit Handlers: Result / Error structs have been clarified

* Simple handler for signals

* add new `check-cfg` calls for libafl qemu
2024-05-07 10:46:15 +02:00
cube0x8
a16fb88f3e
Add null ptr to devices vec (QEMU systemmode) (#2141) 2024-05-06 23:19:30 +02:00
88c5c8a19f feedback for aggregated traces 2024-05-06 16:00:11 +02:00
Dongjia "toka" Zhang
4562f19bdc
Qemu ctrl c exit (#2147)
* fix

* ignore

* fix

* aaa

* bbb
2024-05-06 15:42:43 +02:00
0393f18a47 add stg edge feedback 2024-05-06 14:46:35 +02:00
Dongjia "toka" Zhang
b0d592dc3a
Add to how to leave tui screen (#2146) 2024-05-05 17:21:15 +02:00
Dongjia "toka" Zhang
d4ff7b86b1
Add windows test & ci & fix (#2144)
* fix

* ignore

* fmt

* a
2024-05-05 14:53:27 +02:00
Dongjia "toka" Zhang
502929d967
Separate map observers (#2143)
* rename

* rename

* fmt

* fix

* fmt

* separate observers

* doc fx
2024-05-04 23:11:00 +02:00
Dongjia "toka" Zhang
b0ac25a7b5
Rename Reference to Handle (#2142)
* rename

* rename

* fmt

* fix

* fmt
2024-05-04 18:16:28 +02:00
Dongjia "toka" Zhang
41ff7438eb
Fix incrementing found_objective(#2139) 2024-05-03 23:30:14 +02:00
Langston Barrett
382673b173
GenStage: A stage for generational (e.g., black-box) fuzzers (#2137)
* GenStage: A stage for generational (e.g., black-box) fuzzers

* mv stages/{gen,generation}.rs

* Fix doc link

* `GenStage`: Alphabetize type parameters

* Fighting rustdoc
2024-05-03 19:18:14 +02:00
Dongjia "toka" Zhang
f75c5ff4d3
Add found_objectives metadata (#2093)
* try

* add stuff

* clp

* Move to counter, remove penalization

* fix

* even milder

* fix

* clp

* no score

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
2024-05-03 16:37:05 +02:00
3453d02b1d fix fuzzing loop returning nothing 2024-05-03 13:28:49 +02:00
d93ed809f1 improve stg parsing 2024-05-03 13:28:15 +02:00
Valentin Huber
7fe0c576db
Make CommandExecutor Generic on the specific Input (#2129) 2024-05-02 15:39:06 -04:00
Dongjia "toka" Zhang
2e81dc6c59
Fix DDFuzz instrumentation (#2134) 2024-05-02 20:00:51 +02:00
Romain Malmain
02ef0c4dda
fix qemu systemmode fuzzers exit code (#2133) 2024-05-02 16:27:07 +02:00
Stefan Zabka
ec944a0ea4
Allow setting stdout_file in non-fork launcher (#2127)
* fix(launcher.rs): hide file output behind appropriate feature flag

discovered while debugging #2111

* fix(launcher.rs): implement stdout/stderr piping for non-forking unix

* hide all accesses to stdout_file in cfg blocks

* Conditionally add stdout_file config in frida_gdiplus
2024-05-02 10:24:36 -04:00
Romain Malmain
2302f1b35c
Fix QEMU doc not building (again) (#2130)
* fix doc not building.
2024-05-02 15:17:35 +02:00
Dongjia "toka" Zhang
359e94ec97
ctrl c handler fix for non-fork mode (#2132)
* poc

* ai suggestion

* rename this

* aaaa

* fmt

* simplify

* delete blob

* ignore

* fixup?

* some progress on cow-ification

* some more

* clippy fixes, finalise tests

* whoops, missed a spot

* no std compat

* api change: Named now requires alloc feature

* doc fix

* missed a spot

* additional fixes

* libfuzzer fixes

* fix tutorial

* fix

* add

* aa

* fix tutorial

* fix

* Rename

* fix

* aa

* fmt

* aa

* aa

* another closure

* clp

* fix stuff

* fix non fork

* fmt

---------

Co-authored-by: Addison Crump <addison.crump@cispa.de>
2024-05-02 14:43:25 +02:00
cube0x8
c79cdc89ac
add mmap hooks to libqasan (#2122)
* add mmap hooks to libqasan

---------

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
2024-05-02 10:39:33 +02:00
Romain Malmain
935100e7a7
Qemu update to latest version + various fixes (#2119)
* Fix maps iterator

* Added paranoid debug feature.

* Fix snapshot bugs.

* Update qemu-libafl-bridge.

* Added auto-generation of `x86_64_stub_bindings.rs` .

* Fix sync_exit calling to stopped CPU.
2024-05-02 09:31:54 +02:00
Dongjia "toka" Zhang
2f7c19e2b1
Change centralized launcher signature (#2094)
* poc

* ai suggestion

* rename this

* aaaa

* fmt

* simplify

* delete blob

* ignore

* fixup?

* some progress on cow-ification

* some more

* clippy fixes, finalise tests

* whoops, missed a spot

* no std compat

* api change: Named now requires alloc feature

* doc fix

* missed a spot

* additional fixes

* libfuzzer fixes

* fix tutorial

* fix

* add

* aa

* fix tutorial

* fix

* Rename

* fix

* aa

* fmt

* aa

* aa

* another closure

* clp

* fix stuff

---------

Co-authored-by: Addison Crump <addison.crump@cispa.de>
2024-04-30 19:44:57 +02:00
Dongjia "toka" Zhang
b23180394b
Fix Ctrl-C Handler (#2124)
* fix

* fix

* win

* win clp

* a

* FMT

* aaaaaaaaaaa

* aa

---------

Co-authored-by: Your Name <you@example.com>
2024-04-30 17:18:39 +02:00
clesmian
61ac4ea7be
Improve OnDiskTOMLMonitor (#2125)
* Allow for more frequent updates of TOML monitor

* Don't skip first client

* Reduce code duplication

* Immediately write first TOML file

* Rust fmt

* Use same client numbering as other monitors

* Fmt
2024-04-30 09:05:33 -04:00
Gregory Petrosyan
b49ab999e3
libafl_bolts: rands super mega ultra giga house cleaning of doom (#2123)
* rands: simpler rand_trait code, remove useless test

* rands: provide and use proper random_seed()

* rands: add missing golden tests

* Don't use current_nanos() for seeding

* rands: remove RandomSeed trait
2024-04-29 11:00:44 -04:00
Dongjia "toka" Zhang
50f14d44fa
Restrict more on edges map API (#2117)
* fix

* fix

* feature guard

* use

* cannnot find

* fmt

* more

* fix

* fix

* more

* fucking fmt just shut

* rename and change stuff

* fix

* fix

* fixxxxxxxxxx
2024-04-29 16:28:40 +02:00
Langston Barrett
b0248461e2
Allow for AsIter(Mut)/AsSlice(Mut) to be implemented in safe Rust (#2120)
* Generalize `AsIter` to allow iterating over contents of a `RefCell`

Towards `MapObserver`s in safe Rust.

* Helpers for `RefCellValueObserver`

* MapObserver: Return owned Self::Entry from .get()

`Self::Entry` is `Copy`, so there's not much value in returning a
reference from `get()`. Futhermore, returning a reference limits the
possible implementations of `MapObserver`, because it forces the
borrow/reset to outlive the body of the method.

* MapObserver: Replace `.get_mut()` with `.set(idx, val)`

Like the previous commit, this is intended to expand the possible
implementations of `MapObserver` to types with interior mutability,
which can't necessarily loan out their content.

* Make `RefCellValueObserver` into a safe `MapObserver`

* as iter mut

* as slice (mut): allow for non-& refs

* nostd

* CI round 1

* cleanup + AsSlice defs for RefCellValueObserver

* clippy fixes

* avoid unnecessary imports

* whoops, too aggressive

* use deref instead of as slice

* whoops

* fix as slice conditional importing in stable

---------

Co-authored-by: Addison Crump <addison.crump@cispa.de>
2024-04-27 18:36:56 +02:00
Addison Crump
28c43b332f
Match by Ref fix (#2105)
* match by ref fix

* impl Named for Reference

* rename

* magic indexing

* whoops

* docs, clippy

* some additional CI complaints

* other libafl_qemu fixes

* missed an alloc feature

* a smattering of fixes

* use from not direct construction

* tinyinst fix

* horrible double-mutability things

* fixup nyx

* from not new

* forkserver_simple fixes

* dogfood: forkserver

* mmmm yummy dogfood

* round one CI fixes

* clippy appeasement

* deref generic impl to simplify usage

* adaptive serialization (ouch)

* remaining clippy items

* I am tired

* new not with

* fixup: aflpp tracing was not actually constructable

* fix tmin

* reduce complexity of map feedback now that we do not need to constrain

* frida fixes

* fix concolic

* type_ref => reference
2024-04-27 18:08:09 +02:00
Dongjia "toka" Zhang
084b9b5878
Batch timeout fix (#2109)
* fix

* FMT

* unused
2024-04-26 17:10:36 +02:00
Aarnav
32963be453
add crash_exitcode to Forkserver to accomodate AFL_CRASH_EXITCODE (#2107)
* add crash_exitcode to Forkserver to accomodate AFL_CRASH_EXITCODE

* make crash_exitcode i8

---------

Co-authored-by: aarnav <aarnav@srlabs.de>
2024-04-26 16:24:25 +02:00
Addison Crump
c2e0e8ddbe
Add recv_blocking_with_flags (#2102)
* add recv_blocking_with_flags

* rollback, whoops
2024-04-26 16:22:32 +02:00
Dongjia "toka" Zhang
abcb2bf33e
Remove jobs dependency in CI (#2108) 2024-04-25 16:07:38 +02:00
Addison Crump
4c95d9029a
Split android and ios tests (#2106)
* split android and ios tests

* whoops
2024-04-25 12:23:46 +02:00
Romain Malmain
dd0fbff819
Small refactoring of libafl_qemu structure (#2098)
* Architecture-specific stuff is now in the `arch` directory

* Helpers are now in the `helpers` directory

* `emu.rs` has been moved as `emu/mod.rs` for consistency with the rest of the repository
2024-04-24 21:47:29 +02:00
Dongjia "toka" Zhang
c622a28eba
Rename from ReReference to Reference (#2099) 2024-04-24 15:06:33 +02:00
Gregory Petrosyan
1e8667a9f9
libafl_bolts: more rands improvements (#2096)
* rands: add missing inline directives

See:
- https://nnethercote.github.io/perf-book/inlining.html
- https://users.rust-lang.org/t/enable-cross-crate-inlining-without-suggesting-inlining/55004/6

* rands: better fast_bound() signature
2024-04-24 14:01:37 +02:00
Stefan Zabka
0f42efa12b
refactor(snapshot.rs): use const generics (#2069)
* refactor(snapshot.rs): use const generics

* Add docs to read hooks

---------

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
2024-04-24 11:58:46 +02:00
Dongjia "toka" Zhang
176659821a
Add TypeRefCreator trait (#2065)
* poc

* ai suggestion

* rename this

* aaaa

* fmt

* simplify

* delete blob

* ignore

* fixup?

* some progress on cow-ification

* some more

* clippy fixes, finalise tests

* whoops, missed a spot

* no std compat

* api change: Named now requires alloc feature

* doc fix

* missed a spot

* additional fixes

* libfuzzer fixes

* fix tutorial

* fix

* add

* aa

* fix tutorial

* fix

* Rename

* fix

* aa

* fmt

* aa

---------

Co-authored-by: Addison Crump <addison.crump@cispa.de>
2024-04-23 19:03:30 +02:00
6774a778c3 add wip stg tracer 2024-04-23 16:53:55 +02:00
Aarnav
76a95bc5fd
Introduce AFL_EXIT_ON_SEED_ISSUES (#2085)
* introduce load_initial_inputs_disallow_solution to exit if a solution is found during seed loading

* fmt

* rename CorpusError to Corpus

* add LoadConfig to simplify configuration for loading initial inputs

* Rename Error::Corpus to Error::InvalidCorpus
Add documentation to LoadConfig struct
fix nostd for LoadConfig

---------

Co-authored-by: aarnav <aarnav@srlabs.de>
2024-04-23 15:53:18 +02:00
Josef Haider
d34965192d
Add FeedbackFactory implementations for CrashFeedback, CombinedFeedback and DiffFeedback. (#2060)
* Add FeedbackFactory implementations for CrashFeedback, CombinedFeedback and DiffFeedback

* remove redundant type CrashFeedbackFactory
2024-04-23 15:48:52 +02:00
Gregory Petrosyan
e1b8c9b5d8
libafl_bolts: improvements to the rands module, add next_float (#2086)
* rands: use splitmix64 for seeding

Seeding with splitmix64 is a good way to avoid starting with
low-entropy PRNG states, and is explicitly recommended
by the authors of both xoshiro256++ and Romu.

While at it, give the xoshiro256++ PRNG its proper name.

* rands: use fast_bound() to generate number in range

* rands: add top-level choose()

* rands: add Rand::next_float()

* rands: add Rand::coinflip() helper

* libafl: unbreak tests that relied on direct seeding

* rands: add SFC64 PRNG

SFC64 is a well-established and well-understood PRNG designed by
Chris Doty-Humphrey, the author of PractRand. It has been tested
quite a lot over the years, and to date has no known weaknesses.

Compared to xoshiro256++, it is slightly faster and is likely to
be a more future-proof design (xoshiro/xoroshiro family of generators
come with quite long history of [flaws][1] found over the years).

Compared to Romu, it is slightly slower, but guarantees absense
of bias, minimum period of at least 2^64 for any seed, and
non-overlapping streams for different seeds.

[1]: https://tom-kaitchuck.medium.com/designing-a-new-prng-1c4ffd27124d
2024-04-23 15:37:28 +02:00
Dongjia "toka" Zhang
5ff709f241
Symcc Update (#2047)
* symcc upd

* upda

* fix

* fmt

* mm

* psu

* psh

* fix

* fix

* fix

* tmate

* can't make it work

* i really hate you llvm

* real name

* mm
2024-04-23 13:34:46 +02:00
Romain Malmain
2046cfe82d
Checkout before filter (#2092) 2024-04-23 09:45:45 +02:00
Dongjia "toka" Zhang
ea6a36b0a5
fix (#2091) 2024-04-22 21:55:55 +02:00
Dongjia "toka" Zhang
0f3ad288e7
Fix #1932 (#2089)
* fix

* Stupid lint

* increase rate

* fix
2024-04-22 19:27:13 +02:00
Romain Malmain
98863fbff5
Only run QEMU tests if there is a QEMU-related change. (#2090)
* Only run QEMU tests if there is a change.

* fmt.
2024-04-22 19:14:23 +02:00
Romain Malmain
fef6c8d1b1
Run qemu_systemmode tests with self-hosted runners (#2018)
* run qemu fuzzers (qemu_systemmode only for now) in self-hosted runners

* Remove qemu-related fuzzers to general fuzzers

* fix

* Install dependencies before anything else

* Do not use sudo

* Install sudo

* Revert "Install dependencies before anything else"

This reverts commit 107addad5d9f68dec5a9af50831112cd72c28f4d.

* added qemu specific prerequisites

* add -y flag

* Format with nightly

* Do not use nightly only.
Install fmt and clippy for stable as well.

* Install qemu-img for qemu

* fix qemu-img install

* apt update

* Changed timeout.

* Fix qemu_systemmode test

* fmt

* clippy + decorrelate build and run for qemu_systemmode.

* fix fuzzer

* clippy

* add sqlite3-dev to package prerequisites.

* add arm-none-eabi-gcc

* fix profile dir

* fix condition.

* Run less QEMU stuff faster

---------

Co-authored-by: Toka <tokazerkje@outlook.com>
2024-04-22 18:17:22 +02:00
Tobias Mayer
fe64d10a5c
Fix typo in setup_libxml2.sh (#2088)
exit for a non-zero exit code
2024-04-22 14:37:41 +02:00
Dongjia "toka" Zhang
2df71e7a36
Faster cargo check (#2084)
* speed up cargo check

* fix

* composite

* plural

* wrong name

* go brrrrrrrr

* bash

* aaaaa

* why not even more?

* more composite

* fix

* miri

* test for llvm >= 16

* v2

* v2

* naaaa

* JUST MORE INSTANCES

* aa

* fix

* no bash for windows

* reduce a bit as some guys are delayed

* no deps
2024-04-20 10:50:43 +02:00
Addison Crump
fd364d15fe
cargo-fuzz testing (#2081)
* Build cargo-fuzz end to end

* Workaroudn failing CI

* Fix toml

* Build

* Exclude from workspace

* Fix version

* Fix workspace

* Fix workspace

* FIx workspace

* Fix path

* Set path correctly

* Install llvm-tools

* Test with distro llvm installed

* Use build

* complete

* remove from includes

* add back fuzzer tests, format

* add test for whether all fuzzers are actually tested in pipeline

* whoops

* I hate CI I hate CI I hate CI

* revert removal of llvm

* sh compatibility

* sigh

---------

Co-authored-by: Max Ammann <max@maxammann.org>
2024-04-19 23:55:28 +02:00
Dongjia "toka" Zhang
ea549b9cfe
Add a warning to say never use EDGES_MAP.len() (#2083)
* Revert "Revert splitting libafl_edges_map_max and libafl_edges_map_in_use (#2…"

This reverts commit c68b3816fb680b635f99c337f78185e699864705.

* all

* more

* add

* add
2024-04-19 23:26:00 +02:00
Dongjia "toka" Zhang
e8cc1ba93d
Revert "Revert splitting libafl_edges_map_max and libafl_edges_map_in_use" (#2082)
* Revert "Revert splitting libafl_edges_map_max and libafl_edges_map_in_use (#2…"

This reverts commit c68b3816fb680b635f99c337f78185e699864705.

* all

* more
2024-04-19 19:03:58 +02:00
edwin1729
c238b69498
Implement Hash for MapObserver (#1989)
* MapObserver implements Hash

* Rename the hash utility function (in MapObserver) to hash_easy

* Use hash_slice as a helper function to impl Hash trait

* define_python_map_observer macro implements Hash trait

* Also rename hash_easy to hash_simple

* Rename hash_slice to hash_helper

* hash_helper is used to define the implementation of hash function/trait

* Factor out the Hash trait and function for runtime library structs (#1977)

* Simplify hash_simple (of trait MapObserver) (#1977)

 * Use hash_one function to make hash_simple a one-liner

* remove hash_helper

---------

Co-authored-by: Edwin Fernando <ef322@ic.ac.uk>
Co-authored-by: Addison Crump <addison.crump@cispa.de>
2024-04-19 15:06:14 +02:00
Addison Crump
04cd792df2
fix libfuzzer by simply adding the needed feature (#2080) 2024-04-19 13:35:35 +02:00
Dongjia "toka" Zhang
c68b3816fb
Revert splitting libafl_edges_map_max and libafl_edges_map_in_use (#2079)
* fix

* aa

* push

* fix

* fmt
2024-04-19 13:24:25 +02:00
Tobias Mayer
d7ac802fb2
Update libafl_nyx to newest qemu-nyx and nyx-packer, fixing some problems with build_nyx_support.sh. Providing Makefile for bug in qemu-nyx (#2070)
Co-authored-by: ganbarutobi <ganbarutobi@gmail.com>
Co-authored-by: Romain Malmain <romain.malmain@pm.me>
2024-04-19 10:41:55 +02:00
Addison Crump
276bfc6386
tee not pipe (#2078) 2024-04-18 18:23:57 +02:00
Romain Malmain
84a432dab2
fix import (#2076) 2024-04-18 15:43:21 +02:00
mkravchik
2b18562b08
Fixing the inconsistency btw #2012 and #2066 (#2074) 2024-04-18 13:33:29 +02:00
Romain Malmain
39c32d55e7
Fix main not passing CI tests (#2075)
* Fix sancov import

* fmt

* fmt
2024-04-18 13:33:18 +02:00
mkravchik
886519b10c
Pr/fixing forkserver libafl cc (#2066)
* Fixing forserver_libafl_cc

* Adding tests and showing user stats

* Restoring the map truncation

* Fmt

* small fix

* fix

* fix

* fix

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-04-17 18:28:34 +02:00
Dongjia "toka" Zhang
c50af44099
Split edges_map_size and edges_map_size_alloc (#2012)
* two sizes

* rename

* build.rs

* rename

* capital

* FMT

* macro

* fuck

* fff
2024-04-17 17:58:08 +02:00
Addison Crump
467c6d7582
missed a spot (#2063) 2024-04-17 16:24:15 +02:00
Dongjia "toka" Zhang
7595b2e5c9
Debugging tips upd (#2062) 2024-04-17 16:01:33 +02:00
Addison Crump
edcff3889c
fixup: fix some missing tracking hints (#2058) 2024-04-17 14:34:06 +02:00
Dongjia "toka" Zhang
8bce605503
DDFuzz (#2056)
* push

* add

* book

* ddg

* works
2024-04-16 16:51:28 +02:00
Romain Malmain
bc3ef5952b
Rework of libafl_qemu configuration (#2054)
* LibAFL QEMU can now be dynamically linked
* LibAFL QEMU reconfiguration happens less frequently (now using a signature check)
* Possibility to have custom rpath in QEMU
2024-04-16 11:35:15 +02:00
Dongjia "toka" Zhang
da6118e61e
Debugging tips (#2048)
* push

* add

* book
2024-04-15 13:40:54 +02:00
David CARLIER
4ec50d6a10
bolts: core affinity simplification for freebsd (#2049)
since 13.1 (EOL since mid-2023) , supports the sched affinity api like linux/dragonflybsd.
2024-04-14 10:29:32 +02:00
Dongjia "toka" Zhang
0c68ff033f
Readme Update (#2046) 2024-04-12 23:29:23 +02:00
Dongjia "toka" Zhang
cbb323f26c
LibAFL 0.12 (#1823) 2024-04-12 18:42:14 +02:00
Addison Crump
3d702f403b
Implement CanTrack tracking enforcement through rust types (#1886)
* sample implementation of tracking enforcement (incomplete)

* helpful compiler output

* make it look like a real compiler output

* ensure that the macro may be used outside of libafl

* separate index/novelty tracking funcs

* default const generic values so that we don't need to change this everywhere

* fix tests

* rollback unnecessary specification of stdmapobserver

* register metadata in doc tests

* doc fixes

* doc cleanup

* doc cleanup 2

* reduce implementor overhead to zero

* renaming/docs fixes

* asref isn't reflexive??

* generalization stage updates

* add better documentation about require_{indices,novelties}_tracking

* remaining generic updates

* round one CI pass (knowingly introduces breaking changes)

* typo

* round 2 clippy

* rollback: libafl_frida changes

* fmt

* moar porting

* fix remaining fuzzers

* fix windows build, maybe

* fixup libafl_libfuzzer

* fmt nighlty all the things

* attempt to fix some broken additions

* fix fmt

* oops

* fix new invocation

* minimizer scheduler fixes

* fix accounting

* rename

* fix

* Fix build

* Sort generics

* Move more generics into the right place

* Rename A -> C

* Fix test

* Fix test some more

* Fix doc some more

* critical formatting

* More A->C

* CanTrack harder

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
2024-04-12 18:33:52 +02:00
Romain Malmain
ec935bf95f
Fix GuestMaps iterator in LibAFL QEMU. (#2041)
* Fix maps iterator.

* Use native QEMU structs instead of pointer casting.

* Update stub bindings.

* Maps operations stored in usermode.
2024-04-12 14:40:53 +02:00
Maurice
8b9b5a8767
Introduce StdOutToMetadataFeedback and StdErrToMetadataFeddback (#2042)
* introduce `StdOutFeedback` and `StdErrFeddback`

* hide behind "std" feature flag

* update

* update
2024-04-12 14:26:47 +02:00
Dominik Maier
2f618b62d7
Rename HasAFLSchedulerMetadata to simply AflScheduler (it doesn't hold a Metadata at all) (#2043) 2024-04-12 13:24:00 +02:00
Dominik Maier
0f778b5892
Order differential generics alphabetically (#2044) 2024-04-12 12:14:49 +02:00
Maurice
631b1746e2
libafl_nyx: Add support for StdOutObserver (#2033)
* libafl_nyx: Add support for `StdOutObserver`

* reset file offset

* update example fuzzers

* fix
2024-04-11 18:24:32 +02:00
Romain Malmain
94a2a2363a
Add CPUArchStatePtr to backdoor signature (#2038) 2024-04-11 17:30:59 +02:00
Dongjia "toka" Zhang
287d1ac7c7
Add HasAdaptiveSerializer trait. (#2040)
* fix

* revert test

* add

* a

* check
2024-04-11 15:36:08 +02:00
Stefan Zabka
48463d079b
Fix error handling in libafl_qemu_build (#2036)
* fix(libafl_qemu_build): assert command success

* fix(libafl_qemu_build): make sure linker_interceptor.py picks up correct compiler

Currently linker_interceptor.py uses 'cc' as the __LIBAFL_QEMU_BUILD_CC environment variable is never set

* remove redudant arg
2024-04-10 18:36:36 +02:00
Dongjia "toka" Zhang
0d5c6219d8
Dedup CentralizedEventManager's serialize_observers() (#2034)
* why

* clp
2024-04-10 16:13:03 +02:00
WorksButNotTested
374f8735fa
Implement user-space QEMU ASAN (#1806)
* Implement user-space QEMU ASAN

* Fix wrong cfgs

* fmt

* merge conflicts in libafl qemu

* A few more fixes to qemu_launcher

* Change commit of qemu-libafl-bridge

* Fix clippy in qemu_launcher

* Fix commit id again

* Empty commit to trigger CI

* Fix path to fuzzer for test in qemu_launcher?

* Revert location of target binary and show the full error log from qemu_launcher test

* Appease the clippy gods

* Empty

* Fix format

---------

Co-authored-by: Your Name <you@example.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2024-04-10 01:11:28 +02:00
Aarnav
47c41c2925
Introduce disabled testcases for splicing (#1932)
* introduce disabled field to Testcase

* separate executor's processing of execution (adding to corpus/solution/discarding) and execution of input

* introduce add_disabled_input function

* enable splicing mutators to fetch disabled inputs

* reset modified example

* clean up

* update docs

* update docs for count_with_disabled

* fix random_corpus_id for splicing mutator not considering disabled entries

* fmt

* update docs

* clippy

* fix corpus_btreemap not working

* fix clippy warnings

* fix python bindings

* typo in count_with_disabled implementations

* fix certain splicing mutators not considering disabled inputs

* rename count_with_disabled to count_all

* introduce count_disabled function

* update docs for count_all, count_disabled and count

* * introduce get_from_all and nth_from_all for corpus implementations so get() and nth() do not silently fetch disabled entries.
* remove boolean flag from random_corpus_id which allowed inclusion of disabled ids and make it into a new function random_corpus_id_with_disabled
* update docs

* remove boolean is_disabled flag from corpus::insert and make it into a separate function insert_disabled

* rename do_insert to _insert

* make get_from_all inline for cached and inmemory

* add missing functions implementation for PythonCorpus
prevent writing feedback when adding disabled testcases

* fix nth_from_all overfetching enabled corpus entries

* fix clippy & rename execute_with_res to execute_no_process

* refactor _insert for corpus_btreemap

* make LibfuzzerCorpus and ArtifactCorpus to accomodate disabled entries

* fix typo

* fix missing docs for map field

* fix clippy

* test

* (hopefully) fix CachedOnDiskCorpus using incorrect corpus when caching testcase

* fix typo in inmemory_ondisk leading to fetching disabled entry from enabled corpus

---------

Co-authored-by: aarnav <aarnav@srlabs.de>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-04-10 01:03:00 +02:00
David CARLIER
d3b3d5d462
bolts: add time ticks method for arm (#2032) 2024-04-10 01:01:27 +02:00
Dongjia "toka" Zhang
c4f076356f
Fix the OOM exit code from 137 to 9 (#2029)
* i don't know if there really exit 137

* change message

* not 137 but 9
2024-04-09 17:16:25 +02:00
Romain Malmain
33c6ea1ae4
Fix libafl_qemu python bindings and example (#2030) 2024-04-09 16:09:47 +02:00
Mrmaxmeier
f252469d86
CI: A few updates and fixes (#2023)
* CI: Don't run cargo clean in order to preserve build caches

* CI: run yaml formatter >:)

* CI: try sharing build caches between similar jobs

* CI: it looks like the `ucd-generate` tool is not used anymore

* CI: Sneak in merge queue support :)

* CI: split out `cargo fmt --check` job

* libafl_qemu injections: be more resilient about mapping paths
2024-04-09 12:55:07 +02:00
Dominik Maier
2cc560e727
Tiny clippy fix for qemu_launcher fuzzer (#2026) 2024-04-09 12:49:42 +02:00
Dominik Maier
ef25aef471
Fix docs for frida (see #2025) (#2027) 2024-04-09 12:48:24 +02:00
Dominik Maier
7479726c3e
Un-Unfix libafl_qemu fixes after #2020, remove python CI (#2024)
* Un-Unfix libafl_qemu fixes after #2020

* remove CI for removed python bindings
2024-04-08 22:06:40 +02:00
Dongjia "toka" Zhang
ed5a10d0b5
Inter-job dependency on ubuntu ci (#2021)
* inter-job dependency.

* conc
2024-04-08 19:42:59 +02:00
Dominik Maier
a0a6d0e5cc
Fix yml file for CI (#2022) 2024-04-08 19:42:37 +02:00
Dominik Maier
f19302c9b1
Bring back python bindings for sugar,qemu (partially revert #2005) (#2020)
* Bring back python bindings for sugar,qemu (partially revert #2005)

* sugarman, won't you hurry

* Test?
2024-04-08 19:36:54 +02:00
Dongjia "toka" Zhang
e8fe5bb614
Move HasMetadata/HasNamedMetadata trait to libafl_bolts (#2016)
* move around

* fmt

* rev

* fmt

* doc job

* name

* move to libafl

* separate even more

* miri
2024-04-08 19:24:56 +02:00
Dominik Maier
ff938261df
Fix Clippy on MacOS for qemu, accept some clippy::missing_transmute_annotations suggestions (#2009)
* Fix Clippy/CI

* Ignore transmute annotations in pybind

* fix

* more clippy

* more clippy

* fix fixes
2024-04-08 16:24:10 +02:00
Dongjia "toka" Zhang
fa58dff4b7
concurrency (#2017) 2024-04-08 15:20:42 +02:00
Andrea Fioraldi
e29897dd44
Fix GuestMaps in userspace LibAFL QEMU (#2013) 2024-04-08 08:30:23 +02:00
Dongjia "toka" Zhang
159da0d311
Change when weighted scheduler make new table & don't update global metadata in on_remove/on_replace (#2011)
* fix

* backtick
2024-04-07 17:24:27 +02:00
Dongjia "toka" Zhang
527b892c1d
Separate fuzzer test in CI (#2010)
* ci

* ci

* ci

* aa

* aa

* a

* a

* a

* fix

* no fail fast

* system

* what is this lint...

* a

* clp

* disk

* ok no fastfail

* no qemu for now, reenable monday
2024-04-06 21:01:57 +02:00
Dongjia "toka" Zhang
4901846588
Remove python bindings (#2005)
* delete python bindings

* fix

* example

* fix
2024-04-06 15:16:46 +02:00
Tobias Mayer
24fd098e66
Update Dockerfile to work for nyx (#2008)
Missing file to build libafl_nyx in Docker
2024-04-06 04:48:50 +02:00
Dongjia "toka" Zhang
17aae94efc
Move some C functions to Rust from sancov_cmp.c (#2003)
* some

* a

* clp

* aa

* just new line

* fix

* fxi

* fix
2024-04-06 01:03:01 +02:00
Dongjia "toka" Zhang
90c627a7e7
revert large map (#2004) 2024-04-05 17:06:47 +02:00
Dominik Maier
1c85c3af13
Add option to enabled/disable client stats and fix #1771 (#2001)
* Add option to enabled/disable client stats and fix #1771

* more fix

* fix map_density

* even more fix

* remove need for vec in Aggregator::aggregate

* fix json weirdness - remove individual clients (is that all right? )

* Make pretty
2024-04-05 14:23:56 +02:00
Dongjia "toka" Zhang
98d3dfe821
Replace LLMP client timeout with client deregistration (#1982)
* wip

* done

* fix

* fix

* some fixes

* stuff

* fmt

* stuff

* use

* not 1337

* comment

* move functions around

* fix

* fix

* doc

* mistake

* aa

* fixer

* wipe out restarter id

* denig

* fix

* fix

* include

* fix

* fix

* fix

* clp

* fix

* fix

* error log
2024-04-04 21:01:11 +02:00
Dominik Maier
e64233e203
LLMP: Fix page-size where allocated message is larger than the current map (#1997) 2024-04-03 13:27:19 +02:00
Romain Malmain
50be2f4aaf
Fix of libafl qemu runtime files (#1996)
* Change naming and fix LibAFLQEMU header file. Fix and document LibAFL QEMU Windows ASM file.

* fmt
2024-04-03 11:57:48 +02:00
Dominik Maier
d90d232e7a
Frida: Move ASAN_ERRORS values into a Mutex for shared access (#1995)
* Move ASAN_ERRORS values into a Mutex for shared access

* Fix frida doc

* oops

* clippy
2024-04-03 11:47:09 +02:00
f26582ed75 un-hardcode rtos api functions 2024-04-03 10:19:37 +02:00
Dongjia "toka" Zhang
2137ad0f8f
Don't resume in std mutational stage (#1946)
* fix

* fix

* fix

* fix

* FMT

* don't resume in mutational stage
2024-04-02 13:26:47 +02:00
Dominik Maier
44dca17a6c
Tiny Frida doc fix (#1994) 2024-04-02 13:25:59 +02:00
Romain Malmain
cca4e3daa9
Make inputs in libafl_qemu generic (#1991)
* fix non-generic input in libafl_qemu

* Update setup_libxml2.sh of nyx_libxml2_standalone fuzzer (#1990)

On testing this on my machine not all neccessary files for fuzzing with nyx where provided by the setup. Compared to the nyx_libxml2_parallel fuzzer this packer generation line was missing.
After adding this the fuzzer was able to start.

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Tobias Mayer <arbeitskraftmayer@gmail.com>
2024-04-02 12:30:12 +02:00
Dominik Maier
aaafe1fc6c
Use new Rust CStr constant (#1993) 2024-04-02 10:28:20 +02:00
Tobias Mayer
63a6d1aac0
Update setup_libxml2.sh of nyx_libxml2_standalone fuzzer (#1990)
On testing this on my machine not all neccessary files for fuzzing with nyx where provided by the setup. Compared to the nyx_libxml2_parallel fuzzer this packer generation line was missing.
After adding this the fuzzer was able to start.
2024-04-02 10:19:22 +02:00
Dominik Maier
26122b20a0
Add unsafe to AsanErrorsObserver, fix UBs, fix Frida Version missmatch (#1987)
* Add unsafe to AsanErrorsObserver, fix UBs, fix Frida Version missmatch

* Clippy

* simpler API

* fix build

* fix
2024-04-02 10:17:59 +02:00
ToSeven
10f373d587
fix AFL-Style UI errors when allowing the introspection feature (#1986) 2024-04-01 14:09:15 +02:00
Andrea Fioraldi
45d47214c2
Fix OOM restarts with LlmpShouldSaveState (#1974)
* LlmpSaveState and OOM restarts

* clippy

* clippy

* rename
2024-03-30 17:05:03 +01:00
Romain Malmain
69d7d7b1e3
Add backdoors to portable header file of LibAFL QEMU. (#1978)
* Added backdoors to portable header file.

* fix arm macros.

* copy `libafl_qemu.h` in target directory.

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2024-03-30 17:04:52 +01:00
Romain Malmain
50e0f80d1e
Refactoring of qemu_systemmode fuzzers (#1980)
* Added backdoors to portable header file.

* fix arm macros.

* copy `libafl_qemu.h` in target directory.

* Merged all qemu_systemmode examples into one, settable with features.
Automatic building using `Makefile.toml`

* fix typo.

* added test of QEMU systemmode fuzzers.

* replace test by build for now.
2024-03-30 17:04:37 +01:00
Dongjia "toka" Zhang
0cafa5c72d
Don't use unwrap() in the crash handler (#1979)
* don't

* win

* fix

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2024-03-30 17:04:28 +01:00
Marco C
15aabfe65d
Clean up warnings in baby_fuzzers (#1981) 2024-03-29 15:14:17 +01:00
s1341
1fc5ba63fa
batch_timeout: fix overflowing subtraction (#1976) 2024-03-28 16:50:12 +01:00
c013628017 fix scheduler for storage changes 2024-03-28 14:14:34 +01:00
am009
c221108916
Add MutatedTransform to the input type in TMinMutationalStage (#1251) (#1971)
* Support `MutatedTransform` in `TMinMutationalStage`.

* Run `MutatedTransformPost` for the replaced testcase.

* Add clone trait bound for `MutatedTransformPost`.

* Return an error instead of using unwrap.
2024-03-27 18:59:45 +01:00
730fbcf6d4 fix capture in api calls 2024-03-27 15:24:44 +01:00
Dongjia "toka" Zhang
f0ee6e0587
Make fuzzer examples's argument parser tell that --input is mandatory (#1973)
* add

* not ture

* fmt
2024-03-26 20:02:42 +01:00
Dongjia "toka" Zhang
cd12546748
Fix llvm api so it works with older LLVM version (#1964)
* aa

* fix

* fix

* fmt

* fmt
2024-03-26 19:26:19 +01:00
Dongjia "toka" Zhang
91778961da
Inline cmplog internal functions code (#1972)
* fmt

* aa

* sattic

* win

* frida

* expose API

* fmt

* frida
2024-03-26 17:42:03 +01:00
Dongjia "toka" Zhang
53bfae0a08
Increase llmp timeout & Print PID in logger (#1970)
* increase timeout & print pid for logger

* log

* aa

* rename stuff
2024-03-25 19:15:46 +01:00
Dongjia "toka" Zhang
7170b5391b
Fix UpdateExecStats not sent to the main broker in centralized 2024-03-25 16:39:30 +01:00
Dongjia "toka" Zhang
3cc8ea0336
Fix EventManagerHook (#1968) 2024-03-25 13:04:41 +01:00
Romain Malmain
4d3c6a3b9a
Fix libafl_qemu fuzzers not building in Docker (#1966)
* fixed rustup component added before switching to nightly.
added missing libafl_qemu source files.

* removed touch.
2024-03-24 11:07:33 +01:00
Maurice
f448b6fb24
libafl_nyx: Add bounds check for Nyx input buffer (#1963) 2024-03-23 18:31:07 +01:00
Maurice
a0d4a5b240
libafl_nyx: Add documentation to NyxSettings fields 2024-03-23 15:20:35 +01:00
Romain Malmain
44c841ffb1
WIP: QEMU exit handler (#1745)
* Added paging filtering.
Reworked address range filtering to fit with new generic code.

* Fix: renamed remaining QemuInstrumentationFilter instances.

* Renamed sync breakpoint to sync exit.

* Split emu in systemmode.rs / usermode.rs for specific code.
EmuExitHandler implementation.

* sync_backdoor.rs removal.
Formatting.

* Updated `bindgen` and `which`.
Adapting code to work with update.

* fix: reconfigure cleanly if prior configure was interrupted abruptly.

* Enable sanitizers in QEMU during debug.

* Added target-usable files.

* Added breakpoint structure.

* Adapted other files to work with ExitHandler.

* Adapted existing fuzzer to work with new exit handler.

* fix: use get to avoid crashes.

* Updated README to indicate cargo-make should be installed.

* Added QEMU internal exit handler.

* Adapted qemu_systemmode example with new exit handler.

* Fixed fuzzers to work with new exit handler.

* Trying to fix CI (#1739)

* test

* dummy

* dummy

* Added new examples.

* Forgot to add build scripts.

* format

* format

* clang-format

* python emulator adaptation.

* fixed python bindings.

* clippy fixes.

* python bindings.

* fix qemu_sugar.

* fix fuzzbench.

* fixed import issues.

* misc fixes.

* renamed crate.

* Updated x86_64 stub bindings.

* Fixed static naming.

* binding fmt

* clippy

* clippy

* Removed useless return statement.

* removed advice to install cargo-make in individual repositories.

* symcc_update (#1749)

* Remove unused create_anymap_for_trait macro (fixes #1719) (#1752)

* Fix `as_object` UB discussed in #1748 (#1751)

* Fix as_object UB discussed in #1748

* More cleanup, more less UB

* Fix fixes

* Added uninit_on_shmem api

* clippy

* fmt

* trying to fix fuzzers, libfuzzer wrapper

* Add OwnedRefMit::owned constructor, libfuzzer fix

* Some more fixes

* Add BacktaceObserver::owned fn

* fmt

* more fmt

* Ignore SigPipe by default (#1741)

* Ignore SigPipe by default

* Fix no_std

* fmt

* Fix incorrect imports (#1758)

* Fix incorrect imports

https://doc.rust-lang.org/core/simd/trait.SimdOrd.html

* Fix

* Try fix ci

* Documentation fixes (#1761)

* Documentation fixes

* Fix InProcessExecutor url

* Update all urls to latest

* Miri ignores for M1 regex (#1762)

* Enabling DrCov on Windows (#1765)

* Enabling DrCov for Windows

* Dedup common code in scheduler (#1702)

* dedup common code in scheduler

* del eco

* fixing

* fix

* replace `Emulator::new_empty` by `Emulator::get` calls outside of `emu.rs` for safety. (#1763)

* Add mute_inprocess_target fn, SimpleFdLogger::set_logger, and more (#1754)

* Add mute_inprocess_target fn, SimpleFdLogger::set_logger, set_error_print_panic_hook

* Trying to fix #1753

* typo

* More fix

* Fix test?

* more testcase fixes

* Fix: renamed remaining QemuInstrumentationFilter instances.

* Split emu in systemmode.rs / usermode.rs for specific code.
EmuExitHandler implementation.

* format

* format

* format

* Replace sync_exit with sync_backdoor.

* Rework command system.

* fix bad import.

* format.

* cargo fmt

* disable af-xdp as well to avoid linking errors.

* End of merging.

* format.

* Adaptation for usermode.

* format.

* injection support.

* usermode fixes.
format.

* clippy

* clippy + format

* Do not unwrap emu + format.

* fix: entry_point breakpoint

* inital commit.

* clippy

* tests

* clippy

* adapt example

* systemmode.

* renaming

* fmt

* fix lints.

* more lint fix.

* even more lint fixes.

* always more lint fixes.

* lint fix.

* allow unused qualifications for crate when it could be confusing.

* Still lint fixes.

* Lint fixes on generated code.

* Some lint fixes.

* merge continue.

* renamed modules as well.

* fixing merge.

* systemmode compiling.

* fmt

* fix early emulator drop.

* fmt

* fix cast to c_void of the wrong object.

* Added global enum for snapshot managers.
Some renaming.

* move things around.

* WIP: generic inclusion of QEMU Executor in exit handler.

* * Moved extern calls to `libafl_qemu_sys`
* Replaced old `Emulator` by `Qemu` and only kept C functions wrappers
* Now `Emulator` is for higher-level interactions with QEMU. Kept old functions for compatibility calling to `Qemu` functions
* A direct side effect of this slit is the removal of the `IsEmuExitHandler` trait dependency added in many parts of the code.
* Removed old dirty casting for `QemuExecutor` helpers and used the brand-new access to `QemuExecutorState` instead.
* Minor changes to `Qemu` and `Emulator` `get` methods for cleaner getters.

* Add missing `Qemu` function.

* Updated `qemu_systemmode` example.

* Adapted QEMU fuzzers + renaming.

* Fixed python.

* fix libafl_sugar with new implementation.

* fix dangling RefCell.
adapt new examples.
TODO: merge `libafl_systemmode.*` examples.

* clippy.

* fix more fuzzers.

* clippy.

* Implement `HasInstrumentationFilter` generically.
Updated `StdInstrumentationFilter` accordingly.

* Renamed breakpoint functions for QEMU.
`qemu.run()` handling.

* Removed OnceCell / RefCell in signature.
more explicit `MmapPerms` method names.

* minor code refactoring

* Emulator::run_handle refactoring

* deprecated Emulator functions calling directly to QEMU functions.

* IsSnapshotManager -> SnapshotManager

* IsEmuExitHandler -> EmuExitHandler + fmt

* Generic register when it makes sense.

* reverted IsSnapshotManager -> SnapshotManager because of a collision.

* fix syntax + clippy

* fmt

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: lazymio <mio@lazym.io>
Co-authored-by: Bet4 <0xbet4@gmail.com>
Co-authored-by: mkravchik <mkravchik@hotmail.com>
2024-03-22 18:03:29 +01:00
Maurice
50843b19d1
libafl_nyx: Allow custom input buffer size to be passed to NyxHelper (#1960)
* add option to specify input buffer size

* fix typo

* use `libafl::Error` as default error type

* derive `TypedBuilder` for `NyxSettings`

* update nyx_libxml2_standalone

* update nyx_libxml2_parallel

* update nyx_libxml2_standalone

* update nyx_libxml2_standalone

* update nyx_libxml2_parallel
2024-03-21 22:53:01 +01:00
Dongjia "toka" Zhang
6b94db2260
Use OwnedPtr in ListObserver (#1961)
* aaa

* clp
2024-03-21 19:46:42 +01:00
Dongjia "toka" Zhang
15f4613894
More usable ListFeedback (#1959)
* real list feedback

* add

* fox

* obs

* fix

* FMT

* more

* fmt

* rev
2024-03-21 16:21:15 +01:00
Dominik Maier
7abc26ebc9
Change AnyMap API, add unsafe_ assert (#1958)
* Change AnyMap API, add unsafe_ assert

* clippy

* Add anymap serialize test

* Add test

* fmt
2024-03-20 14:45:23 +01:00
Dominik Maier
14fd3040bd
Remove hash for AnyMap (since it's a hashmap already) (#1951) 2024-03-19 20:41:15 +01:00
Dominik Maier
2efa747292
SerdeAnyMap: add unsafe_stable_anymap feature that uses type_name instead of TypeId::of (#1952)
* Test: Use type_name instead of type_id in AnyMap

* Hide behind 'unsafe_stable_anymap' feature

* nostd?

* rename fn

* cleanup a bit
2024-03-19 20:15:31 +01:00
am009
5eab4fb78b
Update tinyinst_simple to support Linux (#1316) (#1955)
* Make fuzzers/tinyinst_simple support Linux (#1316)

Fix a documentation error for `MmapShMemProvider`.

* Support shmem for `fuzzers/tinyinst_simple` on Linux.

Format code.

* Fix CI to install cxxbridge-cmd.

* Add `CARGO_TARGET_DIR` in makefile to fix CI.
2024-03-19 20:15:07 +01:00
Michael Chen
fde9cda5ee
Gramatron: Upgrade automaton files (#1956)
`auto.postcard` file is following `postcard@0.7` wire format, which is
not compatible with the `postcard@1.0` dependency. `auto.json` is out of
date with the latest `Trigger` struct definition. Regenerated both using
the data from `auto.postcard`
2024-03-19 20:09:47 +01:00
Romain Malmain
928cf80782
fix unwrap. (#1954) 2024-03-18 18:51:19 +01:00
Dongjia "toka" Zhang
0f26f6ea32
Remove useless feedback (#1953)
* stuff

* FMT

* remove stuff
2024-03-18 16:41:43 +01:00
Dominik Maier
a0143d02a6
Rename OSError -> OsError and merge with redundant Error::File (#1944)
* OSError -> OsError

* Move File errors to io Errors

* Removing File errors

* fixes :)

* More format

* fix libfuzzer runtime
2024-03-18 08:46:48 +01:00
Stefan Zabka
fbd0d497d4
Refactor(build.rs): extract common code between branches (#1950) 2024-03-17 21:31:30 +01:00
Dongjia "toka" Zhang
44a37da680
Use const_assert not assert (#1949)
* stuff

* FMT
2024-03-16 03:33:20 +01:00
Dongjia "toka" Zhang
c6420c0987
Separate fuzzbench fuzzers's test (#1947)
* separate fuzzbench test

* upd
2024-03-15 19:44:22 +01:00
Dongjia "toka" Zhang
34b4a6ac1d
Better error message instead of "No entries in corpus" 2024-03-15 19:19:55 +01:00
Dongjia "toka" Zhang
c6875b8cf6
Fix self.iterations underflow (#1942)
* fix

* fix

* FMT
2024-03-15 19:13:58 +01:00
Dongjia "toka" Zhang
e30ff57456
Update exec counts in objective (#1945)
* fix

* fix

* update exec count
2024-03-15 18:52:53 +01:00
Dongjia "toka" Zhang
5cc0180835
Fix self.restart_helper.execs_since_progress_start in calibration stage (#1943)
* fix

* fix
2024-03-15 18:31:44 +01:00
Dongjia "toka" Zhang
ee6385c25b
Fire events in append_metadata not in is_interesting (#1936)
* stuff

* ok

* Recalc filled slightly differently... (#1939)

* Recalc filled slightly differently...

* Make requested changes as per PR review

* unused

* fix

---------

Co-authored-by: Dan Blackwell <danblackwell95@yahoo.co.uk>
2024-03-15 13:24:26 +01:00
Romain Malmain
b3ddab3bce
fix libafl_qemu_sys unnecessarily rebuilding. (#1938) 2024-03-14 18:25:19 +01:00
Dominik Maier
04d87ccc89
Remove (almost) unused stage_idx (#1929)
* Remove (almost) unused stage_idx

* Fix text-based test

* fixed critical whitespace

* clippy

* more fmt

* fix push stage
2024-03-14 13:14:57 +01:00
am009
93f67aa405
Fix os error printing in unix_shmem (#1406) (#1935)
Use `std::io::Error::last_os_error` instead of `libc::perror` for error printing in unix_shmem.
Add a new enum item `OSError` to enum Error.
2024-03-14 13:07:04 +01:00
Dongjia "toka" Zhang
afa2965f3c
Remove some arguments from pre_exec/post_exec in ExecutorHook (#1933)
* refactor

* no std, fmt

* win mac

* state

* frida

* ctx

* trait bound

* clip
2024-03-13 18:49:09 +01:00
Dominik Maier
4f3d9d2e50
Tiny optimization for into_vec (#1931)
* Tiny optimization for into_vec

* fix bug
2024-03-13 16:52:15 +01:00
Dongjia "toka" Zhang
44aec56f7e
remove more args (#1934) 2024-03-13 16:17:46 +01:00
Dominik Maier
2763d945a3
Cleanup last redundant corpus_idx usages (#1930)
* Cleanup last redundant corpus_idx usages

* More cleanup
2024-03-13 01:24:11 +01:00
Romain Malmain
9b96149f6c
Do not build doc with all features. (#1928)
Add documentation about default features for documentation.
2024-03-12 23:08:37 +01:00
Dongjia "toka" Zhang
5f67b9fbc4
Event Manager handle_in_client hooks (#1916)
* event manager hooks

* tcp

* fix

* FMT

* fix

* fix
2024-03-12 14:39:16 +01:00
Stefan Zabka
fe1c7a34b7
Dockerfile: setup for building libafl_qemu in Docker (#1899)
* fix(Dockerfile): add build_linux.rs to libafl_qemu and libafl_qemu_sys

* fix(Dockerfile): workaround for llvm.sh failing on bookworm

Revert this once https://github.com/llvm/llvm-project/issues/62475 has been resolved

* fix(libafl_qemu): add unsafe to callbacks

* chore(devcontainer): update devcontainer to work with newer VSCode versions

* revert(libafl_qemu): revert unsafe keyword

* fix(devcontainer): move settings and extension under customizations.vscode

* fix(devcontainer): use postCreateCommand instead of initializeCommand
2024-03-12 01:00:35 +01:00
Dominik Maier
dd410c590a
Allow dyn in StagesTuple, add Current Testcase API, Untraitify Progress (#1915)
* Move into_vec to extra trait

* fix no_std

* First step towards stages tuples as vecs

* Allow dyn in StagesTuple, add Current Testcase API, un-traitify Progress, cleanups

* Move from generics to impl keyword, more replacements with better API

* rename fn

* Fix additional stages, more cleanup, rename progress to retries

* Fix more fixes

* Fixes

* Rename ProgressHelper -> RestartHelper

* Fix sugar, python, add perform_restartable

* fixes

* remove prelude bs

* rename to restart_progress_should_run

* more cleanup, remove tests I don't understand (sorry)

* fix docs

* more fix

* fix miri

* unsafe safety annotations

* more comments

* last docs

* Mixed_attributes only allowed for bindgen
2024-03-12 00:58:07 +01:00
Mohammad Omidvar
61046c4157
Fix reproducibility of the docker image (#1924)
Add `--locked` flag when installing `sccache` in the first stages to ensure the image gets built when the base image's Rust version satisfies `sccache`'s MSRV.

Fixes #1923 🐛

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-03-11 19:15:54 +01:00
Dongjia "toka" Zhang
9b780cc0a7
Fix UB in anymap.rs and other minor warnings. (#1926)
* fix

* clippy

* fix
2024-03-11 18:15:56 +01:00
7e79f4051d clean trace from ISRs without effect, prevent race-conditions 2024-03-09 13:41:26 +01:00
6793d48dbd extract ABBs 2024-03-08 14:04:23 +01:00
Romain Malmain
e745401a39
Update QEMU version. (#1922)
* update QEMU version.

* clippy
2024-03-08 13:15:00 +01:00
Aarnav
d6fe67c3c8
Introduce multicore loading for the initial seed corpus (#1905)
* introduce multicore load initial corpus

* update fuzzers/libfuzzer_libpng_norestart to use multicore corpus loading

* run clippy

* use CoreId and Cores in state if std

* misc. typos

* adapt multicore load initial inputs to allow resumable corpus loading
in case of crashes or timeouts during corpus loading.

* add std feature flag to multicore_inputs_processed

* fix doc comment

* run fmt for example fuzzer

---------

Co-authored-by: aarnav <aarnav@srlabs.de>
Co-authored-by: Romain Malmain <romain.malmain@pm.me>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-03-08 02:56:08 +01:00
Dongjia "toka" Zhang
1b9f4ea29c
Fix batched timeout (#1920)
* fix ptr

* fix ptr

* fix

* One less windows warning

* One less windows warning
2024-03-07 23:52:56 +01:00
Romain Malmain
781e830923
fix cast to c_void of the wrong object. (#1921) 2024-03-07 21:28:28 +01:00
Mrmaxmeier
6747a7dc2f
token mutations: avoid a few infallible unwraps (#1919) 2024-03-07 18:26:59 +01:00
Mrmaxmeier
e48c8c0e23
fuzzbench_ctx: fix duplicate package warning (#1918)
Cargo previously complained when loading libafl as a git dependency:

warning: skipping duplicate package `fuzzbench` found at
`~/.cargo/git/checkouts/libafl-c33dc6f5ec2f7a70/55a300d/fuzzers/fuzzbench`
2024-03-07 17:56:40 +01:00
Dongjia "toka" Zhang
9a2e7b0e64
Fix redundant xor in Ngram calculation (#1901)
* fix double xor

* tmp

* clp

* no notnightly

* fix

* plural
2024-03-07 14:49:01 +01:00
Stefan Zabka
2ac075024b
fix(Dockerfile): allow running commands with docker run (#1894)
* fix(Dockerfile): allow running commands with docker run

According to
<https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2109#note_47480476>
adding the "-c" to the ENTRYPOINT is necessary to be able to run
commands like `docker run libafl "cargo build"`

* fix(Dockerfile): restore ability to docker run without command

As `bash -c` always requires a string, the previous commit
removed the ability to just `docker run -it libafl` and
get a shell.
This commit restores that ability
2024-03-06 19:14:18 +01:00
Dongjia "toka" Zhang
969aa12c7e
aa (#1913) 2024-03-06 19:05:32 +01:00
Romain Malmain
3b3e2f6efa
Improve readability of InProcessExecutor-related code (#1912)
* inital commit.

* clippy

* tests

* clippy

* adapt example

* systemmode.

* renaming

* fmt

* fix lints.

* more lint fix.

* even more lint fixes.

* always more lint fixes.

* lint fix.

* allow unused qualifications for crate when it could be confusing.

* Still lint fixes.

* Lint fixes on generated code.

* Some lint fixes.

* renamed modules as well.

* Separated inner from InProcessExecutor.

* fix

* unused import

* unused import

* fix import

* fix import
2024-03-06 00:30:35 +01:00
Romain Malmain
55a300d508
Make executor state available to the harness V2 (#1900)
* inital commit.

* clippy

* tests

* clippy

* adapt example

* systemmode.

* renaming

* fmt

* fix lints.

* more lint fix.

* even more lint fixes.

* always more lint fixes.

* lint fix.

* allow unused qualifications for crate when it could be confusing.

* Still lint fixes.

* Lint fixes on generated code.

* Some lint fixes.

* renamed modules as well.
2024-03-05 19:28:46 +01:00
Rayhan Faizel
44b0b0ad82
libafl_targets/src/cmplog.c: Fix warning for deprecated syscall() in macOS (#1911) 2024-03-05 19:04:20 +01:00
Dan Blackwell
cd8003ee69
Fix for #1881, ProbabilitySamplingScheduler seems to be inverted (#1884)
* Fix for #1881, ProbabilitySamplingScheduler seems to be inverted

* Run 'cargo +nightly fmt'

* Added debug_assert as negative and infinite probability values would break the current implementation of next()

---------

Co-authored-by: Dan Blackwell <danblackwell@eduroam-int-dhcp-97-192-218.ucl.ac.uk>
Co-authored-by: Dan Blackwell <danblackwell@ML-W0NYVW4XCK.local>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-03-05 19:04:13 +01:00
Dongjia "toka" Zhang
e3f837d712
Fix inconsistent settings of client_timeout (#1897)
* a

* fix client timeout

* revert

* more

* std

* import

* import

* sdt

* FMT

* backtick again
2024-03-05 17:58:44 +01:00
Dongjia "toka" Zhang
1a0e692f33
Print PID when you create a new Llmp Sender. (#1898)
* aaaa

* FMT

* adding std
2024-03-05 16:02:47 +01:00
Dongjia "toka" Zhang
95bed5b016
Fix the centralize disconnection bug. (#1896)
* fixing the first bug

* backtick
2024-03-05 15:49:35 +01:00
Romain Malmain
d96a1426d5
Fix lint errors (#1909)
* fix lints.

* more lint fix.

* even more lint fixes.

* always more lint fixes.

* lint fix.

* allow unused qualifications for crate when it could be confusing.

* Still lint fixes.

* Lint fixes on generated code.

* Some lint fixes.
2024-03-05 14:16:26 +01:00
a045b7bcd6 track api calls and isrs 2024-03-05 09:56:13 +01:00
Dominik Maier
b7efe8eb7d
Implement MutatorTuple for Vecs to allow Dynamic Mutator Choices (#1893)
* Implement MutatorTuple for Vecs to allow Dynamic Mutator Choices

* fix test

* clippy

* Move into_vec to extra trait

* fix no_std

* more nostd

* no_std
2024-03-04 22:48:38 +01:00
Addison Crump
f3c37db2b7
TransferFeedback for determining if a testcase was from another node (#1906)
* impl TransferFeedback

* whoops, fix build

* fix doc

* fix build for tcp manager

* fix fr
2024-03-04 15:33:46 +01:00
Addison Crump
035c01b4a1
update libfuzzer docs about macos (#1903) 2024-03-01 18:26:22 +01:00
Dongjia "toka" Zhang
1a41e65a5b
Sancov based ngram & ctx implementation (#1864)
* ngram

* ctx

* push stuff

* passing cargo check

* save stuf

* add

* no default

* fuzzbench ready

* formatt

* aaaaaaaa

* adaptive map

* add all

* chg

* fix

* deleting stuff

* fmt

* clang18

* fuck

* save space

* fix?

* feature name

* fucking nightly only

* harness

* fix libafl_cc

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-03-01 13:59:13 +01:00
Addison Crump
8c773a6b85
Implement RetryProgress for limiting retry attempts in stages (#1890)
* do that again but smarter

* remember to register

* appease the clippy

* cleanup

* autofix clippy

* more clippy fixes

* more clippy...

* small clippy fix

* with_tries => with_retries

* most recent suggestions

* final clippy... hopefully
2024-02-28 14:12:28 +01:00
Addison Crump
7a4fb06d02
make nopstate public so that it can be used as reproducer (#1888) 2024-02-27 16:48:08 +01:00
5d9bcba0e6 break on all api functions 2024-02-26 08:40:07 +01:00
Dongjia "toka" Zhang
1dcfe8ef56
Make the map size larger for some of the example fuzzers (#1879) 2024-02-23 17:19:00 +01:00
Dongjia "toka" Zhang
19f5081bd8
Add several warnings when starting forkserver (#1877) 2024-02-22 14:58:51 +01:00
Dongjia "toka" Zhang
b97598d239
Windows fix (#1876)
* win fix

* just some ci

* test

* revert

* aaaaa

* bbbbbb
2024-02-22 14:56:30 +01:00
Dongjia "toka" Zhang
2bfe91e4bd
Fix a corner case where bitmap_size = 0 leads to panic (#1875) 2024-02-19 22:42:44 +01:00
Dominik Maier
263af87652
Less useless allocs for monitor display (#1874)
* Less useless allocs for monitor display

* More less String

* Lol who needs generics

* clippy

* remove &String
2024-02-19 21:15:11 +01:00
w1tcher
f48e281be8
Fix TuiUI deadlock under multi-threading (#1871)
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-02-19 17:20:08 +01:00
sadeli413
ef16e645b7
Support raw byte grammar in NautilusContext (#1868)
* Support raw byte grammar in NautilusContext

* Add `use` statement in doc comment
2024-02-19 16:46:28 +01:00
Dominik Maier
fafe8f5ce8
Fixing clippy some more (#1872)
* Fixing clippy some more

* more commit

* Git gud

* remove more useless imports
2024-02-19 16:46:06 +01:00
Dominik Maier
578a22a3d9
Revert "Companion patch to qemu-libafl-bridge #46 (#1830)" (#1865)
This reverts commit b999b4aac591818d4342773ff48e98f2896f141e.
2024-02-16 20:50:18 +01:00
Sameer Puri
50892ddc75
Finalize macOS support for libafl_libfuzzer (#1843)
* libafl_targets: on macOS, do not provide a default implementation for weak functions

* libafl_libfuzzer: update README to talk about macOS specifics

* libafl_targets: allow __sanitizer_cov_pcs_init to be called more than once

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-02-15 22:45:15 +01:00
Dominik Maier
0a995f241c
Cleanup Pointer Clippy Lints (#1861)
* Fix pointer clippy lints

* More clippy

* fix build

* fix
2024-02-15 16:31:18 +01:00
cube0x8
b999b4aac5
Companion patch to qemu-libafl-bridge #46 (#1830)
* fixing qemu-libafl-bridge #46

* cargo fmt

* updated QEMU revision

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2024-02-15 16:30:05 +01:00
Rubens Brandão
97a83aba3b
feature(libqasan): add strndup (#1860)
* feature(libqasan): add asprintf and vasprintf

* feature(libqasan): add asprintf and vasprintf to hotpatch

* feature(libqasan): add strndup
2024-02-15 16:13:46 +01:00
Rubens Brandão
d6d6a23f69
feature(libqasan): add asprintf and vasprintf (#1844)
* feature(libqasan): add asprintf and vasprintf

* feature(libqasan): add asprintf and vasprintf to hotpatch

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-02-15 13:56:35 +01:00
Romain Malmain
5151f1e35c
fix qemu linking error. (#1846)
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-02-15 00:29:33 +01:00
Dongjia "toka" Zhang
49ad380068
fix (#1859) 2024-02-14 23:28:20 +01:00
Dongjia "toka" Zhang
db88412738
Make cmp_extend_encoding panic-less (#1857)
* Add a panic check for aflpp

* aa

---------

Co-authored-by: novafacing <rowanbhart@gmail.com>
2024-02-14 11:46:09 +01:00
mkravchik
c837d0df7a
Pr/xxh3 rrmxmx mixer fix (#1828)
* Fixing the mixer according to the xxHash implementation

* Using Rust xxhash-rust instead of handwritten implementation

* Fixing the mixer according to the xxHash implementation - linking directly, not relying on bolts option

* clippy+fmt

* Removing rotation, as it causes issues

* Not using xxhash directly, relying on bolts

* Fmt
2024-02-14 11:45:47 +01:00
tbethe
b9650045f6
Getter for mutable reference to forkserver (#1849)
* Getter for mutable reference to forkserver

* Whoops

---------

Co-authored-by: Timme Bethe <git@timmebethe.nl>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-02-13 16:10:26 +01:00
Dongjia "toka" Zhang
cefb73861f
Fix token mutation crash (#1855)
* clippy

* token mutation fix
2024-02-13 16:10:02 +01:00
Dongjia "toka" Zhang
973c4358e6
clippy (#1851) 2024-02-13 13:19:00 +01:00
RobertBuhren
af97033d85
Fix x86_32 build: Don't build functions using uint128_t data type on x86_32 (#1854) 2024-02-13 12:49:52 +01:00
3817892ff1 Fix graph output formatting 2024-02-13 08:28:53 +01:00
Dominik Maier
dede78159c
Remove unused shmem structs, update Nix (#1845)
* Remove unused shmem structs

* More unused stuff

* Unified crate versions, updated docker rust version

* clean up nix 27 mess?

* Windows?

* Fix frida

* Fix frida

* fix fuzzers with nix
2024-02-11 17:45:09 +01:00
Niklas Gögge
15c98de52f
fuzzers: Fix qemu_launcher zlib include path (#1841) 2024-02-08 13:08:36 +01:00
beee8d8cb7 rewrite info dumps as macros 2024-02-08 10:08:25 +01:00
Rubens Brandão
40c8645ed3
Fix libafl_qemu libqasan Makefile (#1835)
* fix libafl_qemu libqasan Makefile

* remove make clean from libafl_qemu libqasan build

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2024-02-07 15:36:36 +01:00
Andrea Fioraldi
41d24ca375
Fix broken closure hooks in libafl_qemu (#1839)
* Fix broken crash hook

* fix hooks

* clippy

* pin
2024-02-07 15:03:27 +01:00
Romain Malmain
9b82af4539
Configurable LLMP client timeout (#1838)
* LLMP client timeout is now configurable.

* fix example.

* Fix for no-std case.
Make default timeout private.

* Fix import.
2024-02-06 18:35:27 +01:00
Addison Crump
c3473e5631
use truncate, not pop (#1837) 2024-02-05 20:48:17 +01:00
Addison Crump
054d0a6b19
OptionalStage is a nested stage, fix stage ID handling (#1836) 2024-02-05 17:51:01 +01:00
Dominik Maier
7d9559b570
Fix Benches (#1833) 2024-02-05 17:19:23 +01:00
Romain Malmain
99a70e5771
Update qemu-libafl-bridge with upstream. (#1829)
QEMU update to v8.2.1
2024-02-05 14:24:02 +01:00
Rubens Brandão
241b93036e
Fix libafl_qemu hooks references (#1825)
* fix libafl_qemu hooks references

* restrict the fatptr transmutation
2024-02-02 21:52:58 +01:00
Nereuxofficial
5c18dca792
Fixed Link in baby_fuzzer_nautilus (#1824) 2024-02-01 12:07:13 +01:00
Rubens Brandão
c96d103b37
HookId trait and types in libafl_qemu (#1796)
* libafl_qemu fix remove_hook

* libafl_qemu specialize hooks into separated types

* libafl_qemu generalize HookState to allow any HookId implementation

* fmt: external C qemu hook functions

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2024-02-01 10:55:55 +01:00
Sameer Puri
13dd1cc4ec
libafl_libfuzzer: macOS build support (#1711)
* libafl_libfuzzer: macOS support

* make clippy happy

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-01-31 02:41:08 +01:00
Dongjia "toka" Zhang
a4f753b0f0
Merge TimeoutForkserverExecutor into ForkserverExecutor (#1819)
* delete timeout forkserver

* clippies

* name

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-01-30 17:34:39 +01:00
Karthik Prakash
519ea435ed
LibAFL_libFuzzer: Default ignore_* flags to true when tui=1 (#1820)
* default `ignore_*` flags to true if `tui=1`

* update docs

* refactor code to use `Option<bool>` instead of extra struct members
2024-01-30 16:25:59 +01:00
Dominik Maier
8b0068e39d
Fix Clippy (#1822) 2024-01-30 16:25:10 +01:00
Dominik Maier
244c6b0da5
QEMU: Fix injections build for hexagon, disable on system mode (#1821)
* Fix CI for Clippy, QEMU

* Clippy, fixes for system mode

* clippy

* clippy

* fixing new clippy
2024-01-30 04:25:14 +01:00
Karthik Prakash
07f9a9d06a
Remove create_serde_registry_for_trait macro (#1815)
* remove `create_serde_registry_for_trait` macro

* fix `clippy` errors

* fix formatting
2024-01-28 17:51:50 +01:00
Dominik Maier
e7df233dc1
QEMU: add injections mode default (#1818) 2024-01-28 17:12:20 +01:00
Marco Vanotti
e6184936ce
Expose PCs table to map coverage bitmap entries to the corresponding code (#1812)
This table allows users to map between coverage bitmap entries and the
corresponding code in memory.
2024-01-25 16:51:13 +01:00
Rubens Brandão
59945fbcc9
Fix typo on qemu_launcher options help message (#1816) 2024-01-25 13:50:20 +01:00
Harrison Green
e117b7199c
Allow testcase removal during fuzz loop (#1717) 2024-01-24 17:56:24 +01:00
Dominik Maier
6a0ba7b647
Add SimpleMgr feature to qemu_launcher (#1790) 2024-01-24 17:54:52 +01:00
Dominik Maier
0cb7b25f39
Replace static borrows with addr_of!, rust 2024 compatibility (#1800)
* Less UB

* fmt

* fix warning

* clippy fixes

* addr_of_mut allthethings

* removed duplicate import

* fix imports

* remove comment

* more windows

* fmt

* fix tests

* fixes

* qemu

* fix more cases, qemu

* fix

* fmt
2024-01-24 17:47:55 +01:00
Dongjia "toka" Zhang
bb443027f7
Observer fix (#1807)
* fix

* Increase default edgemap size for libafl_cc and libafl_targets (#1798)

* fmt

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
2024-01-24 03:30:22 +01:00
Sharad Khanna
1458c3efff
Fix build issues in frida cmplog for aarch64 (#1813)
* Fix build issues for aarch64

* cargo fmt
2024-01-24 01:18:31 +01:00
Romain Malmain
a0e30d01d3
QEMU: safe linking of extern "C" declarations (#1810)
* safe linking initial commit

* Fix static declaration.

* Works also for static variables, even for thread-unsafe types.

* Remove warnings.

* fixed visibility for function.

* remove `rustversion` from dependencies.
2024-01-23 22:38:06 +01:00
Dongjia "toka" Zhang
2ac154d473
Refactor InProcessExecutor, merge timeout executors (#1789)
* move windows, inprocess fork to a different file, try new hook mechanism for the executor

* fix

* even more

* more

* more

* fix

* fix

* macosgit add -ugit add -u

* windows!

* windows!

* aa

* aa

* macos

* std

* wtf unresolved?

* Copy, Clone

* why you just don't have the same API!

* inproc

* next; inprocess

* windows?

* ci

* ci

* ci

* unused

* ci

* unused

* no_std

* windows no std

* fix

* inprocess

* fix

* windows

* fuzzers

* macos , book

* fix

* aa

* allow

* fix

* stop suggesting wrong lint AAAAAAAAAAAAAAAAA!!!

* stop suggesting wrong lint AAAAAAAAAAAAAAAAA!!!

* win

* fix

* wip

* wip2

* windows done?

* remove TimeoutExecutor

* ci

* ci

* miri

* fixfi

* compile on windows

* a

* clp

* no_std stuff

* windows no_std

* mac stuff

* m

* a

* ci

* ci

* deleting timeoutexecutor, gradually

* fucking macos

* ci

* test

* ci

* ci

* batch mode constructor

* fix

* ci

* aa

* miri

* aaa

* tmate again

* fix windows stuff

* final fix

* another win fix

* add

* let's add the new fix later

* more

* fi

* parse

* win clippy

* win no std

* safety

* fix

* DEFAULT

* final fix

* libafl_libfuzzer

* comments

* fix

* fix fuzzres

* fixxxxx

* fixxxxx

* last fix

* change name
2024-01-23 22:35:14 +01:00
Josef Haider
058d2c0825
Remove unnecessary PartialEq trait constraint on DiffFeedback observers (#1811) 2024-01-22 20:23:32 +01:00
expend20
72c862171e
POC attempt to make cmplog work on x64 (#1713)
* POC attempt to make cmplog work on x64

windows POC seems working

unix POC seems working :)

* no register collisions
* rsp-related ref support

iced optional dep

iced depends on cmplog

warnings

one more warning

comments cleanup

ci unbreak

rebase windows unbreak

rebase unix unbreak

unix only

fmt check

clang formatting

clang formatting again

make clippy happy

formatting

double import

windows unbreak

hashmap is conditional

leftover definition

tutorial related formatter

review fixes

comments

.asm fuzz targets for cmplog on Windows

more tests

rip-relative reference support without index register form

proper ignore rip-related references and ignore 8 bit comparisons

another try_into packing

* harness modification reverted

* dummy commit to restart CI

* review comments

---------

Co-authored-by: sbarsky <sbarsky@denuvo.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-01-19 11:52:15 +01:00
WorksButNotTested
e615cb4aed
Disable QemuInjectionHelper if not configured (#1804)
Co-authored-by: Your Name <you@example.com>
2024-01-18 18:53:42 +01:00
Dongjia "toka" Zhang
df8fa71aa7
Revert "Increase default edgemap size" (#1803) 2024-01-18 14:58:29 +01:00
Dongjia "toka" Zhang
001e132186
Fix windows after #1350 (#1801)
* fix

* apt update

* apt update

* a

* split even more

* tmate

* ci

* can't fix this shit

* s
2024-01-17 18:51:56 +01:00
2ac7874895 fix build 2024-01-16 15:53:57 +01:00
David CARLIER
61718c4e88
bolts: fix static mutable use (#1793) 2024-01-16 14:32:42 +01:00
Dongjia "toka" Zhang
c240cdec38
Increase default edgemap size for libafl_cc and libafl_targets (#1798) 2024-01-14 01:25:22 +01:00
Dongjia "toka" Zhang
e72ad4ba2d
remvoe it (#1797) 2024-01-14 01:23:53 +01:00
Dongjia "toka" Zhang
3ed231db69
Don't use assert fail when building on libafl_libfuzzer on windows (#1792)
* fix

* fix

* clippy

* clippy
2024-01-13 16:02:10 +01:00
mkravchik
6a72f8a1ad
libafl_frida: Add tests for ASan for Unix platforms (#1781)
* First draft of a Asan tests. As of now, unix-only. This is a WIP, as 1) destroying Gum causes segmentation fault and thus a single test is supported by using a static Gum object. Ideally, this should be fixed and a new Gum instance would be created for each test. 2) 70 identical errors are reported by Asan instead of a a single one. Apart from that, the draft fixes a number of errors found in Asan

* Fmt fixes

* PR comments addressed

* Not crashing upon Asan errors while testing

* More PR comments: removing env_logger, renaming harness to test_harness

* Revert "More PR comments: removing env_logger, renaming harness to test_harness"

This reverts commit 2d3494b3f56e0a5ef23566cb9a884e8c57867b57.

* More PR comments: removing env_logger, renaming harness to test_harness

* Checking for clang presence and failing the test if harness not found

* Fmt

* Running multiple Asan tests

* Cpp Fmt

* clang-format

* More clippy complaints and Apple compilation

* Last clippy complaints (ran scripts/clippy.sh)

* Fixing unused MacOS function

* Fixing unused MacOS imports
2024-01-11 13:26:00 +01:00
Andrea Fioraldi
aaeeead574
Remove Aggregated label in stats (#1788)
* Remove Aggregated label in stats

* introspection

* fix monitor aggregate propagation
2024-01-10 21:05:19 +01:00
mkravchik
b93a5bb414
Pr/fix qemu launcher build - fixes 1785 (#1786)
* Fixing qemu_launcher build (#1785)

* Fixed the instructions for using the injection feature
2024-01-10 13:17:53 +01:00
van Hauser
0f2cf80085
libafl_qemu injections (#1743)
* nits

* first steps

* different approach

* fixes

* remove temps

* remove temp

* initial import

* more tests

* bug hunt

* cleanup

* yaml function target 0x.... support

* final

* update doc

* other work

* Clippy, fmt

* Removed lazystatic dependency

* More small cleanups

* optimize to_lowercase

* move funtionality to libafl_qemu

* add missing file

* ready

* remove qemu_injections

* move test files to test directory

* doc update

* add todos

* fixes

* add file comment

* add test and other platform support

* fix clippy

* Replace Emulator::new_empty by Emulator::get.
Fix visibility identifier.

* clippy

* let's try this

* cpu_target?

* fmt

* cleanup build system, enable missing fuzzers

* fix qemu_launcher

* enable hexagon in qemu_launcher

* Removed useless `any` predicate in cfg attribute.
Replaced wrong types in `syscall_hook` signature.

* format

* move to read_function_argument

* add hexagon injections support

* enable injections fuzzing everywhere

* unify error msg

* Fix build, add initial toml support

* intermediate push, wip

* fix build

* More WIP

* Fix build

* Clippy

* fix qemu

* Fix arm

* fix more wrong things

* fix testcase

* try to fix it again?

* more release?

* make makefile independent of dev/release

* trying more fix?

* More ugly more works

* more trying to fix the testcase

* allow yml as filename too

* more docs

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: Romain Malmain <romain.malmain@pm.me>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2024-01-09 19:56:19 +01:00
Addison Crump
ba8ca6723b
Resumable stages redux (#1780)
* initial stage refactor

* repair test

* redqueen

* fixup python bindings

* docs and clippy fixes

* misc hidden changes

* Status => Progress

* fix remaining fuzzers

* fix libafl_libfuzzer

* implement resume for nested stages

* deep testing for stage resumeability

* refactor: use let-else, docfix

* refactor in fuzzbench_forkserver_cmplog

* fmt

* actually use progress

* HasStageStatus => HasCurrentStage
2024-01-09 15:18:14 +01:00
Dongjia "toka" Zhang
3d126f21cc
aggregator fixer (#1783) 2024-01-08 19:36:41 +01:00
Dominik Maier
88f3ff4a28
Clang-format latest (#1651)
* Clang-format latest

* add

* rdm

* CHATGPT

* CHATDUMB

* different action

* no

* fix

* ci

* ci

* ci

* fuck

* dir

* checkout?

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* don't use shit

* ci

* ci

* ci

* FMT

---------

Co-authored-by: toka <tokazerkje@outlook.com>
2024-01-05 23:32:06 +01:00
Gheorghiță Mutu
48c9fed2da
[libafl_targets] # fix typo in windows_asan feature (#1779) 2024-01-05 23:31:57 +01:00
Dongjia "toka" Zhang
0a72d8abbc
Add header (#1777)
* add

* rdm

* CHATGPT

* CHATDUMB

* different action

* no

* fix

* ci

* ci

* ci

* fuck

* dir

* checkout?

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* ci

* don't use shit

* ci

* ci

* ci
2024-01-05 19:35:36 +01:00
Dominik Maier
207e7dbdff
Move Clippy to extra CI steps (#1370)
* Move Clippy to extra CI steps

* clippy?

* Last try with nightly

* no clue why but hey

* cleanup

* more

* revert

* check ubuntu works

* f

* debug

* clippy_ci

* remove tmate

* regex

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2024-01-04 21:50:14 +01:00
Dongjia "toka" Zhang
989dd4d89a
More concolic fix (#1776)
* more

* revert
2024-01-04 21:28:11 +01:00
Dongjia "toka" Zhang
616e507593
Update symcc for #1768 (#1775) 2024-01-04 14:25:47 +01:00
Addison Crump
99fd69acdc
Multipart Input support (#1617)
* initial commit: multipart

* document + wrap up baby fuzzer

* oops

* core

* add from method, option to iter

* improve example; use minmap; fix initial_mut

* bindings

* clippy, again

* moar clippy

* fmt

* drop rand dep because we don't need it, actually

* docfix

* ok actually fix docs pls
2024-01-04 01:51:29 +01:00
Dongjia "toka" Zhang
75fcd47044
Recover useful CmpLog updates from #1630 (#1684)
* add

* ci

* wip

* make type name more clear

* last

* add

* more fix

* chg

* fmt

* save changes

* fix_handler

* cfg

* win

* fix

* toml

* f

* more

* fix all the stuff

* fix

* revert fuzzers/fuzzbench to origin/main
2024-01-03 23:44:32 +01:00
Konstantin Bücheler
9b2a17896f
Fix export of afl-clang-fast if already in PATH (#1773) 2024-01-03 23:22:42 +01:00
Dongjia "toka" Zhang
8164bfca96
Fix sigint handlers (#1772)
* fix_handler

* cfg

* win

* fix

* toml

* f

* more

* rename and write_volatile
2024-01-04 04:57:41 +09:00
Romain Malmain
b8d48013c0
updated QEMU. Adapted emu.rs to fit new interface. (#1774)
* updated QEMU. Adapted emu.rs to fit new interface.

* format
2024-01-03 20:10:20 +01:00
Dominik Maier
d143cac663
Fix atheris fmt, clippy (#1769) 2024-01-02 23:12:37 +01:00
Dominik Maier
925b33889f
LibAFL Atheris Compatibility (#1576)
* Made changes to libafl_atheris/src/lib.rs to work with Atheris

* Removed unused imports

* Ran  on libafl_atheris

* Fixed issue with using extra_counters and issue with using println

---------

Co-authored-by: eceo902 <evan.seeyave@gmail.com>
Co-authored-by: Evan <53020947+eceo902@users.noreply.github.com>
2024-01-02 22:18:34 +01:00
Bet4
4f93d7e894
Check canonicalized_module_path before used (#1767) 2024-01-02 18:16:02 +01:00
David CARLIER
440e57dd6f
afl_cc llvm 18 build fixes (#1759) 2024-01-02 14:13:52 +01:00
Dominik Maier
a07563def0
Add mute_inprocess_target fn, SimpleFdLogger::set_logger, and more (#1754)
* Add mute_inprocess_target fn, SimpleFdLogger::set_logger, set_error_print_panic_hook

* Trying to fix #1753

* typo

* More fix

* Fix test?

* more testcase fixes
2024-01-01 23:14:59 +01:00
Romain Malmain
38e16fbade
replace Emulator::new_empty by Emulator::get calls outside of emu.rs for safety. (#1763) 2024-01-01 18:49:11 +01:00
Dongjia "toka" Zhang
2717018601
Dedup common code in scheduler (#1702)
* dedup common code in scheduler

* del eco

* fixing

* fix
2024-01-01 18:22:03 +01:00
mkravchik
df96bb02ee
Enabling DrCov on Windows (#1765)
* Enabling DrCov for Windows
2023-12-27 11:10:04 +02:00
Dominik Maier
9ad7d9bb64
Miri ignores for M1 regex (#1762) 2023-12-27 00:36:21 +01:00
Bet4
ce71858100
Documentation fixes (#1761)
* Documentation fixes

* Fix InProcessExecutor url

* Update all urls to latest
2023-12-26 11:27:07 +01:00
lazymio
ea5ea3410c
Fix incorrect imports (#1758)
* Fix incorrect imports

https://doc.rust-lang.org/core/simd/trait.SimdOrd.html

* Fix

* Try fix ci
2023-12-23 23:12:20 +09:00
Dominik Maier
16a152267e
Ignore SigPipe by default (#1741)
* Ignore SigPipe by default

* Fix no_std

* fmt
2023-12-22 16:50:36 +01:00
Dominik Maier
c93291ab57
Fix as_object UB discussed in #1748 (#1751)
* Fix as_object UB discussed in #1748

* More cleanup, more less UB

* Fix fixes

* Added uninit_on_shmem api

* clippy

* fmt

* trying to fix fuzzers, libfuzzer wrapper

* Add OwnedRefMit::owned constructor, libfuzzer fix

* Some more fixes

* Add BacktaceObserver::owned fn

* fmt

* more fmt
2023-12-22 16:49:01 +01:00
Dominik Maier
4e7d2caa9f
Remove unused create_anymap_for_trait macro (fixes #1719) (#1752) 2023-12-22 16:48:43 +01:00
fc331fc6d8 consolidate outputs 2023-12-22 12:57:51 +01:00
90cae14958 new cli 2023-12-22 12:57:51 +01:00
6e0b49bf9b switch address data type, simplify synbol resolution 2023-12-22 12:57:51 +01:00
aba83dfb6f minor fixes 2023-12-22 12:57:51 +01:00
5648255542 fixup graph cycles 2023-12-22 12:57:51 +01:00
d179343a63 add delay list overflow 2023-12-22 12:57:51 +01:00
61ff3e3196 WIP: quick-fix for missing metadata 2023-12-22 12:57:49 +01:00
38e5767775 filter interrupt abbs 2023-12-22 12:56:54 +01:00
3fcb9a74e0 add graph printing 2023-12-22 12:56:54 +01:00
4e18b8fdab fix graph dump build 2023-12-22 12:56:54 +01:00
3a601fe250 hack async activation detection 2023-12-22 12:56:54 +01:00
bf42de5698 fix api regression 2023-12-22 12:56:54 +01:00
82908badfd add simple iteration counter 2023-12-22 12:56:54 +01:00
086a575f44 add delay list to RefinedFreeRTOSSystemState 2023-12-22 12:56:54 +01:00
e31c01b2af capture delay list 2023-12-22 12:56:54 +01:00
6dafc4f9d6 update to 0.11.1 2023-12-22 12:56:54 +01:00
92da68af6f small build fixes 2023-12-22 12:56:54 +01:00
53ef9ae96e port to libafl 0.10.1 2023-12-22 12:56:54 +01:00
900ce0bc92 remove dead code 2023-12-22 12:56:54 +01:00
e9f2792488 igonre archives 2023-12-22 12:56:54 +01:00
2d70cff21e eval script wrangeling 2023-12-22 12:56:54 +01:00
5ddb7192ba HACK: interrupt limit for random fuzzing 2023-12-22 12:56:54 +01:00
711fd36200 plot enpoints 2023-12-22 12:56:54 +01:00
81cbddc1be paralellize plots 2023-12-22 12:56:54 +01:00
8c6f8c861f update plot script 2023-12-22 12:56:54 +01:00
47d7ff3c48 tweak time outputs 2023-12-22 12:56:54 +01:00
f2244c96b0 add run_until_saturation 2023-12-22 12:56:54 +01:00
a970954a40 update snakefile 2023-12-22 12:56:54 +01:00
db6df36110 fix empty iterator crash, restart 2023-12-22 12:56:54 +01:00
884a19cf9d set up configurations 2023-12-22 12:56:54 +01:00
e130155204 add missing use 2023-12-22 12:56:54 +01:00
a6052ddad7 randomize interrupts until wort 2023-12-22 12:56:54 +01:00
dd6be70a01 Test: remove pc from hash 2023-12-22 12:56:54 +01:00
0e5dc21cd6 Test: hash notification states 2023-12-22 12:56:54 +01:00
ee15313d96 allow plotting from remote mount 2023-12-22 12:56:54 +01:00
4e08db297a update snakefile 2023-12-22 12:56:54 +01:00
8395ca1000 small fixes 2023-12-22 12:56:54 +01:00
e2aee4af17 WIP: add simple interrupt time randomizer 2023-12-22 12:56:54 +01:00
fef550ecb6 update target_symbols 2023-12-22 12:56:54 +01:00
fc0f1807a9 skip unchanged interrupts 2023-12-22 12:56:54 +01:00
2032f1420d fix staeg setup 2023-12-22 12:56:54 +01:00
fb95bc9e3c fix use 2023-12-22 12:56:54 +01:00
063a4c9216 WIP: move interrupt mutation to new stage 2023-12-22 12:56:54 +01:00
e673d02b70 wip: interrupt placement 2023-12-22 12:56:54 +01:00
f88bd8044b add interrupt mutator 2023-12-22 12:56:54 +01:00
0318891ef6 plot min and max lines 2023-12-22 12:56:54 +01:00
db492f4525 plot lines instead of points 2023-12-22 12:56:54 +01:00
356d05bf26 fixes 2023-12-22 12:56:54 +01:00
147f8c3f69 revert changes 2023-12-22 12:56:54 +01:00
8be9d9146a add generation based genetic testing 2023-12-22 12:56:54 +01:00
d005a8e044 snakefile: dump cases, fix random fuzzing 2023-12-22 12:56:54 +01:00
6a8e9c80c1 add a new scheduler for systemtraces 2023-12-22 12:56:54 +01:00
5db99e4e68 fix snakefile, symbols 2023-12-22 12:56:54 +01:00
99daee7b14 seed rng from SEED_RANDOM 2023-12-22 12:56:54 +01:00
f075988643 determinism fixes, scheduler precision, restarts 2023-12-22 12:56:54 +01:00
c49edd729d switch to native breakpoints 2023-12-22 12:56:54 +01:00
090b006a50 fix interrupt config 2023-12-22 12:56:54 +01:00
d4407b331d fix rng seed 2023-12-22 12:56:54 +01:00
9ea825bbf9 configure restarting manager 2023-12-22 12:56:54 +01:00
7f6ef95496 add micro_longint 2023-12-22 12:56:54 +01:00
98328ae50f fuzz multiple interrupts 2023-12-22 12:56:54 +01:00
c024001243 rework plotting 2023-12-22 12:56:54 +01:00
0abb6a0d41 add interrupt fuzzing 2023-12-22 12:56:54 +01:00
bd3362309f dump time for showmap 2023-12-22 12:56:54 +01:00
e3b05df3c0 add plotting to snakefile 2023-12-22 12:56:54 +01:00
8387b61622 add feed_longest to record random cases 2023-12-22 12:56:54 +01:00
0b6d8a93b8 plotting: respect types 2023-12-22 12:56:54 +01:00
deee67fd3b change feedback order 2023-12-22 12:56:54 +01:00
a531d27464 fix build 2023-12-22 12:56:54 +01:00
cfb8ebd0ad fix feedbacks 2023-12-22 12:56:54 +01:00
ba5c3c8037 benchmark using snakemake 2023-12-22 12:56:54 +01:00
96e79144c2 trace_abbs and dump path 2023-12-22 12:56:54 +01:00
7a3aaba0a3 add graph feedback 2023-12-22 12:56:54 +01:00
fc355f5fd1 update input sizes, dump worstcase, benchmarking 2023-12-22 12:56:54 +01:00
5a2d75a317 remove address translations, extend plots 2023-12-22 12:56:54 +01:00
cf68ad4a85 add hists to plot script 2023-12-22 12:56:54 +01:00
dcd899b789 speed up random generation 2023-12-22 12:56:54 +01:00
27877bde97 write out times over time 2023-12-22 12:56:54 +01:00
091ce4b24f add sytemstate sceduler, fuzz until time 2023-12-22 12:56:54 +01:00
f26eed2178 re-add system state fuzzing 2023-12-22 12:56:54 +01:00
85718c1280 add virtual edge to longest runs 2023-12-22 12:56:54 +01:00
76f6114b50 do not force generated inputs 2023-12-22 12:56:54 +01:00
ea7edb2001 debug stuff 2023-12-22 12:56:54 +01:00
180edbb7d5 random seeds, better plots 2023-12-22 12:56:54 +01:00
e70a816f49 add more benchmarks 2023-12-22 12:56:54 +01:00
1976150a45 exectime increase feedback 2023-12-22 12:56:54 +01:00
f1552f95a0 rename bin, allow random fuzzing 2023-12-22 12:56:54 +01:00
00b68edfb3 benchmark with duration 2023-12-22 12:56:54 +01:00
25e81498f5 add benchmark scripts 2023-12-22 12:56:54 +01:00
fab1b1ef9f add systemstate feature and dump times 2023-12-22 12:56:54 +01:00
7fa6fd7f85 fix multicore build 2023-12-22 12:56:54 +01:00
a5b333f635 ignore artifacts 2023-12-22 12:56:54 +01:00
5c80cb780f minimal changes 2023-12-22 12:56:54 +01:00
7f362f5907 add interrupt injection 2023-12-22 12:56:54 +01:00
e2f4744823 input length and read input pointer 2023-12-22 12:56:54 +01:00
c3b2777acb draft: add graph feedback 2023-12-22 12:56:54 +01:00
3435a79e26 add TimeMaximizerCorpusScheduler 2023-12-22 12:56:54 +01:00
25a58ddbe1 add last api callsite to system state 2023-12-22 12:56:54 +01:00
b678f9f18b libafl_qemu: add jmp instrumentation 2023-12-22 12:56:51 +01:00
b3416fe0c5 WIP: add systemstate tracking 2023-12-22 12:54:16 +01:00
66c4cb5316 add arguments 2023-12-22 12:54:16 +01:00
693ba3b942 get time from ClockTimeFeedback 2023-12-22 12:54:16 +01:00
0a703f6ff5 fixup 2023-12-22 12:54:16 +01:00
03fbe41dbb WIP: port fret 2023-12-22 12:54:16 +01:00
Dongjia "toka" Zhang
9993cf1000
symcc_update (#1749) 2023-12-22 02:29:46 +09:00
Romain Malmain
830faec95f
QEMU filtering rework + paging filtering (#1705)
* Added paging filtering.
Reworked address range filtering to fit with new generic code.

* Fix: renamed remaining QemuInstrumentationFilter instances.

* Fix: clippy + format

* Updated qemu-libafl-bridge

* Fix QEMU userspace crash handler (#1706)

* Fix QEMU userspace crash handler

* no_std

* libafl_cc custom llvm_config lookup for solaris/illumos (#1708)

* fix simd (#1709)

* Updated qemu

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: David CARLIER <devnexen@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-12-21 15:51:14 +01:00
David CARLIER
ea61b79012
bolts/minibsod add openbsd arm64 support (#1724)
* bolts/minibsod adding openbsd arm64 part.

* disable core ids test on freebsd
2023-12-21 14:25:25 +01:00
Dongjia "toka" Zhang
a98805b4ca
Another attemp to fix CI (#1744)
* fixing?

* more

* delete macos build_and_run fuzzers as its runtime exceeds 360minutes and can't fix it
2023-12-21 04:43:01 +09:00
Dominik Maier
68e7b203f5
Add file descriptor logger (#1742)
* Add file descriptor logger

* clippy

* Fix closing fds

* fix no_std, fmt

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-12-20 16:53:33 +01:00
Dongjia "toka" Zhang
57a64e805f
Trying to fix CI (#1739)
* test

* dummy

* dummy
2023-12-20 16:48:02 +09:00
Dongjia "toka" Zhang
78060ea308
0.11.2 (#1735) 2023-12-18 14:33:14 +01:00
van Hauser
63e1523358
small fixes and enhancements (#1731)
* nits

* first steps

* different approach

* fixes

* remove temps

* remove temp

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-12-17 20:19:15 +09:00
Addison Crump
ef8ebd5239
fixup: don't download unicode categories data (#1732)
* fixup: don't download unicode categories data

* whoops, document

* fmt

* ci

---------

Co-authored-by: toka <tokazerkje@outlook.com>
2023-12-17 19:09:59 +09:00
iximeow
2726a59711
use yaxpeax-x86 version from crates.io instead of direct git dep (#1733) 2023-12-17 15:54:12 +09:00
Dongjia "toka" Zhang
7894efe728
Last cleanup after decapstone (#1727)
* Last clenup

* more

* more
2023-12-16 19:51:42 +09:00
Sharad Khanna
fce5fd9a2b
Remove capstone from frida [aarch64] (#1723)
* Partially finish ASAN and CmpLog changes

* Fix handle_trap, report_error, and remove capstone

* Fix a few bugs. Can now detect UAFs properly

* Some small changes

* Make API more consistent with x86

* Fix printing

* Remove unneeded inputs, final changes

* formatting

* Fix x86 build

* Formatting
2023-12-16 16:10:40 +09:00
Dongjia "toka" Zhang
a0a4dd60bb
Remove capstone from frida [x86_64] (#1720)
* init

* more

* just fixing stuff
2023-12-16 02:39:11 +09:00
Dongjia "toka" Zhang
ee447468c6
message (#1726) 2023-12-16 00:13:21 +09:00
Andreas
2f036b72e4
Make inner value of llmp Flags pub (#1725) 2023-12-15 20:58:05 +09:00
Andrea Fioraldi
002656b076
Fix #1721 (#1722) 2023-12-11 15:26:53 +01:00
Dongjia "toka" Zhang
c2db7ad162
Add Resource (#1718) 2023-12-07 13:54:56 +01:00
mkravchik
b336411516
Adding support for shutdown upon Ctrl+C on Windows for LLMP (#1704)
* Adding support for shutdown upon Ctrl+C on Windows for LLMP

* PR comments and clippy suggestions addressed

* Enable CI for PR branches and manually triggered CI

* Removed an empty line that broke compilation on some platforms

* Trying to fix nostd compilation

* Trying to fix nostd compilation for nightly toolchain

* Removing use that is unused on some platforms

* Trying to fix build on the nightly toolchain

* Trying to fix build on the nightly toolchain, take 2

* Unifying LlmpShutdownSignalHandler

* Fmt fix

* Making the handler pub(crate)

* Nightly toolchain fmt fixes

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-12-05 21:03:00 +01:00
tbethe
686d29a3cb
Don't reset child_pid in forkserver executors (#1715)
Child pid is no longer reset after a run in persistent mode

Co-authored-by: Timme Bethe <git@timmebethe.nl>
2023-12-05 20:38:17 +01:00
Dongjia "toka" Zhang
fad59987d9
Better SigInt handler (#1710)
* fix simd

* better exit

* chg

* more

* more

* use

* change to proper name

* w

* aaaaaaa

* delete

* just separate them

* shell check
2023-12-04 20:06:11 +01:00
Dongjia "toka" Zhang
210315da0f
fix simd (#1709) 2023-12-03 16:19:12 +01:00
David CARLIER
108c04a8d2
libafl_cc custom llvm_config lookup for solaris/illumos (#1708) 2023-12-03 10:23:33 +01:00
Andrea Fioraldi
517d6962bd
Fix QEMU userspace crash handler (#1706)
* Fix QEMU userspace crash handler

* no_std
2023-12-01 13:26:10 +01:00
Andrea Fioraldi
5d83c9399a
Fix bp in QEMU thumb mode on arm64 systems (#1701) 2023-11-29 10:37:10 +01:00
Andrea Fioraldi
bc458864f1
Fix libafl_qemu edge hooks src addr (#1700) 2023-11-28 17:16:15 +01:00
Rowan Hart
5d5ee40329
Add Features for C Targets (#1663)
* Allow disabling C targets for platforms that dont support them when using cmp observers

* Make sancov depend on coverage
2023-11-27 22:34:41 +01:00
David CARLIER
c84629a2f8
bolts: fix solaris cpu binding (#1699)
Seems `PS_MYID` to save one syscall was not really working, explicit current id makes the test always pass.
2023-11-27 22:34:12 +01:00
Andrea Fioraldi
1545514ed8
JIT fast path for edge cov hooks in libafl_qemu (#1696)
* JIT fast path for edge cov hooks in libafl_qemu

* fix

* fmt

* fix

* unify hooks as opt
2023-11-27 13:20:20 +01:00
Dongjia "toka" Zhang
00740190a7
Delete update_rust_toolchains.yml (#1698) 2023-11-26 21:01:55 +01:00
Mrmaxmeier
84a87f1da8
bolts: support dump_registers for x86 linux (#1694)
* bolts: support dump_registers for x86 linux

* bolts: fix write_crash fault addr for linux/x86
2023-11-26 16:39:16 +01:00
Romain Malmain
bd12e060ca
Update qemu-libafl-bridge (#1697)
Update to last version of qemu-libafl-bridge
2023-11-24 20:19:57 +01:00
Dongjia "toka" Zhang
16af5debbe
Fix aggreagator ui (#1693)
* fix

* more

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-11-24 13:50:57 +01:00
Romain Malmain
b4e987a640
Clippy fix for Refactor QEMU hooks (#1695)
* clippy

* format

* clippy
2023-11-24 13:15:33 +01:00
Andrea Fioraldi
f1aee3c376
Refactor QEMU hooks (#1690)
* Rewrite QEMU Asan

* fake sys

* New hooks

* edge cov helper

* opaque raw hook

* new hooks

* EMulator::get

* new asan

* fix fuzzers

* fix types

* fix

* fix

* fix

* merge fix

* fix
2023-11-23 18:57:15 +01:00
Romain Malmain
43c9100f59
QEMU Synchronous Exit + Syx Snapshot update (#1681)
* Fix: typo in variable name.

* Fix: thread-safe static for emulator initialization.

* Initial support for synchronous exit from QEMU.

* New commands for the sync exit feature.
Supports physical and virtual address requests.
Updated for new SyxSnapshot naming.

* update qemu commit and fix some things

* - Removed lazy_static dependency
- Compiles for usermode
- Format

* Fix warnings

* Fixed sync_exit for missing architectures

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-11-23 17:35:32 +01:00
Dongjia "toka" Zhang
28f34e076e
Reduce deps (#1692) 2023-11-23 17:21:13 +01:00
Dongjia "toka" Zhang
903a242e3e
Fix unused import (#1691) 2023-11-22 21:04:05 +01:00
Dongjia "toka" Zhang
4a94bcb806
Monitor refactor + add aggregator (#1671)
* push

* decouple clients_stats_mut_for

* coding done

* push

* more

* upd

* fix

* aa

* don't change harness
2023-11-22 20:38:59 +01:00
Dongjia "toka" Zhang
cad2ff6319
Fix scheduled ci (#1688)
* fix

* small z
2023-11-22 11:46:15 +01:00
Dongjia "toka" Zhang
9a1173d4a6
scalability monitor 2nd (#1685)
* tekito

* monitor

* fix

* all

* ci

* ci
2023-11-21 23:54:19 +01:00
Dongjia "toka" Zhang
9345b80256
Schedule rust update in build_and_test.yml (#1687)
* ci cron

* correct regex
2023-11-21 23:49:36 +01:00
s1341
ba394c4acc
Fix LLMP map reuse overflow for slow brokers (#1679)
* Attempt to fix llmp refcounting

* readers->readers_count

* Removed refcounting for now, fixed

* fixes

* fixes

* add extra debug assert, remove duplicate line

* semicolons are pain :)

* Add comment

* oooooops, bugfix

* fmt

* Fix calcualtion in in_shmem

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-11-21 16:48:17 +01:00
Dongjia "toka" Zhang
379e2ae89b
Scalability introspector + State refactor (#1674)
* check

* clippy fmt fixing all the stuff

* restore Cargo.toml

* a

* ci

* ci

* a

* a

* workging?

* work

* ?

* why it worksgit add -u

* ci

* ci

* TMATE

* ci

* ci

* ci

* remove tmate

* less

* fuck; let's try with introspection first

* fucking macro

* another windows shit

* stop it

* i'm harassed by how shit windows is

* fixing

* ci

* ziopera

* fix from main

* ci

* ci
2023-11-21 14:38:48 +01:00
Addison Crump
86cb187ef1
Add arg for profile in build.sh (#1680) 2023-11-21 04:15:53 +01:00
Addison Crump
281524dbf9
Unicode-preserving mutators (#1542)
* create the string classification stage

* modify API to pre-group

* preserving mutator

* more meaningful test

* subproperty mutators + some fixes

* document, finalise, integrate with libafl_libfuzzer

* add example, fix for weird range select

* fix for introspection

* fix fuzzer build

* speed optimisation: allow, but do not require, stacking

* property => category

* token replacement

* fixup: rare case where rust does not agree on valid character

* fix CI again

* again again

* take two: dynamic unicode discovery

* oops

* fix: last byte is never selected

* opt: bias to smaller unicode categories

* fix test

* opt: precompute regions and fix tests

* cache and allow stacking

* document and update libafl_libfuzzer

* oops, use reverse

* fix bolts clippy error

* fixup part 2

* clippy

* part 2

* clippy warning allow

* clippy complaint

* use alloc not std

---------

Co-authored-by: toka <tokazerkje@outlook.com>
2023-11-21 00:41:16 +01:00
Addison Crump
1e96652ed2
libafl_libfuzzer: rename all symbols and allow mimalloc use (#1565)
* rename allocator symbols to avoid conflict with mimalloc

* re-add llvm-tools to CI

* rename everything

* fixup clippy lint

* make fuzzer entries more noticeable :)

* rabbit mode

* clippy
2023-11-20 21:55:40 +01:00
Andrea Fioraldi
aa69436b64
Fix i386 QEMU read_function_argument() (#1677) 2023-11-20 13:53:29 +01:00
Addison Crump
a278357ed9
Add whole-archive feature to libafl_targets (#1544)
* maybe fix linkage?

* fix hack CI

* interceptors

* do not call strstr and friends

* format

* whoops

* enforce nightly; fixup linkage by featuring interceptors

* skip libafl_libfuzzer in stable cargo hack check

* oops

* packed_bundled_libs is stablised
2023-11-20 10:38:17 +01:00
David CARLIER
a013ad6085
bolts for haiku update (#1673)
core_affinity using available_parallelism which also support this
platform. further tests disabling.
2023-11-19 23:58:30 +01:00
s1341
57296a6750
Use Compound configurations in libpng launcher fuzzer (#1676) 2023-11-19 11:11:52 +01:00
Andrea Fioraldi
cc1ebb29f7
Add CmpLog routines to LibAFL QEMU and various fixes (#1664)
* Add CmpLog routines to LibAFL QEMU and various fixes

* format

* fix

* fix read_function_argument

* fix

* multithread

* fix qemu fork

* fix

* clippy

* fix systemmode

* unused imports
2023-11-17 16:59:50 +01:00
Andrea Fioraldi
d606d9f4f6
Avoid lagged receiver in TCP manager (#1672) 2023-11-17 14:23:51 +01:00
Andrea Fioraldi
d7825851e9
Fix SimpleRestartingMonitor after restart (#1669)
* Fix SimpleRestartingMonitor after restart

* a

* a

* a

* a

* a

* a

* a

* a

* a

* ci

---------

Co-authored-by: toka <tokazerkje@outlook.com>
2023-11-16 20:06:27 +01:00
Mark Giraud
0750a6c3ca
refactor: Remove unnecessary Debug trait bounds (#1667)
* refactor: Remove Debug supertraits

Instead of having the Debug trait as supertrait on several traits, the
Debug trait is now required in bounds in specific implementations that
need this specific trait. This keeps the API cleaner, since users now
don't have to propagate the Debug requirement if they don't need to use
the Debug trait.

* refactor: Reformat code
2023-11-15 20:26:12 +01:00
s1341
b1888e12c9
Support precompiled headers in clang/ar wrappers (#1668) 2023-11-15 15:10:03 +01:00
s1341
7acdeacae8
Allow compiling 32bit (#1666)
* Allow compiling for 32bit

* Fmt

* Clean up minibsod for 32bit

* fmt
2023-11-15 12:43:04 +01:00
Dominik Maier
8c62d339a2
Fix FreeBSD CI by updating freebsd-vm (#1665) 2023-11-13 22:51:57 +01:00
Dominik Maier
1138e6a341
Fix CI (#1662) 2023-11-10 12:08:29 +01:00
Benjamin Beyret
6300c5f493
Remove debug log (#1659) 2023-11-08 15:46:20 +01:00
Dongjia "toka" Zhang
d53503b73e
Fix stb image on windows (#1657)
* fix

* fix

* HOW DO I ADD FROM:FROM????

* ok
2023-11-08 15:20:35 +01:00
Benjamin Beyret
c97d0fa7fc
Allow MinimizerScheduler to not cleanup metadata after use (#1658)
* Allow MinimizerScheduler to not cleanup the metadata after use.

* Fix constructor

* cargo fmt and fix docstring.
2023-11-08 12:00:25 +01:00
Nereuxofficial
6089cc21ce
Fixed panic feature in baby_fuzzer example (#1656)
* Fixed panic feature in baby_fuzzer example

* Fixed typo
2023-11-08 00:14:42 +01:00
Dongjia "toka" Zhang
c9e147de8c
Fix LLVM Pass (#1654) 2023-11-06 13:35:10 +01:00
Dominik Maier
8545778780
Revert "Use clang-format-16 (#1649)" (#1650)
This reverts commit 1aede04af75564d4063f91d1c8c1a402760e86f5.
2023-11-04 21:38:36 +01:00
Abc Xyz
65ddfa6acf
drcov_rt: make coverage file names unique (#1581)
* fix(drcov_rt): coverage files are overwritten if have the same names

Make it unique.

* fix(drcov_rt): use coverage and input as a filename, skip empty covs
2023-11-04 17:54:35 +01:00
Dominik Maier
8a18ee4ece
Add Android Ashmem stub header to libafl_targets forkserver.c (#1648)
* Add Android Ashmem stub header to libafl_targets forkserver.c

* clang-format
2023-11-04 17:48:02 +01:00
Dongjia "toka" Zhang
1aede04af7
Use clang-format-16 (#1649) 2023-11-04 17:45:01 +01:00
David CARLIER
bae24d9072
bolts: haiku, addressing clippy warnings (#1647) 2023-11-04 17:03:09 +01:00
Addison Crump
56b37bb4bd
Improve the libafl_libfuzzer corpus (#1539)
* improved libfuzzer corpus

* use .into() for converting ids to usize

* oops

* fix warning about unused arg

* fix some lingering CI errors

* actually save the last lmao
2023-11-03 17:33:38 +01:00
Addison Crump
fd98eabfbf
clamp last to infinity to handle rare imprecision issues (#1532) 2023-11-03 17:32:48 +01:00
David CARLIER
2e980ca08d
bolts: initial haiku support (#1643) 2023-11-03 17:18:53 +01:00
Dongjia "toka" Zhang
745326ee26
Add post_run_target for ShadowExecutor (#1641) 2023-10-30 19:27:55 +01:00
Anne Borcherding
976d6b2e97
[WithObservers] Call the wrapped observer's post run function (#1640)
* [WithObservers] Call the wrapped observer's post run function

* fix typo and naming of variable
2023-10-30 17:58:54 +01:00
Azim Muradov
ad33ea086b
Fix typos and crates names formatting in crates.md (#1639)
* Fix typos and crates formatting in crates.md

* Fix header in crates.md
2023-10-27 11:31:02 +02:00
Dongjia "toka" Zhang
c6c93b5785
aa (#1638) 2023-10-25 16:36:20 +02:00
Dongjia "toka" Zhang
fdfa5b2d48
Fix ci (#1637)
* fix

* Stupid lint 🖕
2023-10-25 16:28:31 +02:00
Dongjia "toka" Zhang
f34bab2486
Fix CI (#1636) 2023-10-25 16:10:10 +02:00
Andrea Fioraldi
406e77faa9
QEMU Asan backtrace and report (#1628)
* wip

* ExtractFirstRefMutType

* Asan report with backtrace

* Print asan reports and fix backtraces in libafl qemu

* print context

* enlarge redzone

* nopstate

* fix

* reproducer

* clippy

* clippy

* Fix android

* Crash hook
2023-10-25 15:58:32 +02:00
Dongjia "toka" Zhang
02cd260af0
Update LibAFL concolic (#1634)
* concolic upd

* more

* working

* clippy

* rev

* fix

* remove cur_input

* rev

* gitignore
2023-10-22 13:44:01 +02:00
Anne Borcherding
c9403cbd00
fix: use correct trait bound in WithObservers Executor (#1633) 2023-10-20 16:32:40 +02:00
cube0x8
0db67dfc9a
updated rust container image + default nightly (#1631) 2023-10-19 11:05:39 +02:00
Dongjia "toka" Zhang
0b38fabeb0
CmpLog {Instruction, Switches} pass (#1612)
* switch and instruction pass copy paste

* FMT

* add cb

* put things in the functions

* fi

* working

* oops

* options

* no 128bit int on windows

* no 128bit on windows

* oops

* unix only

* windows

* PACKED

* let's stop using it, it's ugly

* fmt

* adjust

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-10-14 11:47:16 +02:00
Dongjia "toka" Zhang
77dfc7a26a
Update llvm ver in Dockerfile (#1629)
* llvm 15

* more
2023-10-13 17:00:12 +02:00
Benjamin Beyret
1b7e1da809
Fix typo in SimpleStdoutLogger comment. (#1627) 2023-10-12 17:03:38 +02:00
Dongjia "toka" Zhang
cb9ace52e1
Rename more options (#1626) 2023-10-12 12:01:39 +02:00
Andrea Fioraldi
f6ba9de044
Add SplitBorrow trait to split borrow tuple_list elements (#1624)
* Add SplitBorrow trait to split borrow tuple_list elements

* clippy
2023-10-12 10:16:41 +02:00
Andrea Fioraldi
4c17da00b0
Clipped Fixxy (#1622)
* clippy fix

* fix

* fix

* it works

* imports
2023-10-11 21:19:30 +02:00
Dongjia "toka" Zhang
67aa5b12c1
Rename option name (#1623)
* rename

* FMT
2023-10-11 17:38:56 +02:00
Andrea Fioraldi
35e387773c
Format C code (#1621)
* Add iter() to owned slice

* Format C
2023-10-11 14:19:14 +02:00
Andrea Fioraldi
6986317a03
Add iter() to owned slice (#1620) 2023-10-11 14:13:26 +02:00
Andrea Fioraldi
47cd4dfea6
Break on timeout in QEMU system mode (#1619)
* Break on timeout in QEMU system mode

* fix

* fix

* fix
2023-10-11 14:01:18 +02:00
Andrea Fioraldi
31f4669794
Autodetect llvm-config for QEMU bindings generation (#1610)
* Autodetect llvm-config for QEMU bindings generation

* fix ci

* Fix signal handlers without ucontext pointer

* ci
2023-10-10 15:26:32 +02:00
Andrea Fioraldi
bbb999f4d5
New logo in the book (#1618) 2023-10-09 15:54:04 +02:00
Dongjia "toka" Zhang
c94c26cb56
Document how to use cpp() and optimize() (#1615) 2023-10-07 16:36:33 +02:00
Dongjia "toka" Zhang
bc91436ef4
Refactor cmplog observers (#1603)
* refactor

* Rename Everything

* fmt

* chg

* test

* aa

* doc fix

* fix?

* doc
2023-10-06 15:22:11 +02:00
Dominik Maier
0bba8535b8
Tiny typo fix (#1611) 2023-10-06 01:11:23 +09:00
Dominik Maier
30686a2d28
Remove return type from fuzz_loop fn that never returns (#1606) 2023-10-06 01:02:16 +09:00
Dongjia "toka" Zhang
2ade1ee1f6
Bring back some checks (#1597) 2023-10-05 16:14:55 +02:00
Dongjia "toka" Zhang
f17e49e9aa
Remove warnings (#1609)
* two falgs

* UNIX ONLY FLAGS

* moa

* FMT
2023-10-05 15:25:55 +02:00
Dongjia "toka" Zhang
74783c2027
Add executions count at proper places (#1608)
* executions count

* tinyinst qemu frida

* aaaa

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-10-05 15:25:40 +02:00
Andrea Fioraldi
cffbf069d2
Call the original QEMU user crash handler in libafl_qemu (#1575)
* Call the original QEMU user crash handler in libafl_qemu

* Return if real crash or not

* merge

* Fix singal handlers in libafl and libafl_qemu

* doc and clippy

* clippy

* clippy

* clippy

* slirp

* fix

* fix system
2023-10-05 15:24:21 +02:00
cube0x8
d4e9107fc2
added ninja-build and python3-venv as dependencies (#1604) 2023-10-04 14:27:55 +02:00
Abc Xyz
7f68f66d70
drcov_rt: remove unused a field and methods (#1601) 2023-10-04 14:34:53 +09:00
Dominik Maier
cce25d0a94
Add OptionalStage (#1600) 2023-10-04 14:24:02 +09:00
Dongjia "toka" Zhang
fc16b70a65
Format C (#1602) 2023-10-03 13:40:19 +02:00
Dongjia "toka" Zhang
a9014a9419
fmt c too (#1593)
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-10-03 11:43:28 +02:00
Dominik Maier
25409119ff
Make Signals compatible with nix, implement TryFrom<&str> (#1599)
* Make our signals compatible to nix Signals

* no-default nix
2023-10-03 17:33:45 +09:00
Addison Crump
20f1119bab
libafl_libfuzzer: documentation and build script (#1596)
* add docs; add build script for prepping libFuzzer

* clarifications
2023-10-03 16:56:27 +09:00
s1341
a27553daec
libafl_cc: fix configuration support (#1595)
* libafl_cc: fix configuration support

* fmt

* clippy
2023-10-02 17:48:33 +03:00
Dongjia "toka" Zhang
f35c59131d
Fix redundant area_is_valid() (#1594) 2023-10-02 13:44:42 +02:00
Dongjia "toka" Zhang
b20fda2a4a
Use /dev/urandom instead of /dev/null for probing valid memory (#1586) 2023-10-01 23:08:29 -05:00
Dongjia "toka" Zhang
583c84ab4e
cmplog routines update & fix (#1592)
* update

* runtime

* Update cmplog-routines-pass.cc (#1589)

* rtm

* fix

* no link rt

* fmt

* let's change script in another pr

* colon

* adjust the checks

* fix

* more fixes

* FMT
2023-10-01 23:06:34 -05:00
Abc Xyz
5854fd0c5b
fix(libafl_frida): correctly calculate the coverage using DrCov (#1579) 2023-10-01 08:11:46 -05:00
Dongjia "toka" Zhang
ee9eb3eef1
Revert "Update cmplog-routines-pass.cc (#1589)" (#1591)
This reverts commit d2ff88f6ff6ec38c16200e9ee59c180412430120.
2023-10-01 14:46:21 +02:00
Dongjia "toka" Zhang
60b3408737
Update dependencies (#1588)
* update

* downgrade some
2023-10-01 07:20:23 -05:00
Dongjia "toka" Zhang
d2ff88f6ff
Update cmplog-routines-pass.cc (#1589) 2023-10-01 07:20:00 -05:00
Dongjia "toka" Zhang
2474691623
Fix libjpeg fuzzer (#1582)
* Revert "Insert into corpus if feedback is_interesting on crash/timeout (#1327)"

This reverts commit 871dfa0a013f31f84e43e125105febca2f137049.

* unused
2023-09-30 18:34:08 +02:00
Dongjia "toka" Zhang
f31c2cc4ce
remove unused deps (#1587) 2023-09-30 18:32:59 +02:00
Dongjia "toka" Zhang
70b75e7fdb
Fix BytesDeleteMutator (#1585) 2023-09-30 00:25:12 +02:00
Abc Xyz
0932421020
fix(libafl_frida): enable asan for Android x86_64 (#1578) 2023-09-29 17:10:27 -04:00
Abc Xyz
6f67919622
fix(minibsod): allow dump_registers and write_crash for Android x86_64 (#1577) 2023-09-29 17:10:15 -04:00
Dongjia "toka" Zhang
5b0e3dd3bc
Make fuzzbench debugging easier (#1574)
* to make debugging easier

* debug
2023-09-29 18:32:09 +02:00
WorksButNotTested
d3a4b726d8
Added qemu_cmin (#1572)
Co-authored-by: Your Name <you@example.com>
2023-09-29 08:59:41 -04:00
WorksButNotTested
9755d189dd
Write coverage for QEMU into separate files (#1571)
Co-authored-by: Your Name <you@example.com>
2023-09-28 15:57:34 -04:00
s1341
78fd4e0d39
frida-asan: move to mmap-rs (#1570) 2023-09-28 16:35:54 +03:00
WorksButNotTested
9c3f8f4511
Qemu features3 (#1538)
* Fix issue with libafl_qemu being repeatedly rebuilt

* Changes to make qemu_launcher a production ready fuzzer

* Remove _get prefix

* Don't collect DrCov data during the campaign

* Fix poor performance

* Better validation for core selection

* Changes to print debug when running in verbose mode

* Autofix

* Remove afl++-clang

* Fix build error on 32-bit

* Fix some clippy

* Fix OSX

* Set default version of clang/clang++

* Review changes

* Fix issue with fd sharing between processes

---------

Co-authored-by: Your Name <you@example.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-09-28 14:31:15 +02:00
Andrea Fioraldi
19aac2fc04
Fix TCP manager and restarts (#1556)
* Fix TCP manager and restarts

* clippy

* clippy

* clippy
2023-09-28 13:46:07 +02:00
s1341
652c24cb2a
windows: Support LIBAFL_DEBUG_OUTPUT (#1569) 2023-09-28 11:16:41 +03:00
s1341
7cb1080e35
libafl_ar: add extensions (#1568) 2023-09-28 09:09:29 +03:00
Dongjia "toka" Zhang
4e6ad397ec
Fix CI (#1567) 2023-09-28 00:47:40 +02:00
s1341
fd229328eb
Fix frida libafl after #1523 (#1560)
* Fix frida libpng after PR1523

* fmt

* Fix

* Clippy
2023-09-27 08:02:11 -04:00
Dongjia "toka" Zhang
b3483ddd42
Give proper name to some crates and exclude them 2 (#1562)
* fix

* comma
2023-09-27 13:29:24 +02:00
Dongjia "toka" Zhang
324db072a2
Fix CI (#1558)
* endif

* just fix every profile

* WHY YOU DONT JUST USE THE SAME NAME FOR DIR

* fix

* Some fuzzer want release

* WHY I ALWAYS FORGET COMMA

* NO MORE SPACE

* rename

* stb doesn't like debug build

* just use release

* another just use release
2023-09-27 09:59:55 +02:00
Dongjia "toka" Zhang
74435e1461
Fix LLVMPass (#1557) 2023-09-26 18:54:54 +02:00
Dongjia "toka" Zhang
c1006c4d38
Fix CI (#1553)
* export PROFILE

* install aflplusplusw

* no dot

* a
2023-09-25 20:51:40 +02:00
Dongjia "toka" Zhang
c1eef33b5d
Remove --release from Makefile.toml (#1522)
* rem release

* Revert "rem release"

This reverts commit 13aaf13e412818629880348188c3e1b4137b9ed8.

* toggle it with envvar

* fm
2023-09-25 14:22:10 +02:00
Dongjia "toka" Zhang
dc7d561621
Don't send unstable entries if there's nothing (#1552)
* shutup calibration

* Update build_and_test.yml
2023-09-24 17:27:12 +02:00
Dominik Maier
aa7993de10
Some AFL UI example fuzzer cleanup (#1529)
* Some afl ui cleanup

* more info

* Fix CI (#1549)

* Change profiles for the fuzzbench fuzzers.

* just foreground

* Revert "just foreground"

This reverts commit abd4fbec40fd1a7f3bcca1190ce11816fc868c53.

* fix Makefile.toml

* Tmate debug

* fix?

* fix?

* Can't fix this

* remove reset

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-09-24 14:54:14 +02:00
Dongjia "toka" Zhang
c103444396
Change profiles for the fuzzbench fuzzers. 2023-09-22 23:51:06 +02:00
Dongjia "toka" Zhang
6251ad0051
Update llvm version in CI (#1533)
* UPD

* UPD

* UPD

* UPD

* MORE

* ??

* Update build_and_test.yml

* LLVM 15

* Update build_and_test.yml

* chg

* Update build_and_test.yml

* Update build_and_test.yml
2023-09-21 01:04:50 +02:00
Fabian Freyer
a092aed538
libafl_frida: Allow setting path for DrCovRuntime (#1536) 2023-09-21 01:03:56 +02:00
Dominik Maier
f70a16a09a
Fix unsoundness for misaligned map observers (#1530)
* Fix unsoundness for misaligned map observers

* nits

* clippy

* Make sure beginning of the page is aligned
2023-09-20 18:25:37 +02:00
Addison Crump
761a77fce0
libafl_libfuzzer fixes for port and fd allocation (#1525)
* better port and fd handling

* fix multitude of CI failures
2023-09-20 17:36:43 +02:00
Benjamin Beyret
0e149afd7a
Allow both fuzz_time and iters in TuneableMutationalStage (#1531) 2023-09-20 12:47:56 +02:00
Fabian Freyer
7f0a4f1d7e
libafl_frida: Add FridaInstrumentationHelperBuilder, don't rely on Clap options (#1523)
* impr(frida): Don't keep FuzzerOptions in Helper

Instead, keep the actual values that are needed. This allows us to make
a builder for FridaInstrumentationBuilder in a subsequent commit.

* refactor(frida): Move workaround to separate method

This is just code movement.

* refactor(frida): move transformer initialization

Mostly code movement here, sets up replacing `new` with a builder. The
one exception is the introduction of a lifetime bound on RT, which needs
to outlive the transformer. This could be generic, but there's probably
no reason to introduce an additional lifetime.

However, because of this lifetime introduction, this is _technically_ a
breaking change.

* impr(frida): Pass module map to runtimes

Instead of passing a slice of modules to instrument, and re-building the
modulemap, pass a Ref-counted module map directly to the initialization.

* feat(frida): Builder for InstrumentationHelper

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

* impr(frida/alloc): optional options in allocator

Move all the initialization into Default::default with sensible defaults
and override parameters set from options in new.

* impr(frida): remove options from AsanError

The only option AsanError uses is whether to continue on error. Instead
of keeping a whole clone of the options around, just store that single
boolean value.

* impr(frida/asan): Use less FuzzerOptions

* Implement Default::default to get a good default AsanRuntime

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-09-20 11:08:59 +02:00
Dongjia "toka" Zhang
fdd2f53871
Fix doc in testcase_score.rs 2023-09-20 10:36:56 +02:00
Dominik Maier
3625e881a3
Fix forkserver child kill, add kill_signal support (#1521)
* Fix forkserver child kill, add kill_signal support

* more fix
2023-09-19 17:27:50 +02:00
Addison Crump
8f6efe993d
Address recent clippy changes; build clippy in debug instead of release for perf (#1516) 2023-09-19 00:42:46 +02:00
Fabian Freyer
27333f9ce8
libafl_bolts fix potentially unaligned ucontexts in signal handler (#1520)
When entering a signal handler, the ucontext_t is not necessarily 0x10-aligned, so we need to use read_unaligned instead of dereferencing.
2023-09-18 23:17:54 +02:00
Addison Crump
6d0d4e287a
Metadata + infinite loop fix for TuneableMutationalStage (#1514)
* update tuneable: consistently access metadata + force 'choice'

* oops, loop in the wrong place

* clarify API some; allow for least of set configuration
2023-09-16 16:54:40 +02:00
Elnard Utiushev
d4f47340a3
libafl_libfuzzer: replace cargo:error with assert in build.rs (#1517)
It is very confusing if you are trying to build on MacOS
and it is telling you that it worked, but actually it didn't.
2023-09-16 01:53:33 +02:00
Andrea Fioraldi
acecf46fb9
Ignore TCP recv if failed (#1519) 2023-09-15 13:18:46 +02:00
Dongjia "toka" Zhang
b3e82ad36e
Add trophies (#1518) 2023-09-14 20:18:01 +02:00
Addison Crump
0b889312ae
mac forkserver linkage fix (#1503) 2023-09-14 12:52:29 +02:00
ToSeven
defe9084ae
Add an example fuzzer with AFL-Style UI (#1501)
* Add an example fuzzer with AFL-Style UI

* fix CI errors

* fix CI and improve the UI

---------

Co-authored-by: toseven <Byone.heng@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-09-12 10:17:31 +02:00
lenawanel
84beb61c3f
remove libafl/src/feedbacks/owned.rs (#1508)
fixes #1504
2023-09-08 11:14:37 +02:00
Andrea Fioraldi
5311ce705a
Fix missing usage of saved_tree in AsanGiovese (#1506) 2023-09-07 13:40:17 +02:00
David CARLIER
b090bc7b4b
bolts: openbsd (snapshot) clippy fix (#1502) 2023-09-06 03:39:43 +02:00
ToSeven
04aecd97f6
Add AFL-style metrics(pending,pend_fav, own_finds,imported) (#1351)
* add the metrics(pending,own_finds,imported)

* add the pend_fav metrics

* push

* Add the feature that AFLStats is computed and reported in AFLStatsStage

* fix some cicd errors

* AFLStats migrates to stage/stats.rs

* fix the cicd error

* fix some bugs and resolve the conflicts

* fix some typos

---------

Co-authored-by: toseven <Byone.heng@gmail.com>
Co-authored-by: toka <tokazerkje@outlook.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-09-06 03:38:41 +02:00
lenawanel
c791a23456
reduce memory usage of the construct_automata script (#1481)
* remove unneeded loop in `SpliceMutator::mutate`

previously we searched for the first and the last difference
between exactly the same 2 inputs 3 times in a loop

* remove unused struct fields

* avoid allocating strings for `Transition`s

* avoid allocating `String`s for `Stack`s

* avoid allocating Strings for `Element`s

* apply some clippy lints

* some more clippy lints

* simplify regex

* remove superflous if condition

* remove the Rc<_> in `Element`

* small cleanups and regex fix

* avoid allocating a vector for the culled pda

* bug fix

* bug fix

* reintroduce the Rc, but make it use the *one* alloced VecDeque this time

* slim down dependencies

* use Box<[&str]> for storted state stacks

this saves us a whopping 8 bytes ;), since we don't have to store
the capacity

* revert the changes from 9ffa715c10089f157e4e20563143a2df890c8ffe

fixes a bug

* apply clippy lint

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-09-05 16:29:24 +02:00
Andrea Fioraldi
4c0e01c4aa
Fix memopidx bug in libafl_qemu r/w hooks and update QEMU (#1500) 2023-09-05 16:28:52 +02:00
Evan
9645dca274
Fixed libafl_atheris Makefile and flag read (#1499) 2023-09-05 01:31:31 +02:00
Dongjia "toka" Zhang
2076fc0722
Fix CI (#1498)
* Update build_and_test.yml

* Update build_and_test.yml

* fmt
2023-09-04 13:00:54 +02:00
ToSeven
a0bcdfa005
implement the AFL-Style Tui (#1432)
* implement an AFL-Style TUI

* improve the tui/mod.rs according to the reviews

* fixing fmt manually

---------

Co-authored-by: toseven <Byone.heng@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-09-03 23:52:48 +02:00
David CARLIER
1b6ef52a4e
bolts core affinity illumos clippy fixes (#1497) 2023-09-02 21:56:22 +02:00
Dominik Maier
f27107c5e4
Fix docs build for libafl_qemu (#1495)
* Fix docs build for libafl_qemu

* turn around

* does this work?

* build all-features in CI

* fixes

* fix ci
2023-09-02 21:56:01 +02:00
David CARLIER
7e5a1dba05
bolts linux arm64 clippy fix build (#1496) 2023-09-02 01:35:05 +02:00
Rowan Hart
256d010981
Add embed-runtime feature (#1489)
* Add library embedding feature to libafl_libfuzzer

* Add comment describing embed-runtime feature and CI test
2023-09-01 01:03:17 +02:00
Dominik Maier
134fe6a992
ForkserverExecutor: stop forked children on exit (#1493)
* wip

* Fix forkserver exit

* undo change in forkserver_simple

* less map_err

---------

Co-authored-by: Marco Vanotti <mvanotti@google.com>
2023-08-31 22:51:21 +02:00
David CARLIER
d0d378c174
bolts write_minibsod solaris version (#1494) 2023-08-31 22:48:43 +02:00
Andrea Fioraldi
00033426e7
Bump to 0.11.1 (#1491) 2023-08-31 15:07:31 +02:00
Andrea Fioraldi
d68c70b0f5
Fix clippy lint in libafl_libfuzzer (#1490)
* Fix clippy lint in libafl_libfuzzer

* fix libafl_libfuzzer_runtime version
2023-08-31 15:03:15 +02:00
Rowan Hart
bca14c041b
Update from unmaintained tui-rs to ratatui (#1488) 2023-08-31 02:02:36 +02:00
David CARLIER
09295ae819
fix frida build for linux arm64 (#1487) 2023-08-31 02:01:32 +02:00
Dominik Maier
81bdbc0dde
Fix TuneableMutationalStage _std function generics (#1486) 2023-08-30 00:57:10 +02:00
Addison Crump
9149d69699
Fixes for serdeany_autoreg (#1479)
* fixes for serdeany_autoreg

* fmt

* yet more docs

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
2023-08-30 00:13:50 +02:00
Dominik Maier
5710c8b28a
Document LIBAFL_DEBUG_OUTPUT in Launcher (#1485)
* Document LIBAFL_DEBUG_OUTPUT in Launcher

* fmt

* more doc

* fork

* unix
2023-08-30 00:00:12 +02:00
Alexander Qi
51e4d814fb
bolts: Fix shmem leak when Drop-ing CommonUnixShMem (#1484) 2023-08-29 18:10:59 +02:00
kiwids
c91fc9a521
Update LibAFL_CC README.md (#1483)
Updated with steps to compile LLVM from source tree
2023-08-29 18:09:28 +02:00
Dominik Maier
61ad4a6ee8
bolts: Make xxh3 hashing optional with xxh3 feature flag (else use ahash for everything) (#1478)
* Make xxh3 hashing optional (and default to ahash)

* make xxh3 default anyway

* move import

* fix no_alloc

* No ahash without alloc

* fix import

* Keep xxh3 as default for libafl as well

* no randomness for xoshiro
2023-08-29 16:22:46 +02:00
Dominik Maier
ab837cbbf5
Fix document_features for libafl_libfuzzer (#1480) 2023-08-29 15:10:50 +02:00
Andrea Fioraldi
638d315b57
Add readmes (#1476)
* Add readmes

* fix docker
2023-08-29 14:51:55 +02:00
lenawanel
f3a4f4f664
Remove unneeded loop in SpliceMutator::mutate (#1471)
previously we searched for the first and the last difference
between exactly the same 2 inputs 3 times in a loop

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-08-29 13:30:29 +02:00
Dominik Maier
7d2c854b71
Introduce document-features feature (#1477) 2023-08-29 12:40:35 +02:00
Andrea Fioraldi
e66eb33e96
Fix libafl_libfuzzer publish (#1475)
* fixup build

* allow dirty

---------

Co-authored-by: Addison Crump <addison.crump@cispa.de>
2023-08-29 11:32:52 +02:00
Andrea Fioraldi
062ae9d544
Fix doc for publish (#1472)
* Fix doc for publish

* add bolts to publish.sh
2023-08-28 17:22:44 +02:00
Andrea Fioraldi
7dd7c1a485
Bump to 0.11.0 (#1469)
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-08-28 15:36:43 +02:00
Dominik Maier
b45985c76b
Less pub in LLMP (#1470)
* Less pub in LLMP

* add mut to docstring

* fix eample
2023-08-28 13:18:58 +02:00
Dominik Maier
1357b9f310
Add Broker.peek_next_client_id (#1468)
* Add Broker::next_client_id

* rename to peek_

* Undo change, probably not better
2023-08-28 09:00:05 +02:00
Dominik Maier
0a0c4639a6
Replace manual binary search with stdlib (#1466) 2023-08-27 23:12:36 +02:00
lenawanel
6a2d6fa66d
fix some docs and use slice::fill instead of manual implementation (#1467)
* update documentation of `MinimizerScheduler`

(convert a few references to types into doc links and update the docs of `on_remove`)

* replace manual implementation of `slice::fill`

the in the code comment linked stackoverflow comment https://stackoverflow.com/a/51732799/1345238/
now mentions `slice::fill`
it seems to compile to the same thing as the old version https://rust.godbolt.org/z/98Y4x97vY

* fix docs for the `*InterestingMutator`s and `*ByteAddMutator`s

the macros didn't previously docs gens didn't previously
 generate fitting docs
2023-08-27 23:11:44 +02:00
David CARLIER
713f0c5913
Update FreeBSD on CI (#1463) 2023-08-27 15:34:46 +02:00
David CARLIER
fc6df5ef47
llmp: switch to binary search (#1465) 2023-08-26 13:52:14 +02:00
Rowan Hart
8d8fcdd8db
Add generic cmp observer metadata, rename cmp observers, fix cmplogmap reset (#1461)
* Make cmp metadata generic, rename ForkserverCmpObservers with more accurate names

* Fix zeroed assignment in cmplogmap

* Dont use prelude in libafl_targets

* Make _mut functions actually return mut references

* Fix fuzzbench forkserver build

* Add type alias for easier construction of the standard cmp observer and add aux data accessors
2023-08-26 09:54:31 +02:00
Dominik Maier
6df415438d
Update frida_gdiplus readme (#1464)
Thanks to Nuja from Awesome Fuzzing Discord
2023-08-25 14:49:57 +02:00
Andrea Fioraldi
760edbf0d2
Fix forward_id stats for the centralized manager (#1454)
* Fix forward_id stats for the centralized manager

* Fix stats bug
2023-08-25 14:23:25 +02:00
Andrea Fioraldi
04c8d5208b
qemu: Fix cpu page size function for full-system (#1452)
* Revert "qemu: add cpu page_size call (#1433)"

This reverts commit d338b30c080ecfe1a6639185b6505b7a7b8edbeb.

* Reintroduce page_size
2023-08-25 11:42:23 +02:00
David CARLIER
4a96354276
bolts: fix netbsd/openbsd clippy (#1459) 2023-08-24 21:41:44 +02:00
David CARLIER
209d38a768
bolts: disable build for rust < 1.70 proposal. (#1460)
mostly due std::cell namespace introduction in the 1.70 version.
as rust versions evolve fast enough, it might be easier than
having conditional dependency on he old once_cell crate.
2023-08-24 21:41:26 +02:00
Addison Crump
9aa40c0734
Document libafl_libfuzzer (#1457)
* prep for publishing libafl_libfuzzer

* learn to use linkers

* document-features

* special handling for fuzzbench builds

* Update cmplog.c

* drop dep for llvm-tools; add testcase for memcmp sanity

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-08-24 20:24:38 +02:00
Dominik Maier
f7c94f9a85
Create _std public methods on TunableMutationalStage (#1458)
* Create _std public methods on TunableMutationalStage

* No tunafish
2023-08-24 16:05:30 +02:00
Dominik Maier
9208531951
Move from intervalltree to meminterval dep (#1456)
* Move from intervalltree to meminterval dep

* fixes
2023-08-24 14:15:24 +02:00
Addison Crump
862de53cf6
Full libfuzzer shimming (for cargo-fuzz libfuzzer alternative and other use cases) (#981)
* squash libfuzzer edits

* fixup: compat with custom mutators

* use tui flag

* add introspection support

* use libfuzzer dep now that we've merged

* force input loading

* some fixes

* begin docs, impl shrink

* make whole-archive conditional and not default

* make more copies of counters maps

* lol, remember to add the observer

* make size edge map observer an observer

* fixup: make def of run driver conditional

* add sanity checks for insertion

* revert silencing of forks

* add experimental tmin support; add default asan flags

* use default options instead of specifying our own

* implement lockless mode

* fix merge

* fixup lockless corpus

* fixup for generalisation

* remove erroneous drop_in_place

* improve error logging in the case of corpus loading failure

* ok, use lock files 😔

* fix tmin

* implement merge (again); fix rare cases with maps being too small

* implement a scheduler for removing excess

* implement a walking strategy for corpus loading for large corpora

* revert filename parameter; rename and remove duplicates

* various cleanup and clippy satisfaction

* fix no_std tests

* clang-format

* expand and satisfy the clippy gods

* fix sanitizer_ifaces bindgen for no_std

* fix wasm fuzzer

* fixup clippy script

* rename and provide a small amount of explanation for sanitizer_interfaces

* fixup: HasLastReportTime

* fix clippy oddities

* restrict clippy checks to linux-only for libafl_libfuzzer_runtime

* name the mutators

* format

* fix clippy warning

* hope docker is fixed

* fix cmin lint

* clippy pass

* more docs

* more clippy

* fix remaining clippy complaints

* fix import

* miri fixes (no constructors executed)

* exclude libafl_libfuzzer from cargo-hack

* fix clippy check for sanitizer_interfaces

* fmt

* fix CI (?)

* deduplicate sancov 8bit for improved perf on ASAN

* merge 8bit coverage regions + comment out insane deduplication

* no erroring out on free hooks

* fixup for non-forking merge

* skip the corpus dir if we use it

* fixup: recent libafl changes and feature flags

* libafl_libfuzzer: use rust-lld for whole-archive feature

* clarify cause of failure

* mark unsafe

* clippy :cursed_cowboy:

* attempt to fix wasm

* spooky unknowable bug 👻

* more clippy lints

* clippy fix for merge

* use the version pin

* add unsafe to ::register

* Serdeany autoreg fix

* make type assert actionable

* miri fixes

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: Mrmaxmeier <Mrmaxmeier@gmail.com>
2023-08-24 13:30:23 +02:00
Dominik Maier
f68fe95f09
Document features (#1453)
* Document features

* Fix doctest

* remove link

* <<<<head

* Fix doc links
2023-08-24 13:27:37 +02:00
Dominik Maier
e89e8dbaab
Remove dependencies, add doc.rs metadata (#1450)
* Remove dependency, add doc.rs metadata

* remove lazy_static

* even less lazy_static

* serial_test no default
2023-08-24 11:34:38 +02:00
lazymio
c84c105fb9
Allow setting max iterations for stages (#1436)
* Allow setting the max iterations

* Rename API

* Fix baby_fuzzer_grimoire

* Relax bound

* Also add a new API for transforming

* Revert back grimoire fix

* Revert bound relax
2023-08-24 09:59:11 +02:00
lazymio
20cee8cd33
Allow multiple tuneable mutational stages (#1437)
* Allow multiple tuneable mutational stages

* Fix for default name

* Fix import

* Format code

* Standalone trait bounds

* Minor fix

* Add _with_name API

* Format code

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-08-24 09:58:23 +02:00
Dominik Maier
2f840ef92d
Windows dependency upgrade (#1448)
* Windows dependency upgrade

* update windows

* fmt

* expect is not fun but what can you do

* fmt, clippy
2023-08-24 08:15:31 +02:00
Dominik Maier
454142c29e
Add bolts::math, make functions const, cleanup (#1444)
* Make some functions const

* fix isprint

* more const

* move integer_sqrt to bolts, use binary search, use u128 to handle extreme values

* Technically correct

* clippy

* u64 algo

* More test

* cumulative_distribution to in_place

* move calculate_cumulative_distribution_in_place to bolts

* clippy

* Move math stuff to bolts::math

* actually add math

* math?

* For some reason this fixes things, dunno

* fix builds?

* does that help?

* clippy ignores

* more clean clippy

* more cfg_attr
2023-08-23 21:12:39 +02:00
David CARLIER
d338b30c08
qemu: add cpu page_size call (#1433)
* qemu handy cpu page size call proposal.

* changes from feedback.
2023-08-23 20:27:58 +02:00
Manish Goregaokar
8f27b14eb8
Use postcard with default-features = false (#1446) 2023-08-23 19:53:25 +02:00
Dominik Maier
65ec23fd35
Update uds, remove unused features (#1447) 2023-08-23 19:52:59 +02:00
David CARLIER
1922cb0a65
qemu snapshot little update proposal. (#1431)
* qemu snapshot little update proposal.

* reeatablishing the TODO since the change does not do it at all
 but getting unrelated constant mask unrelated to mappings protection.

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-08-23 10:13:08 +02:00
Rowan Hart
942c6a42ac
Reset headers with a memcpy, not an assign from zeroed (#1443) 2023-08-23 08:23:52 +02:00
Marco Vanotti
174b852e0a
Fix probabilities in TuneableScheduledMutator (#1440)
This commit fixes some issues regarding the `TuneableScheduledMutator`,
which had an edge case for drawing probabilities.

The user is supposed to provide a vector with probabilities that have to
add up to 1.0, but due to floating-point errors, the number can be
sligthly off.

If the sum ends up being slow, there's a chance that we draw a number
that is bigger than it (for example, 1.0), and that would not be present
in the cumulative distribution vectors (either for iterations or
mutations).

The issue is fixed by setting the last value of the cumulative
distribution to 1.0.

This commits adds some validations in the function that calculates the
cumulative distribution function, making sure that the numbers add up to
1, and that they are all between 0 and 1.

The API is now changed so the functions can now return an error instead
of crashing.

The commit also adds some tests, and fixes the `reset()` function.
2023-08-23 01:37:22 +02:00
David CARLIER
389c7c6554
bolts: fix freebsd clippy warnings (#1442) 2023-08-23 01:32:34 +02:00
Andrea Fioraldi
0b43711dc9
Fix LLMP p2p + restart bug with CentralizedEventManager (#1389)
This commit rewrites the centralized manager to use a secondary broker, as p2p communication is unreliable during frequent restarts. A centralized launcher is introduced too.
2023-08-22 15:57:50 +02:00
Rowan Hart
a14363f1fc
Make CmpValues Clone (#1439) 2023-08-21 22:11:11 +02:00
Dominik Maier
6e5d102673
Clippy fixes for frida_executable_libpng fuzzer (#1438) 2023-08-21 19:41:03 +02:00
Dominik Maier
a426b6fc3d
Clippy for pthread_hook (#1435)
* Clippy

* doctest
2023-08-21 13:35:59 +02:00
Dominik Maier
c31ca2c9f7
Fix Frida CI for Windows, Clippy (#1430)
* Fix Frida for Windows

* more fix

* clippy in pthreads
2023-08-20 13:30:21 +02:00
David CARLIER
c6bfb07832
bolts write_minibsod netbsd implementation. (#1428)
pretty close to freebsd for the most part.
2023-08-20 12:01:04 +02:00
Dominik Maier
1d746b4074
Fixes for frida, qemu_sugar (#1427)
* Fixes for frida, qemu_sugar

* tiny clippy

* clippy

* fix thread_id

* Attempted fix for qemu
2023-08-20 12:00:41 +02:00
lenawanel
173b14258b
fix CI QemuCmpLogHelper error. (#1429)
this was caused by using `cpu_arch = {mips,hexagon}` and `feature = [mips,hexagon]`
for the same reasons
2023-08-20 11:58:50 +02:00
r4ve1
0eceafe0c5
Allow the FridaInProcessExecutor to attach Stalker on specific thread (#1256)
* feat: support specify thread id for frida stalker

* fix: thread_id type

* fix: use official repo for frida-gum

* Merged

* Added back missing bolts

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-08-17 19:47:07 +02:00
Dominik Maier
35fa881ff0
Update frida (#1408)
* Update frida

* fix build

* aarch64

* fix aarch64 buid

* Fix CI

* move to git version of frida

* fix

* Frida frida frida
2023-08-17 17:49:12 +02:00
Dominik Maier
b0179b4498
Update some deps, clippy (#1422)
* More less default

* More clippy

* updated rangemap

* Clean up depencdencies

* Undo accidental remove

* Fix

* trying to fix qemu build

* hexagon be gone
2023-08-17 17:15:03 +02:00
David CARLIER
b5774b2275
write_minibsod for apple (#1425) 2023-08-15 20:16:07 +02:00
lenawanel
5c05b3d32d
Update documentation of feedbacks::map::OneOrFilledIsNovel (#1423)
this previously seemed to describe `NextPow2IsNovel`
2023-08-15 20:14:30 +02:00
David CARLIER
bc42880274
minibsod, fix clippy warning (#1424) 2023-08-14 10:51:01 +02:00
Dominik Maier
0be4847cb7
Add more libafl_qemu archs to libafl_sugar (#1419)
* Add more archs to LibAFL_QEMU

* fixed critical whitespace
2023-08-13 20:38:24 +02:00
David CARLIER
8f16001c47
minibsod::generate_minibsod openbsd implementation (#1420) 2023-08-13 20:36:13 +02:00
David CARLIER
698ebb6b35
libafl_bolts: fix musl build (#1421)
despite being present in the headers, getcontext is not implemented in
musl libc, most likely due to the fact it s a deprecated interface.
The only way around is having the third party libucontext apk package
installed.
2023-08-13 12:14:30 +02:00
Dominik Maier
dcdfa978a4
Fix latest Clippy for good (#1418)
* More Clippy

* More clippy

* More ignore
2023-08-13 12:10:55 +02:00
Dominik Maier
b02592c5c7
Add serdeany_autoreg to libafl_frida (#1417) 2023-08-13 10:07:33 +02:00
Konstantin Bücheler
9650e06b45
Add serdeany_autoreg to libafl_qemu (#1416)
* Add `serdeany_autoreg` to `libafl_qemu`

* Update Cargo.toml

Add autoreg to default

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-08-13 01:25:59 +02:00
Dominik Maier
e0d90aa67f
More Clippy fixes (#1415)
* More Clippy fixes

* Clippy
2023-08-13 01:17:34 +02:00
Dominik Maier
b9879a8bfc
Fix CI (#1414) 2023-08-12 03:24:06 +02:00
mark0
a55d40cd00
Update accounting.rs (#1411)
Remove dead code for better semantic compliance
2023-08-10 17:46:56 +02:00
Dominik Maier
ff2f325d68
Fix building docs (#1413) 2023-08-10 14:51:19 +02:00
Dominik Maier
8ca2df8819
Updated Scheduler::on_add documentation (#1410) 2023-08-10 14:27:21 +02:00
lenawanel
4bee9a9039
Update documentation of PowerQueueScheduler::on_add (#1409)
this fixes https://github.com/AFLplusplus/LibAFL/issues/1373
2023-08-10 14:23:19 +02:00
Dominik Maier
418d0dba91
Remove unused owned (for now) (#1405) 2023-08-07 12:50:43 +02:00
Dominik Maier
b877ed7e0e
Removed unused intrinsics features (#1404) 2023-08-07 10:55:08 +02:00
WorksButNotTested
51e2f64e5b
gdb_qemu: Ignore UTF-8 errors (#1403)
Co-authored-by: Your Name <you@example.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-08-07 10:54:49 +02:00
David CARLIER
3bf3172928
fix bolts build, intrinsics is an internal feature. (#1402) 2023-08-06 23:03:34 +02:00
Dominik Maier
dfaf06a22e
Make bolts work without alloc (#1401)
* Make bolts work without alloc

* Use core::Error where available

* unstable_feature -> nightly

* windows no_alloc
2023-08-05 01:03:40 +02:00
Dominik Maier
a0c03fccc5
Add serdeany_autoreg feature flag to allow disabling ctor use (#1398)
* Add  feature flag to allow disabling  use

* fix typo

* undo cargo.toml change

* Fix no_std

* Backticks

* rename register_at_startup to create_register

* fix

* Move Tui_monitor to default instead of std
2023-08-04 15:36:48 +02:00
David CARLIER
83f739f010
libafl_cc using hwasan on Linux/Android arm64 (#1399) 2023-08-04 01:50:41 +02:00
Dominik Maier
5dd5b1efa8
More fuzzer fixes for Bolts (#1397)
* more fixes

* more docker fix
2023-08-03 11:45:18 +02:00
Dominik Maier
dbba687b9b
Add proper REAME.md to libafl_bolts (#1396)
* Add proper readme to libafl_bolts

* more 0.11 doc
2023-08-03 02:59:30 +02:00
Dominik Maier
f752acc2a4
Info about how to migrate to 0.11 (#1395) 2023-08-03 02:35:37 +02:00
Dominik Maier
febb154e49
Fix merge fail for baby_fuzzer / bolts (#1394)
* Fix merge for bolts

* warning fix

* warning fix
2023-08-03 01:58:09 +02:00
Dominik Maier
e9e9c457d6
Move Bolts to libafl_bolts (#1335)
* sort memebers

* Building bolts

* fixing python, feature flags

* Cleanup bolts Cargo.toml

* Fix tests

* cleanup libafl

* removed duplicate examples

* Info text

* reenable agpl CI

* fix impl_serdeany

* new fmt

* Moved bolts

* fix some builds

* fix

* fix more fixes

* serdeany

* no_std

* Dependency cleanup

* Fix docs

* Docker

* add python bolts bindings

* no_std test fix

* merge fail

* typo fix

* add bolts dependency to fuzzers

* tiny fixes

* merge fun

* clippy

* link no longer exists

* make sure python gets rebuilt

* fix pybind

* doc fix

* remove bolts ref

* LibAFL bolts

* More info

* deprecation notice for launcher

* fix python

* cargo fmt

* fix concolic

* fix

* clippy

* fix libafl_cc

* fix tutorial, clippy

* fix concolic fuzzer

* fix push_stage_harness fuzzer

* prelude

* fix testcase post-merge

* mute clippy
2023-08-02 17:36:26 +02:00
Dominik Maier
d69cde896c
Less unsafe type_eq in stable (#1392)
* less unsafe type_eq

* add type_eq test

* More type eq test

* extend test by a lot

* go mad with tests

* fmt

* simpler tests

* clippy
2023-08-02 13:58:05 +02:00
David CARLIER
f4f55088e3
ControlFlowGraph::calculate_difference_all_edges build warning fix. (#1390)
get_edge returns a reference, anyhow CfgEdge does implement the Borrow's trait neither.
2023-08-02 09:58:49 +02:00
Dominik Maier
fc809ccb33
Remove FeedbackState reference from the book (#1391)
* Remove FeedbackState reference from the book

* Update feedback.md
2023-08-01 23:27:51 +02:00
Dominik Maier
006dcac00c
Named Mutators and MultiMutator API change (#1387)
* Mutators need names (alternative to #1379)

* Signature of MultiMutator shouldn't be the same as the normal mutator

* Named for python, remove mutator for multi_mutator

* fmt

* clippy edition warning

* clippy

* mac_count doc fix, return cleanup
2023-08-01 16:58:40 +02:00
Dominik Maier
90e9f3c786
Move apt-get before checkout (#1388) 2023-08-01 14:42:35 +02:00
Andrea Fioraldi
ac4a0e7330
libafl_qemu snapshot device filter (#1386)
* libafl_qemu snapshot device filter

* Working device list

* regenerate bindings stub
2023-08-01 12:01:10 +02:00
Mrmaxmeier
fc9caa8314
Fix UB in frida fuzzers (#1385)
* WIP: fix ub issue in frida fuzzers

* refactor frida helper: remove unused fields

* revert frida-gum bump. Current frida-gum doesn't build on iOS :/

* libafl_frida: silence must_use_candidate lint

this lint is very noisy, and adding #[must_use] to _all_
(even pure )functions seems very excessive to me

* fix clippy
2023-07-29 13:44:54 +02:00
Andrea Fioraldi
37bfead4e5
Fix generic hooks bug in libafl_qemu (#1382) 2023-07-27 17:28:33 +02:00
David CARLIER
eae6f0436f
fix riscv(32) tick reading for clang (#1381)
albeit it passes with gcc it does not with clang.
2023-07-26 13:58:35 +02:00
Andrea Fioraldi
cb24b5dc2d
Extract linker args when building QEMU (#1377)
* Update qemu commit

* Hook the linker and automatically extract linker args

* Comment code
2023-07-26 10:42:15 +02:00
Abc Xyz
993eb62bb8
fix(libafl): update Z3 dependency (#1372)
See https://github.com/Z3Prover/z3/issues/5586. libafl with `cmin` feature cannot be built for Android.
2023-07-24 15:12:16 +02:00
Addison Crump
81e9a9a60f
Fix build/clippy errors and update CASR (#1375)
* fix new exciting clippy errors

* fix CASR build errors

* bump casr version

* more clippy whack-a-mole

* allow needless pass by ref mut as it is improperly marked unnecessary
2023-07-24 15:11:24 +02:00
David CARLIER
b064eb3994
read_time_counter port for the RISCV family. (#1378) 2023-07-24 13:14:07 +02:00
David CARLIER
f0563475c3
noaslr: add netbsd support (#1371) 2023-07-16 17:09:44 +02:00
Dominik Maier
36b1d8aea2
Fix status updates for crashing fuzzers (fixes #1367) (#1368)
* Fix status updates for crashing fuzzers (fixes #1367)

* client perf fix

* Add HasLastReportTime trait :/

* ****** prelude

* reoder phantom

* fix tests

* clippy, fixes

* more fixes, traits are maaad

* fmt
2023-07-14 18:50:31 +02:00
Dominik Maier
003b219826
Make all no_mangle fns extern "C" (#1369) 2023-07-14 17:42:58 +02:00
David CARLIER
eb362c5c77
libnoaslr support for netbsd (#1366) 2023-07-14 14:59:24 +02:00
s1341
11fc57a5d7
Launcher: Allow setting a distinct stderr redirect (#1329)
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-07-13 22:50:01 +02:00
Addison Crump
f76331eac7
Add RefCellValueObserver (#1363)
* add RefCellValueObserver

* appease the clippy gods

* Update libafl/src/observers/value.rs

Co-authored-by: Langston Barrett <langston.barrett@gmail.com>

---------

Co-authored-by: Langston Barrett <langston.barrett@gmail.com>
2023-07-13 18:02:02 +02:00
David CARLIER
a95b322b1c
noaslr disable aslr for dragonflybsd. (#1364) 2023-07-13 14:11:09 +02:00
David CARLIER
1609960244
libnoaslr: add FreeBSD support (#1361) 2023-07-12 13:55:18 +02:00
epi
72e54ac2f4
Update ForkserverBytesCoverageSugar to use parse_afl_cmdline, latest features (#1343)
* update forkserversugar to use parse_afl_cmdline

* added tokens/persistent/deferred to forkserver sugar

* removed deferred option

* added build_dynamic_map call; removed generic const

* clippy

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-07-12 12:16:46 +02:00
Andrea Fioraldi
3e0e753e9f
Update typed_builder to fix no_std (#1360) 2023-07-11 11:31:37 +02:00
WorksButNotTested
2002bbca35
Arch independent helpers in libafl_qemu (#1355)
* Add more features to libafl_qemu to remove some of the heavy lifting from the fuzzers

* Refactor qemu_coverage

* Minor tweaks to fix other fuzzers

* Autofix

* Add CallingConvention to write_function_argument

* Replay reverted clippy fixes

---------

Co-authored-by: Your Name <you@example.com>
2023-07-11 10:56:40 +02:00
Dongjia "toka" Zhang
109755208e
Revert "Make harness function take mut ref (#1338)" (#1358)
This reverts commit fe6daecf0bb178cd19970ae81c797443fd8cd88f.
2023-07-10 17:33:26 +02:00
Dongjia "toka" Zhang
1ad1b7cb17
revert typed builder version (#1357) 2023-07-10 14:16:24 +02:00
Andrea Fioraldi
65368408dd
Algorithm to choose to serialize the observers or not (#1227)
the algorithm is balancing between observers serialization and re-execution
2023-07-10 13:42:53 +02:00
Langston Barrett
cbf0952ec7
libafl{,_qemu}: Bump num_enum to 0.6 for syn 2 support (#1350)
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-07-10 13:13:53 +02:00
Langston Barrett
2885b10f70
libafl_qemu_build: Bump bindgen to 0.66 for syn 2 support (#1349) 2023-07-10 13:12:26 +02:00
Langston Barrett
33aa012bdd
libafl_qemu: Bump strum to 0.25 for syn 2 support (#1348) 2023-07-10 13:12:16 +02:00
Langston Barrett
3f8c5f585b
libafl{,_concolic}: Bump ctor to 0.2 for syn 2 support (#1347) 2023-07-10 13:12:08 +02:00
Langston Barrett
2712430f93
libafl{,_sugar}: Use typed-builder 0.15 for syn 2 support (#1346) 2023-07-10 13:11:52 +02:00
Rowan Hart
fe6daecf0b
Make harness function take mut ref (#1338)
* Change executor trait to allow \&mut Input

* Add mut inprocess executor

* Add mut inprocess executor

* Format and fix clippy errors

* Fix more clippy errors

* Revert accidental refactoring of InMemoryCorpus

* Add mut versions of all executors that can support it

* Do not persist possible testcase mutation in stages, shadow/differential executors, or corpus minimization

* Fix missing imports

* Fix executor type for missed qemu items

* Add re-exports for mut executors

* Use InProcessForkExecutorMut in QemuForkExecutorMut

* Update BytesInput harnesses to take mutable references

* Update other-input-type-taking harnesses to take mut references

* Clippy fixes

* Feature gate TryFromIntError import

* Fix missed harness input type in baby_fuzzer

* Fix additional clippy issues

* Fix unnecessary hashes on string literal

* Even MORE clippy fixes

* Fix one more clippy issue

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-07-10 13:06:38 +02:00
Dongjia "toka" Zhang
52ab8c02d6
Fix CI (#1354)
* Update build_and_test.yml

* Update build_and_test.yml
2023-07-07 17:24:03 +02:00
Dongjia "toka" Zhang
44bbaf7d22
Update build_and_test.yml (#1353) 2023-07-07 16:22:27 +02:00
Dongjia "toka" Zhang
8cca87f2bd
Fix #1342 (#1345)
* push

* fmt
2023-07-05 13:03:09 +02:00
Dominik Maier
e5b3e5a677
Fixed Forkserver shmem input length, made it configurable (#1342)
* Fixed Forkserver shmem input length, made it configurable

* fix redqueen clippy

* Clippy

* Clippy

* WHY ARE THERE TWO TIMES THE SAME FN

* More clippy
2023-07-04 14:57:09 +01:00
Ivan Fratric
829b5049e6
Hexagon support (#1323)
* Hexagon support

* Fix format

* Fix needless bool

* Address comments

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-07-04 11:08:36 +02:00
Dongjia "toka" Zhang
07f4c42ecf
AFL++ redqueen update (#1291)
* up

* dbg

* fix

* fmt

* fix

* refactor

* more

* clp

* upd

* fmt

* fmt

* last

* debugging

* wip

* lastlast

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-07-03 19:27:34 +02:00
David CARLIER
4897c3f205
util/noaslr porting to FreeBSD (the non-lib part). (#1337)
to port to the library, might need a nice layer over the FreeBSD's C api (nix?)
before hand.
2023-07-03 00:51:32 +01:00
Dominik Maier
c0e1236a07
Formatting fuzzers with new fmt (#1340) 2023-07-02 18:19:48 +01:00
Dominik Maier
6f4955619a
Latest fmt (#1339) 2023-07-02 18:13:46 +01:00
WorksButNotTested
07047cb3bb
Added noaslr (#1333) 2023-06-30 20:37:48 +02:00
WorksButNotTested
97b3d3c7c7
Add gdb_qemu utility (#1331) 2023-06-30 20:36:46 +02:00
WorksButNotTested
c6062889d5
Extend qemu_launcher to support multiple architectures (#1328)
* Change qemu_launcher fuzzer to support multiple architectures and remove qemu_arm_launcher

* Review changes

* Changes to milliseconds

---------

Co-authored-by: Your Name <you@example.com>
2023-06-30 02:18:00 +02:00
s1341
871dfa0a01
Insert into corpus if feedback is_interesting on crash/timeout (#1327)
* Insert into corpus if feedback is_interesting on crash/timeout

* Use correct import for HasExecutions

* Windows add missing import

* QemuExecutor add HasFeedback

* Windows asan fix

* Add missing call to scheduler.on_add

* Add missing HasExecutions for windows frida

* QemuExecutor missing HasScheduler

* QemuExecutor missing HasCorput
2023-06-28 23:53:51 +02:00
s1341
71aa0221a0
Add feature to build variants/configurations automatically, with libtool/cc/cxx shims (#1322)
* Add feature to build variants/configurations automatically, with libtool/cc/cxx shims

* Fixes

* Clippy

* Add brief comment describing usage

* Fix

* Fix fuzzers: add ToolWrapper

* Clippy

* More clippy

* More clippy

* Add Compound configuration

* Clippy

* Fix

* Clippy

* Damn that Clippy

* Change names of Configurations

* Add ar wrapper

* Fix

* Clippy

* Windows build

* Clippy

* Clippy

* Clippy
2023-06-22 16:17:33 +02:00
Andrew-Fryer
07530fea57
Trigger feedback side effects during force-loading (#1317)
* this triggers feedback side effects during force-loading

* oops; correct typo in introspection branch

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-06-17 02:06:07 +02:00
Dongjia "toka" Zhang
dad8217c38
Update build_and_test.yml (#1318) 2023-06-16 01:26:40 +02:00
WilliamParks
dec202e6d6
Fixes math with register offsets (#1314) 2023-06-15 21:53:22 +02:00
s1341
c66c3ff2b8
Attempt to fix ci (#1315)
* Attempt to fix ci

* fix

* fix

* rm all the stuff
2023-06-15 21:53:06 +02:00
Dominik Maier
f858e1a247
Add TcpEventManager (#1302)
* Tcp manager, initial commit

* no tokio by default

* Allow Any broker type

* Add tcp_manager example

* fix CI
2023-06-10 06:25:25 +02:00
s1341
751d96f45a
libafl_cc: Add override env vars to configure LLVM (#1310)
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-06-09 16:55:31 +02:00
Dominik Maier
62b1bde7a9
Fix AnyMap for TypeIds with 128 bit (#1311)
* Fix AnyMap for TypeIds with 128 bit

* make const

* added test, removed static_assertions
2023-06-09 14:06:42 +02:00
Daniel Blackwell
fa63493cee
Fix for issue with CommandExecutor when using InputLocation::StdIn (issue #1306) (#1308)
Co-authored-by: dan <dan@localhost.localdomain>
2023-06-08 16:25:20 +02:00
Dimitri Kokkonis
7d67fc77b5
Give baby fuzzer listings unique package names (#1307)
As discussed in [#1305], it is problematic for the listings to have the
same package name, as they cause warnings to be emitted.
2023-06-08 15:23:39 +02:00
Addison Crump
60c1990f4a
Make it possible to escape from simple event restarter (#1303) 2023-06-06 23:43:41 +02:00
WorksButNotTested
747a636f4f
Add sample fuzzer which collects DrCov coverage for various architect… (#1300)
* Add sample fuzzer which collects DrCov coverage for various architectures using QEMU instrumentation

* Fix clippy

* Rename NullCorpus to NopCorpus

* Added support for verbose output

* Attempt to fix clippy again

* Fix remaining defaults to use x86_64 when no arch specified and be more robust handling partial builds

* Make build even more robust against partial re-builds

* Added missing dependencies to workflow, updated README

* Add missing dependencies for i386

* Another dependency

* More dependencies

* Disable tests on OSX

* Add tmate

* Add missing dependencies and symlink header directory

* Tidy up after test so we don't hog all the disk space

---------

Co-authored-by: Your Name <you@example.com>
2023-06-06 11:50:38 +02:00
Dongjia "toka" Zhang
fa1e3fd504
CI (#1301)
* ci

* fi

* Revert "fi"

This reverts commit ed298d71057607f019e64d58687273a01d30e260.

* Revert "ci"

This reverts commit 6b65936990143a6069abd56dcbe633ac37be2ede.

* fi
2023-06-05 16:29:51 +02:00
Andrea Fioraldi
356698c24b
Update to QEMU 8 (#1299)
* Update to QEMU 8

* fix

* fix snapshots

* fix pcrel
2023-06-02 18:24:07 +02:00
Dongjia "toka" Zhang
8445ae54b3
Allow multiple source file in libafl_cc (#1296)
* add

* clp

* fi

* fmt
2023-05-26 11:35:04 +02:00
WorksButNotTested
0336eae908
Tidy libaf_qemu hooks (#1293)
* Simplify hooks

* More simplification

* Appease the clippy gods

---------

Co-authored-by: Your Name <you@example.com>
2023-05-25 00:24:28 +02:00
Dongjia "toka" Zhang
594ce420fc
Fix libafl_cc (#1295)
* push

* fix
2023-05-24 18:44:13 +02:00
WorksButNotTested
53dd6c6be6
Post gen (#1282)
* Add post_gen

* Adopt post_gen hooks in DrCovHelper

* Bump qemu-libafl-bridge revision

---------

Co-authored-by: Your Name <you@example.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-05-24 16:03:59 +02:00
Andrea Fioraldi
258780370f
Update publish.sh (#1294) 2023-05-24 14:16:09 +02:00
Dimitri Kokkonis
89876f2d89
Use listings for baby_fuzzer book chapter (#1289)
* Clarify setup steps for the baby fuzzer

Specifically:
- Explicitly mention that the dependency path must point to a specific
  directory in the cloned repo (and not the root directory)
- Explicitly mention how to manually trigger the panic in the harness
  for testing purposes

* Clean up documentation on the baby fuzzer

Since the baby fuzzer chapter of the documentation is done in a
"tutorial", step-by-step fashion, it would be nice to be able to see
where exactly new lines have to be placed in the existing code. To that
end, the code used in the tutorial is moved to snippets (as is done in
the Rust Book), as it allows for much more convenient maintenance of the
snippets, as well as easy hiding of the non-important code on any given
snippet.

Furthermore, a few minor fixes are applied; a typo on a comment and a
missing unsafe block.

* Fix code snippet attributes for baby fuzzer

Specifically:
- Remove unnecessary `compile_fail` attribute
- Add `ignore` attribute to the snippets of the complete baby fuzzer. As
  explained in [#1290], it is expected for the baby fuzzer to return a
  non-0 exit code, so this should not trigger a failure during `mdbook
  test`.

* Fix CLI snippet language

For CLI snippets, the "language" should be set to `console`.

* Remove nested safe block in baby_fuzzer listings
2023-05-24 12:18:26 +02:00
Rowan Hart
5a6d683fed
Add an observer for COUNTERS_MAPS for 8-bit SanCov (#1283)
* Add sancov multimap observer to sancov_8bit target

* Undo autofmt of Cargo.toml

* Fix formatting

* Fix import errors under no-default-features, add Safety to counters_maps_observer

* Make observer function no_mangle to allow it to easily be used in a staticlib crate

* Make clippy happy by using export_name instead of no_mangle

* Add observers feature flag and hide counters maps observer behind it

* Fix formatting
2023-05-23 23:31:07 +02:00
Dongjia "toka" Zhang
aa6d331110
Fix CI (#1292) 2023-05-23 18:07:54 +02:00
David CARLIER
dc82a53bec
minibsod dragonflybsd's portage (#1287) 2023-05-22 13:13:07 +02:00
Dongjia "toka" Zhang
2be9686a80
Fix clippy (#1288) 2023-05-22 13:12:43 +02:00
David CARLIER
b9b70b0d51
minibsod: generate_minibsod further memory maps data for freebsd. (#1285) 2023-05-22 12:43:31 +02:00
David CARLIER
0d7d52decf
afl_cc fix build for LLVM 17 (#1286) 2023-05-22 12:42:56 +02:00
Dongjia "toka" Zhang
6f21cb3848
Bump to 0.10.1 (#1280)
* bmp

* remove DEBUG env var
2023-05-22 12:42:36 +02:00
Dongjia "toka" Zhang
cba9df9a28
Delete gitmodules (#1278)
* fix

* rm
2023-05-18 13:07:10 +02:00
WorksButNotTested
4029069640
Disable capstone when building qemu-afl-bridge for user-mode fuzzing (#1281)
Co-authored-by: Your Name <you@example.com>
2023-05-18 00:47:59 +02:00
Dongjia "toka" Zhang
52557aefdd
Fix #1276 2023-05-17 15:39:21 +02:00
Dongjia "toka" Zhang
3fd5671909
add (#1276) 2023-05-17 15:22:49 +02:00
Dongjia "toka" Zhang
66127d8492
Revert "Don't pass LLVM pass & its args during linking (#1274)" (#1275)
This reverts commit efc5756e3fac9ed3b82e6d82b770b578b47b42d0.
2023-05-17 14:53:17 +02:00
Dongjia "toka" Zhang
efc5756e3f
Don't pass LLVM pass & its args during linking (#1274) 2023-05-17 14:32:56 +02:00
Dongjia "toka" Zhang
b7c1591b00
Linking arguments for LLVM passes (#1273) 2023-05-17 13:53:02 +02:00
Dominik Maier
20f8cb10eb
Revert "Automatically add the comment about executions when a new PR triggers (#1270)" (#1271)
This reverts commit d2e4b9f206307db0898caac707c0d2687079bfb1.
2023-05-17 02:48:15 +02:00
ToSeven
d2e4b9f206
Automatically add the comment about executions when a new PR triggers (#1270)
Co-authored-by: toseven <Byone.heng@gmail.com>
2023-05-17 00:30:15 +02:00
Arpan Kapoor
6d2284d8b9
Allow configuring timeout for CommandExecutor (#1269)
* Allow configuring timeout for CommandExecutor

* import Duration on windows as well

* fix example fuzzers
2023-05-15 12:59:06 +02:00
Addison Crump
1da621456f
Add check for if mutation succeeded, else skip processing (#1265) 2023-05-14 12:03:25 +02:00
ToSeven
659e91fb68
Fix performance regression detection in CI #1248 (#1259)
Co-authored-by: toseven <Byone.heng@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-05-14 12:02:32 +02:00
Dongjia "toka" Zhang
b9a540561b
Don't add llvm pass args when there're no passes & Don't pass -mllvm arguments when compiling asm files (#1266)
* f

* fix

* clp
2023-05-12 11:48:12 +02:00
intrigus-lgtm
91b10f8c40
LibAFL_qemu: Disable Capstone to fix build issues on some distributions (#1263) 2023-05-11 09:52:57 +02:00
Kevin Phoenix
6883c776ef
Update pyo3 crate to 0.18.3 (#1255)
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-05-10 20:01:51 +02:00
Lei Zhu
a2719cf559
Add suggestion for arg & args (#1257)
* Add suggestion for arg & args

* Make fmt happy

* Explain @@

* Spotlight afl-fuzz

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-05-10 13:53:40 +02:00
Dominik Maier
0c7d42d28b
Clippy Debug fixes (#1261) 2023-05-09 17:05:51 +02:00
Dongjia "toka" Zhang
52d557aa8f
Ecofuzz Fix 2 (#1262)
* finally works

* f
2023-05-09 16:45:20 +02:00
Kevin Phoenix
be1d3da159
Add pyproject.toml to python bindings (#1239)
* Add pyproject.toml to python bindings

* Improve pyproject.toml

* Update CI pipeline to use pip to install python bindings
2023-05-09 13:23:28 +02:00
Dominik Maier
8bd18ef007
Fix latest clippy (#1258)
* Fix latest clippy

* oops needs alloc
2023-05-09 13:17:57 +02:00
Dongjia "toka" Zhang
fe8c06dd8f
Eco fuzz fix (#1253)
* f

* more fix

* aaaaa

* f

* fix

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-05-09 12:56:23 +02:00
Dongjia "toka" Zhang
721c02cd2c
Revert "Add a CI task that checks performance regression (#1248)" (#1254)
This reverts commit 6929c89b861faa4f382a51ab07e3ee1eb727df8c.
2023-05-04 20:03:06 +02:00
Addison Crump
a8e64be169
Alternative scheduled count strategy (#1252)
* early return generalization stage

* scheduled count

* aaa

* compile

* fix

* implement alternative scheduled count strategy

---------

Co-authored-by: toka <tokazerkje@outlook.com>
2023-05-04 13:15:28 +02:00
Tomas Duchac
53659f8a5c
Add file extension for clang in libafl_cc/build.rs (#1237)
* Add CLANG and CLANG_PP env vars

Add CLANG and CLANG_PP env variables for Windows. Resolves issue if clang and llvm-config are not in the same location.

* Just add clang".exe" for windows

User should have llvm-config and clang.exe clang++.exe in the same directory anyways.

* Ran cargo fmt
2023-05-04 11:52:51 +02:00
ToSeven
6929c89b86
Add a CI task that checks performance regression (#1248)
Co-authored-by: hengzh <byone.heng@gmail.com>
2023-05-04 11:51:42 +02:00
Arpan Kapoor
c8c5d89f33
Ignore 'Broken Pipe' if child process does not read all of stdin (#1244)
* Ignore 'Broken Pipe' if child process does not read all of stdin

* follow clippy suggestion
2023-05-03 15:45:27 +02:00
Dongjia "toka" Zhang
abd8efabd3
Add additional security sensitive functions for coverage accounting (#1246) 2023-05-03 15:45:07 +02:00
Dominik Maier
f9c74ed5d6
Update llvm for FreeBSD CI (#1243) 2023-05-03 11:45:49 +02:00
Dongjia "toka" Zhang
cf79d13d17
Change DumpToDiskStage's callback (#1242) 2023-05-03 11:16:53 +02:00
Dongjia "toka" Zhang
5b02fb420d
Fix CI (#1241) 2023-05-02 17:38:56 +02:00
Dongjia "toka" Zhang
c8fad7833d
Use InMemoryOnDiskCorpus in fuzzbench fuzzer (#1240)
* in memory

* f

* aaa

* nn
2023-05-02 15:18:17 +02:00
Michael Rodler
95d1069393
Use sancov_8bit.rs for OwnedMutSlice (#1235)
Co-authored-by: Michael Rodler <mrodler@amazon.de>
2023-05-02 14:41:33 +02:00
Dongjia "toka" Zhang
b2f9e23975
Fix double crash for solutions with the same filename (#1232) (#1236)
* fix

* mre

* why delete it???

* fmt

* clp

* comment
2023-04-29 23:42:51 +02:00
van Hauser
8ff8ae41f1
switch fuzzbench to FAST schedule (#1233) 2023-04-27 11:11:53 +02:00
Dongjia "toka" Zhang
dde7bc9b5c
Dump Call Graph (#1230)
* call graph

* nl

* typo
2023-04-26 20:22:57 +02:00
ToSeven
f248a061ef
add the version information of fuzzers in the UI (#1224)
Co-authored-by: toseven <Byone.heng@gmail.com>
2023-04-26 16:52:21 +02:00
Dongjia "toka" Zhang
037b9551ea
Fix #1228 (#1229) 2023-04-26 12:00:36 +02:00
Dongjia "toka" Zhang
eab7c32e9f
Dump whole program's CFG pass (#1226)
* skelton

* pass

* compiles

* python

* optional pass

* rev

* chg
2023-04-24 14:57:24 +02:00
Andrea Fioraldi
8ade809588
Centralized Testcase evaluation EventManager (#1216)
* template

* moar

* merge

* compiles

* fuzzer

* forward event newtestcase

* clippy
2023-04-24 11:38:55 +02:00
Dongjia "toka" Zhang
39c0a2040b
Fix CI (#1225) 2023-04-20 19:04:31 +02:00
Dongjia "toka" Zhang
e2f4e83890
Fix CommandExecutor type params (#1222) 2023-04-20 16:34:41 +02:00
Dongjia "toka" Zhang
fc23782dc3
Fix is_valid on Windows (#1217)
* git add -u

* fix cfg

* pub

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-04-18 12:15:47 +02:00
Dominik Maier
96e24d1c8b
Move Input loading and dumping APIs from Testcase to Corpus (#1201)
* Less allocatiosn for filenames

* clippy for wasm fuzzer

* Reworked filename and rename APIs

* python, clippy

* fmt

* More cleanup, fixed metadata location

* clippy

* fix fuzzbench_text / cached len, invert parameters (state first)

* clippy

* oops

* Caching for paths

* simplified, fixed

* no_std

* cached_len

* Nider API for input getting
2023-04-18 12:14:49 +02:00
Andrea Fioraldi
fd68c8a81f
Batch mode timeouts (Linux only ATM) (#1193)
* batch mode timeouts for linux

* batch_mode is linux only atm

* fix

* fix

* fix

* imports

* winfix

* more fix

* winfix

* fix

* fix

* fix

* fix

* clippy

* fix macos

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-04-17 18:16:44 +02:00
Andrea Fioraldi
fafa27a7e9
serial_test as normal optional dep enabled with std (#1215)
* sertial_test as a std and test only dependency

* serial_test as normal optional dep enabled with std
2023-04-17 18:16:29 +02:00
Dominik Maier
c881dc996d
Example fuzzers with less UB (#1212)
* Example fuzzers with even less UB

* more less ub, fixes

* unused dep
2023-04-16 14:29:41 +02:00
Dominik Maier
cdd3d8ace0
Tuneable stage with per-seed timeout (#1209)
* Tunable mutations with timeouts

* fix

* fmt

* Introspection fix
2023-04-13 15:30:47 +02:00
Langston Barrett
863a6b8b7c
Mark buffer_{self_,}copy as unsafe, don't export them (#1207) 2023-04-12 17:42:16 +02:00
Langston Barrett
1b9ffcec74
LibAFL: LLMP manager docstring cleanup (#1208) 2023-04-12 17:40:16 +02:00
Langston Barrett
aa3f126100
LibAFL_qemu: Return errors from Emulator::new instead of asserting (#1197)
* qemu: Return errors from Emulator::new instead of asserting

Libraries should not `assert!` except in cases of unrecoverable (library)
programmer error. These errors are all potentially recoverable, and aren't
internal errors in `libafl_qemu` itself.

* Respond to review comments
2023-04-09 21:27:27 +02:00
Elsa Granger
21ee8d2cae
Fix on_remove of MinimizerScheduler (#1161)
* Fix cursor not step

* Update ref_cnt after remove

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-04-08 16:58:25 +02:00
Vincent
b519d24981
Fix Testcase renaming on disk (#1191)
* fix set_filename

* use ? quantifier instead of expect

* fix clippy

* cargo fmt

* add rename old file to new file logic

* add cfg feature std

* add no_std set_filename

* fix create and remove lockfile logic

* fix cargo fmt

* remove unused import

* cargo fmt

* fix clippy

* fix lock filecondition

* remove useless import

* fix path

* revert fuzzer Makefile.toml

* fix fmt

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-04-07 02:36:08 +02:00
Dominik Maier
f73e2006fc
Removed more new_ (#1200) 2023-04-07 02:34:28 +02:00
Andrea Fioraldi
0f633962ff
Bump to 0.10.0 (#1156)
* Bump to 0.10.0

* fix

* Fix CI

* Fix copyright

* fmt

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-04-05 17:49:53 +02:00
Felipe Baltor
6523341c4d
fix: output directory name; monitor output with println! (#1192) 2023-04-05 11:00:21 +02:00
Dominik Maier
0d446bab20
Updated dependencies (#1174)
* Updated deps

* win

* Revert "win"

This reverts commit a6dfd95f1c63a9471659481d92c5cbc480af6360.

* revert win

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-04-04 22:58:00 +02:00
Andrey Fedotov
807a534121
Use observers to handle crashes in run_target for TimeoutForkserverExecutor (#1189)
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-04-04 19:17:48 +02:00
Andrey Fedotov
1bd21509af
CASR deduplication for StacktraceObservers (#1184)
* Implement CasrAsanBacktraceObserver for dedupe crashes using libCASR and ASAN reports.

* Use casr observer with forkserver executor

* Add casr deduplication for AsanBacktraceObserver

* Add casr deduplication for BacktraceObserver

* Add Stacktrace filtering

* Move init_ignored_frames to constructors

* Add go ignore regexps for BacktraceObservers

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-04-04 19:03:11 +02:00
Dongjia "toka" Zhang
ccd1211cd2
Remove qemu_arm_launcher test from CI (#1179)
* remove qemu arm

* trigger all

* debug

* revert

* api chg

* fix

* try

* debug

* remove qemu

* no_std

* Update build_and_test.yml

* llvm16

* revert z3

* macos

* fix

* remove test

* don't grep on mac

* fix

* ok

* f

* f

* f

* aaa
2023-04-04 14:49:58 +02:00
LiuZhihong
590d3655cd
add readme documentation description about the tui feature (#1198) 2023-04-04 10:34:22 +02:00
ToSeven
ea512f70f8
Fix a build error in baby_fuzzer_minimizing (#1195)
Co-authored-by: toseven <Byone.heng@gmail.com>
2023-04-03 13:38:11 +02:00
Andrea Fioraldi
a01863696e
Implement restarting without serializing the corpus (#1182)
* Restart without serializing state option

* libfuzzer libpng example

* clippy

* libfuzzer_libpng_norestart

* fix
2023-03-30 14:35:58 +02:00
Dongjia "toka" Zhang
702f163c13
Fix #1181 2023-03-26 17:37:44 +09:00
Dongjia "toka" Zhang
0c9933c3e4
Remove libfuzzer_stb_image_sugar for now (#1177)
* a

* better check

* slow
2023-03-24 02:41:15 +09:00
Dongjia "toka" Zhang
ae2caff990
Revert "Fix testcase set_filename (#1092)" (#1175)
This reverts commit a659dd821c484c4e0524d0a2bf88023dae5e259b.
2023-03-24 01:53:42 +09:00
Dominik Maier
620b2861e3
Fix libafl_qemu testcase (#1173)
* Fix libafl_qemu testcase

* stb?

* Undo change for stb
2023-03-23 15:15:54 +01:00
Dominik Maier
66b2867ba2
Fix example fuzzers (#1171)
* Fix example fuzzers

* fmt
2023-03-23 11:02:18 +01:00
Vincent
a659dd821c
Fix testcase set_filename (#1092)
* fix set_filename

* use ? quantifier instead of expect

* fix clippy

* cargo fmt

* add rename old file to new file logic

* add cfg feature std

* add no_std set_filename

* fix create and remove lockfile logic

* fix cargo fmt

* remove unused import

* cargo fmt

* fix clippy

* fix lock filecondition

* remove useless import

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-03-23 00:21:07 +01:00
David CARLIER
c9ea6ee6aa
core_affinity: freebsd constants are included in libc now. (#1170) 2023-03-23 00:11:02 +01:00
Dominik Maier
76e4f6031d
Fmt, no_std fixes (#1167)
* Fmt, no_std fixes

* push-stage fix
2023-03-23 00:10:01 +01:00
Aritra Mallick
02c6cab744
Link to mdbook book, not github (fixes #1137) (#1168) 2023-03-23 00:08:31 +01:00
Arpan Kapoor
d98384e582
Fix SimplePrintingMonitor (#1164) 2023-03-22 15:39:07 +01:00
Dominik Maier
3f7d35bfdc
Install libz3-dev in CI (#1163)
* install z3 in CI

* Update logics.rs

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-03-22 15:38:33 +01:00
v1ce0ye
7c514c3669
ix UB in baby_fuzzer_grimoire (#1166) 2023-03-22 15:37:57 +01:00
Vincent
38ea17b426
libafl_frida for Linux executables (#1117)
* add frida_executable_libpng

* fix makefile

* fix README.md

* remove author from Cargo.toml

* fix fuzzer

* fix fuzzer

* fix Makefile

* fix linter

* fix clang-format-13

* unsupport mac os

* fix build_and_test_fuzzers

* fix cargo fmt

* cargo fmt

* add safer libc_start_main

* fix call rax addr

* fix frida

* fix cargo fmt

* fix metadata() to metadata_map()

* fix toml

* fix maxmapfeedback
2023-03-22 15:18:21 +01:00
Alexander Zhang
c9a78f154b
Remove duplicate lines in attributes (#1165) 2023-03-22 19:08:32 +09:00
Dominik Maier
8f8e74d670
Don't build z3 from source by default (and add static_z3 feature) (#1160)
* Reduce build times by using preinstaled z3

* fix env order

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-03-20 10:04:27 +01:00
Dominik Maier
f4f23de32b
Fix fuzzers after HasTestcase (#1123) (#1162)
* Fix fuzzers after HasTestcase (#1123)

* Make the trait a trait

* Implement HasTestcase for Corpora

* fix

* fix

* a

* a

* fix

* wasm32

* a

* f

* f

* aa

---------

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2023-03-19 11:58:32 +09:00
Dominik Maier
bbe4e85768
Removed new_ from constructors that don't need it (API consistency) (#1159)
* Removed new_ from constructors that don't need it (API consistency)

* un-change python bindings
2023-03-17 17:02:21 +01:00
Matheus Baptistella
104c170ade
Use the new metadata() function in more places (#1155) 2023-03-17 16:03:57 +01:00
David CARLIER
fd95560512
Check for the presence of clang frontends. (#1158)
* checks the presence of clang frontends.

close GH-1149.

* fix clippy complaints
2023-03-17 16:00:54 +01:00
Dongjia "toka" Zhang
d6ee2dbe12
IfStage (#1157)
* macro

* bracket

* IfStage

* remove macro

* revert
2023-03-17 23:25:01 +09:00
Dongjia "toka" Zhang
8245c7eda9
Logic stages (#1148)
* IfStage

* fmt clp

* constructor

* fmt

* else

* fmt

* while logic

* delete skippable

* fmt

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-03-17 10:21:51 +01:00
Dominik Maier
306cdcd800
Frida: Fix Android build (#1154)
* update android version

* fix android build some more
2023-03-16 16:26:22 +01:00
Dominik Maier
b9970cbdac
Implement From<CorpusId> for usize (#1152) 2023-03-16 16:12:00 +01:00
Dominik Maier
a351e7a509
Frida: fix aarch64 build (#1153) 2023-03-16 16:11:44 +01:00
Dongjia "toka" Zhang
08fe6ab791 Fix mutator slowdown (#1138)
* perf stat

* fix except swap

* swap

* fix

* reveral-based byte swap

* Revert "reveral-based byte swap"

This reverts commit 2bc9609ece47fd4e8f6d96862f8ad3fb77f11aec.

* no introspection

* clp fmt

* change rand_range to have at least 1 length

* don't use modulo

---------

Co-authored-by: Addison Crump <addison.crump@cispa.de>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-03-16 15:58:03 +01:00
Dominik Maier
3c331e5a9b
Create SchedulerTestcaseMetadata if it doesn't exist (#1151)
* Create SchedulerTestcaseMetadata if it doesn't exist

* reset symcc
2023-03-16 14:29:40 +01:00
Dongjia "toka" Zhang
51bc1d0328
Fix infinite calibration (#1147)
* Fix infinite calibration

* fmt

* fix

* fix
2023-03-15 22:19:23 +09:00
Dongjia "toka" Zhang
6c98945fc3
Fix fuzzbench_forkserver 2023-03-15 13:32:04 +09:00
Dongjia "toka" Zhang
0fa815f2b8
Rename MetaData to Metadata 2023-03-14 23:57:55 +09:00
Matheus Baptistella
c38405ef83
Shorthand functions to get typed metadata, renamed metatdata -> metadata_map (#1123)
* Created macro to get the metadata form State and Testcase

* Expanded the macros for mutable, or not, State and Testcase metadata

* Created functions on traits HasMetadata and HasNamedMetadatato get, mutable or not, metadata

* Created the functions to get metadata

* Added #[inline] attribute and renamed the functions

* Renamed the functions and added #[inline] attribute

* Temporarily added testcase() function

* Added testcase() function

* Changed Ref import to core::cell:Ref

* Added testcase_mut() and renamed occurences of metadata() and metadata_mut()

* Renamed more occurences

* Renamed the metadata() on impl HasMetadata for NopState

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-03-14 14:24:33 +01:00
Dominik Maier
8dfdee6fce
Fix UB for differential map observer example (#1140)
* Fix UB for differential map observer example

* clippy

* undo submodule foo
2023-03-14 13:50:50 +01:00
Dongjia "toka" Zhang
460787196a
Update README.md (#1142) 2023-03-14 02:09:39 +09:00
Dominik Maier
6894a37ceb
Added Truncate trait (#1141) 2023-03-13 17:34:58 +01:00
Dongjia "toka" Zhang
44b798c07e
AFL++ RedQueen (#1087)
* step 1

* step 2

* Vec

* comment

* Observer

* tmp

* TaintedTracingStage

* more

* more

* more

* Idea

* more

* more

* mmmmmore

* moremoremore

* more

* all

* clp

* comment

* core

* push temporary debug change

* note for myself

* working

* rename to AFLCmplogTracingStage

* rename

* revert fuzzers' change
2023-03-13 17:34:16 +01:00
Andrea Fioraldi
e8d99b9975
Fix capsone mode in LibAFL QEMU (#1136)
* Use regex feature in libafl_qemu

* wip

* set mode for arm reading pc

* fixes
2023-03-12 23:29:55 +01:00
Addison Crump
786af9f6a9
resolve zero-sized allocation in swap diff fuzzer (#1139) 2023-03-12 23:24:22 +01:00
lazymio
b72bf55555
Add From BytesInput trait for Vec<u8> (#1135)
* Allow take the ownership of the BytesInput

* Add must_use as told

* Implement From&Into for better interoperability

* Format code

* Remove into_bytes

* Remove From<&BytesInput> to avoid misuse
2023-03-09 02:12:09 +01:00
Dongjia "toka" Zhang
4d778dd64d
Fix fuzz_level related thing, separate on_replace/on_remove from Scheduler & various fixes (#1119)
* delete HasFuzzedCorpusId

* more

* fmt clp

* aa

* fixing

* delete

* a

* append parent id when Objective

* add HasCorpus inprocss executor

* ecofuzz, delete was_fuzzed, update fuzz_level

* fix

* RemovableScheduler for Tunable, Queue, Weighted

* clp

* no std

* import

* on_execution

* fix

* win

* fmt

* fix

* revert to on_evaluation and propogate in the accounting scheduler

* fix

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-03-08 19:43:32 +01:00
Dominik Maier
2ed6583041
CI: Run miri tests (#1130)
* Fixes/ignores for miri support

* linux

* fix doctest for miri

* fix docs

* fix UB in baby_fuzzer

* no custom allocator in miri
2023-03-08 19:21:17 +01:00
Dominik Maier
e8838ebebe
Safer EoP handling (#1128) 2023-03-08 00:33:55 +01:00
Andrea Fioraldi
3ac439b345
Use regex feature in libafl_qemu (#1127) 2023-03-07 15:18:50 +01:00
Andrea Fioraldi
20c32316eb
Define custom collectors for QemuCallTracerHelper (#1099)
* Define custom collectors for QemuCallTracerHelper and create OnCrashBacktraceCollector

* fmt

* clippy
2023-03-07 13:16:51 +01:00
Andrea Fioraldi
3ffec79a17
Increase LLMP clients timeout to 5 min (#1126)
* LLMP client access fast path

* Increase LLMP client timeoit to 5min

---------

Co-authored-by: Your Name <you@example.com>
2023-03-07 11:47:45 +01:00
Marco Cavenati
b96e194812
Improve find_llvm on MacOS (#1124)
By looking for explicitly versioned Homebrew formulae for LLVM
2023-03-07 03:23:46 +01:00
Vincent
c8254dbd0e
Check CI result on cargo make test for available fuzzers (#1107)
* fix libfuzzer_libpng_cmin

* fix libfuzzer_libpng_ctx

* revert libfuzzer_libpng_cmin and check ci by grepping broker stdout result instead

* revert libfuzzer_libpng_ctx and check ci by grepping broker stdout result instead

* add check ci for fuzzers

* add check ci for fuzzers

* add check ci

* add fuzzbench test

* add validation for qemu fuzzer

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-03-06 23:21:24 +09:00
Dongjia "toka" Zhang
9df95bd936
Use InMemoryCorpus in libfuzzer_libpng (#1125) 2023-03-05 23:23:42 +09:00
Elia Geretto
4f7b59aca4
Forward on_evaluation callback in MinimizerScheduler (#1122) 2023-03-05 22:00:32 +09:00
Langston Barrett
35e5b87188
Cargo feature to avoid regex dependency (#1102)
regex is a large crate, and is only used in a few specific spots. Users should
have the ability to avoid this transitive dependency if not using the features
in question.
2023-03-03 16:00:49 +01:00
Dongjia "toka" Zhang
5b4ae61cdd
SimpleLogger API improvements, printing to stdout, timestamps (#1109)
* log

* fix

* a

* rev

* remove

* 2 logger

* cfg std

* more

* more

* cf

* no_std

* features

* optional

* rename

* current_time()
2023-03-02 14:07:46 +01:00
van Hauser
2a3f1d68f5
fix weighting from hits (#1120) 2023-03-02 14:05:34 +01:00
Arpan Kapoor
672f4d1668
Use a different crash history in forkserver examples (#1118) 2023-03-02 19:49:50 +09:00
Dongjia "toka" Zhang
2a926f6546
Fix forkserver regression in LTO mode (#1114)
* regression

* fix

* chg

* Comment

* fmt
2023-03-02 10:17:20 +09:00
Andrea Fioraldi
452ca7a672
Implement EcoFuzz (#1115)
* Implement EcoFuzz

* clippy

* fix
2023-03-01 13:21:43 +01:00
Dominik Maier
df6271a0f3
Windows fix (#1116)
* Windows fix

* fix fix
2023-03-01 00:49:11 +01:00
Dominik Maier
31357aa7e2
Track parent testcase id, tuneable stage probabilistic settings (#1081)
* Added local event handlers

* clippy

* move tuned mutator to pow2

* Tunable updates

* parent ids

* no_std, etc

* windows

* remove local event manager handler

* maybe fix win

* win:

* win docs

* docs

* ASAN -> ASan
2023-02-28 16:36:04 +01:00
Dongjia "toka" Zhang
3e7322e395
Remove unnecessary check in calibration stage (#1111)
* save

* fix
2023-02-28 15:41:17 +01:00
Dominik Maier
fbe8cce1b8
Real OnDiskCorpus (#1096)
* Real OnDiskCorpus

* clippy

* python

* docs

* clippy

* docs

* move to reuse cachedinmem corpus

* fmt
2023-02-28 15:41:05 +01:00
Andrea Fioraldi
d36296c654
Fix llmp CliendId search (#1112) 2023-02-28 15:20:24 +01:00
Andrea Fioraldi
dc800f0814
on_evaluation Scheduler method (#1106)
* add on evaluation hook in schedulers

* on_evaluation for WeightedScheduler

* fix PowerQueueScheduler

* fix fuzzers

* upd qemu

* tests

* upd
2023-02-28 11:33:26 +01:00
Dongjia "toka" Zhang
59bf118a5a
Clippy (#1105) 2023-02-28 01:08:19 +09:00
Addison Crump
0727c80347
Add example for WASM (#1093)
* add baby_fuzzer for wasm targets

* elaborate in README

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-02-26 17:02:22 +01:00
Dongjia "toka" Zhang
c0f229ec23
Add UsesObserver to allow more generic MapFeedback (#1104)
* UsesObserver

* a

* more

* don't need these
2023-02-26 08:35:45 +01:00
clesmian
cf02553ea7
Cleanup forkserver exec builder (#1094)
* Don't use magic string but string constant

* Don't allow to specify multiple input files with different names

* Ensure that the file name for the current test case is unique for every fuzzer currently running

* Add note advising users to choose distinct names for the input file

* Move builder functions to more generic implementation to allow parse_afl_cmdline rewrite

* Rewrite parse_afl_cmdline to reduce code duplication

* Add remark to documentation regarding the program path

* Change behavior to allow the usage of actual AFL command lines, hopefully without breaking existing code

* Rustfmt

* Move generation of unique filename to fs

* Ensure default input filename for command executor is unique per fuzzing process

* Pass the input to the target via stdin, when no input file is specified

Previous solution of passing it via a standard file is useless, as the target does not know to read said file

* Rustfmt

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
2023-02-26 02:00:28 +01:00
Langston Barrett
3dbea91a63
Use Iterators as Generator (#1101)
Also, remove seemingly-unused generate_dummy method to enable this instance.

Also, add an adapter that creates an Iterator from a Generator.
2023-02-26 01:59:56 +01:00
Dongjia "toka" Zhang
95004aab7e
Update build_and_test.yml (#1103) 2023-02-25 15:12:59 +09:00
Dominik Maier
b3020d7296
Fix CoreId for Frida, FreeBSD (#1100) 2023-02-25 00:16:37 +01:00
Dominik Maier
672d25e5ac
LLMP Client timeouts, Exit broker when last client exits (#1057)
* Moving type definitions to transparent structs

* function to notify other side of exit

* docs

* Exmaple support windows now

* timeout fix

* Exiting after the last client quit

* inform about quits

* clippy

* clippy

* clean exits

* fix

* more unsafe

* fixes

* Move ClientId

* fix no_std

* Fix prometheus

* introduce Cores.trim()

* add always_track metadata

* docu

* add AlwaysUniqueMapFeedback

* rename to always_interesting

* return CoreId for Launcher

* CoreId as transparent tuple struct

* fix graceful exits for launcher

* Broker exits after launcher

* clippy

* Fix llmp eop race, introduce llmp shmem cache

* initialize cached page, clippy

* fix llmp_debug strings

* add error handling

* nicer error output

* More error handling convenience

* clippy

* fix macos example

* nits

* trying to add a logger

* no_std

* inline logger enabled

* fix windows, non-fork

* macos

* no_std docs

* clippy

* use ? instead of unwraps in example

* more logging

* docs
2023-02-24 11:50:42 +01:00
Dominik Maier
92842c8b04
Fix LLMP eop race, introduce LLMP ShMem cache (#1091)
* Fix llmp eop race, introduce llmp shmem cache

* initialize cached page, clippy

* fix llmp_debug strings

* add error handling

* nicer error output

* More error handling convenience

* clippy

* fix macos example

* nits

* trying to add a logger

* no_std

* inline logger enabled

* clippy
2023-02-24 10:28:21 +01:00
Mrmaxmeier
ff4e2f4192
Fix max input size for {CrossOverInsert,BytesInsertCopy}Mutator (#1097) 2023-02-24 00:07:54 +01:00
R. Elliott Childre
64a57ad3e3
Move bytecount to dev-dependencies (#1090)
It is only used in test code
2023-02-23 13:52:43 +01:00
Dongjia "toka" Zhang
9e88e5734e
Timeout executor cfg fix (#1088)
* fix

* fix

* fix from mac

* fix

* fix

* fix

* ?

* fix
2023-02-22 10:20:11 +09:00
Andrea Fioraldi
1b0cdab3e4
Use GuestAddr in QemuInstrumentationFilter (#1085)
* Use GuestAddr in QemuInstrumentationFilter

* fix types
2023-02-21 16:19:43 +01:00
Addison Crump
b7296db406
Fix exits which may cause double-free corruption (#1086) 2023-02-21 07:34:16 +09:00
Dongjia "toka" Zhang
20958a979f
Weak link token section (#1080)
* fix

* a
2023-02-17 10:38:46 +01:00
Addison Crump
bdac876dd4
Mutator sampling probability fixes (#1030)
* fixes for standard mutations

* more mutation updates for sampling probability, tests

* slight doc fix

* clippy gripe

* clippy fixes

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-02-16 17:29:57 +01:00
Michael Rodler
46b75747ef
Make sure input was loaded to avoid panic on unwrap in MutatedTransform (#1077)
* make sure input was loaded to avoid panic on unwrap
fixes issue #1059

* avoid unnecessary clone, avoid unnecessary branching

---------

Co-authored-by: Michael Rodler <m@mrodler.eu>
Co-authored-by: Addison Crump <addison.crump@cispa.de>
2023-02-16 17:29:33 +01:00
Addison Crump
f454d17482
CMin: don't add to map if it's the initial value (uninteresting) (#1078) 2023-02-16 17:28:49 +01:00
Dongjia "toka" Zhang
8bffd28b4c
fix (#1076) 2023-02-16 10:29:24 +09:00
Dongjia "toka" Zhang
e7ef6ae8b7
Forkserver: 1. Add mem barrier 2. Don't send the initial 4 bytes message when it uses dynamic map option only (#1073)
* fix

* Real fix

* a
2023-02-16 09:42:28 +09:00
Addison Crump
26aace6073
Fix grimoire when used with on_replace/on_remove (#1075) 2023-02-16 00:14:26 +01:00
Addison Crump
e42cd9c12f
Fixes for on_replace/on_remove and related for StdFuzzer and MapFeedback (#1067)
* scheduler replace fixes

* oops, no-std

* add

* changes on the fuzzers

* move map feedback history updates to append_metadata

* fixes for python bindings

* learn to clippy

* fix for fuzzer add_input

* clippy fixes for frida

* additional powersched differences

* corrections for bitmap_size

* off-by-one

* I live in a prison of my own creation and clippy is the warden

* clear the novelties map for the situation where is_interesting is invoked, but not append_metadata

---------

Co-authored-by: tokatoka <tokazerkje@outlook.com>
2023-02-15 17:04:18 +01:00
radl97
e61ac10656
Fix StdErrObserver not implementing needed traits (#1072) 2023-02-15 12:39:23 +01:00
Vincent
71d367af30
TimeObserver: Use Instant::now instead of Duration (#1064)
* Use Instant::now instead of duration

* Use Some

* add custom serde for Instant

* fix linter

* only enable TimeFeedback when std flag is enabled

* fix typo

* fix linter std

* cargo fmt

* allow clippy::trivially_copy_pass_by_ref on custom serde serialize function

* allow TimeObserver and Timefeedback for no_std

* cargo fmt

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-02-15 12:38:25 +01:00
David CARLIER
fb0d3b07ea
MiniBSoD: solaris on amd64 implementations (#1068) 2023-02-15 12:27:45 +01:00
Andrea Fioraldi
cf0a0a0698
Add stub lib for fuzzbench (#1074) 2023-02-15 12:05:10 +01:00
Elsa Granger
44b69666da
Fix fuzzbench build (#1004)
* Fix -z,defs handle

* Add libfuzzer_no_link_main option in libfuzzer

* Use libfuzzer_no_link_main for fuzzbench

* no_link_main feature

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-02-15 11:58:32 +01:00
Andrea Fioraldi
f8a4a020e8
QEMU: do not crash in helpers pre and post execs (#1065)
* QEMU: do not crash in helpers pre and post execs

* comma
2023-02-14 13:35:20 +01:00
Fabian Freyer
53dba5f49d
Use the log facade instead of println (#1060)
* switched a couple of println / dbg statements to use log crate
* Use pyo3-log for logging in python bindings
2023-02-14 10:01:51 +01:00
Dongjia "toka" Zhang
30b51bb810
Remove unused dependencies (#1069) 2023-02-14 09:02:18 +01:00
Dongjia "toka" Zhang
bd2de16b4e
Colorization stage (#1039)
* type_replace

* separate

* more

* heap

* comment

* f

* fix

* clp

* need rev

* comment

* ColorizationTracingStage

* get_raw_map_hash_run

* process_execution

* metadat

* unused TE

* resolve type errors

* remove colorizationtracingstage

* Finally compiles

* clp

* fmt

* a few debug println

* revert

* fix
2023-02-13 15:02:19 +09:00
Dongjia "toka" Zhang
a74e5da268
Revert FridaInstrumentationHelper changes (#1062)
* Revert "Send stability in calibration stage & FridaInstrumentationHelper retunrs Result<Self, Error> (#1056)"

This reverts commit 4d78878c02846b2c0a49686cd05cccadd2b0ac72.

* fux

* poc

* revert
2023-02-13 10:02:26 +09:00
Dongjia "toka" Zhang
4d78878c02
Send stability in calibration stage & FridaInstrumentationHelper retunrs Result<Self, Error> (#1056)
* fix

* fix

* clippy
2023-02-13 05:35:09 +09:00
Dongjia "toka" Zhang
b7a0b823c6
Fix frida_gdiplus (#1045)
* fix

* I don't like prelude

* clp

* cargo make test

* poc

* one to_vec()

* fix?

* del

* fix
2023-02-08 00:20:38 +09:00
Andrea Fioraldi
0173d722c6
Fix typo in directory visiting (#1050) 2023-02-07 10:47:36 +01:00
Dongjia "toka" Zhang
30e296968b
Rename LLMP Timeout message, increase timeout (#1048)
* rename

* Update llmp.rs

* Print every 30 seconds only

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
2023-02-06 16:42:14 +01:00
Langston Barrett
4e15be182e
Increase default initial capacity of NewHashFeedback (#1049) 2023-02-06 15:50:26 +01:00
R. Elliott Childre
4d5a759955
Update deps for libafl (#1042)
Reduces total number of packages from 577 to 571 on building with:
`cargo +nightly build --workspace --all-features`

* ahash 0.7 -> 0.8
  * Move `AHasher::new_with_keys` to `RandomState::with_seeds` given the
    recommendation from: aHash maintainer:
    https://github.com/tkaitchuck/aHash/issues/132#issuecomment-1288207069

* bindgen: 0.61 -> 0.63

* c2rust-bitfields: 0.3 -> 0.17

* criterion: 0.3 -> 0.4

* crossterm: 0.25 -> 0.26

* dynasmrt: 1.2 -> 2

* goblin: 0.5.3 -> 0.6

* hashbrown: 0.12 -> 0.13

* nix: 0.25 -> 0.26
  * The `addr` arg of `mmap` is now of type `Option<NonZeroUsize>`
  * The `length` arg of `mmap` is now of type `NonZeroUsize`
  * Requires updating implementers to update `nix` as well

* prometheus-client: 0.18.0 -> 0.19
  * Do not box metrics
  * Gauges (a majority of the LibAFL metrics) are now i64 types so there
    is a small chance of overflow, with the u64 values that LibAFL
    tracks, but unlikely to be problematic.
 * Keep `exec_rate` as a floating point value

* serial_test: 0.8 -> 1

* typed-builder: 0.10.0 -> 0.12

* windows: 0.42.0 -> 0.44

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-02-06 12:24:42 +01:00
Langston Barrett
e75f65080e
libafl: with_capacity method for NewHashFeedback (#1034)
Most of the time, fuzzing campaigns are reasonably long. Accordingly, when
using `NewHashFeedback`, you might have good reason to believe that you'll
find thousands (or more) different observations with different hashes. When
the `HashSet` outgrows its capacity, it can cause reallocation, which is slow.
See the following link for more details:

https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
2023-02-06 01:44:57 +01:00
R. Elliott Childre
5d76707ede
Bump deps and fix Clippy warns in example fuzzers (#1043)
* Mostly addressing changing the `uninlined_format_args` lint which was
  changed to warn-by-default in rust clippy 1.67

* Bump dependencies:
  bindgen:  0.61 -> 0.63
  cc:       1.0 -> 1.0.42 (Exclue versions w/incompat rayon dependency)
  clap:     3.x -> 4.0
  rangemap: 0.1 -> 1
  xz -> xz2:  move to updated version

* Add fallthrough default return to `LLVMFuzzerTestOneInput` in
  **/fuzz.c to prevent Clang's -Wreturn-type

* libafl_atheris: Improve POSIX compatibility and reduce warnings
  * Check for .dylib and .so libraries
  * `source` -> `.` for POSIX shells
  * install wheel into the venv to support newer Python packaging
    standards
  * `LDPRELOAD` -> `LD_PRELOAD`
2023-02-05 21:53:45 +01:00
Dominik Maier
48caffb802
Allow to load a list of files (#1044) 2023-02-05 21:22:58 +01:00
Andrea Fioraldi
eaf5ff9de0
Restart loading initial inputs even after a crash/timeout (#1040)
* Track initial inputs loading

* libfuzzer libpng

* fuzzbench

* fix no_std

* fix no_std

* clippy

* fuzzers
2023-02-03 11:56:47 +01:00
Dominik Maier
86ab682e5a
Readme: Add information about system mode QEMU (#1038) 2023-02-02 15:20:45 +01:00
Dongjia "toka" Zhang
db62c26eda
Remove unused imports (#1035)
* remove unused imports

* fmt
2023-02-01 12:26:56 +01:00
WorksButNotTested
71f106be20
Fix accidental breakage of non-AARCH64 systems (#1036)
Co-authored-by: Your Name <you@example.com>
2023-02-01 17:46:12 +09:00
WorksButNotTested
d0b4c39acd
Change to combine restoration prologue with coverage register spill (#1029)
Co-authored-by: Your Name <you@example.com>
2023-02-01 04:41:56 +01:00
Andrea Fioraldi
2a88a776bf
Fix frida Cargo.toml (#1033) 2023-01-31 14:05:07 +01:00
Andrea Fioraldi
b77c0b78cc
Fix readme position in qemu sys (#1032) 2023-01-31 13:40:28 +01:00
Dongjia "toka" Zhang
f9dd67b59b
Comment Fix 2023-01-31 19:40:58 +09:00
Dominik Maier
cc53da85fb
Remove {update,clear}_hash from ObserverWithHashField, add hasher (extending #1019) (#1028)
* libafl: Remove `{update,clear}_hash` from `ObserverWithHashField`

These methods aren't used by `NewHashFeedback`, so there's no compelling reason
to keep them in the interface. They preclude implementations of
`ObserverWithHashField` that calculcate a hash on-the-fly from a value. For
example, my use-case is to store the stdout of a process, and use
`NewHashFeedback` to only collect inputs that result in new messages on stdout.

Both of these methods are pretty suspicious to begin with - why should other
code be able to update the internal state of the observer? What are the
semantics of `update_hash`? If there are compelling reasons to keep these
methods, let's clarify their intent in the documentation.

* libafl: Return hash by value from `ObserverWithHashField`

This allows implementors of this trait to not store the hash, but rather to
compute it on-the-fly. Since `Option<u64>` is `Copy` (and quite small), and
this method is called once per execution of the target program, this is likely
to have negligible performance impact.

* libafl: Implement `ObserverWithHashField` for `ValueObserver`

This demonstrates the utility of the previous two commits. Now, `ValueObserver`
can be used with `NewHashFeedback`.

* Clippy, move to ahasher

* Oops :)

---------

Co-authored-by: Langston Barrett <langston.barrett@gmail.com>
2023-01-31 10:45:42 +01:00
Andrea Fioraldi
fdf579bcd5
Bump to 0.9.0 (#946)
* bump to 0.9.0

* fix libafl_tinyinst

* fix

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2023-01-31 10:42:01 +01:00
Dominik Maier
d73fb92ddf
Python CI (#1024)
* Python CI

* fix testcase

* fix yml

* Fixing test

* format python

* cleanup
2023-01-31 05:04:19 +01:00
Dominik Maier
fc8c92514f
Update README.md (#1027) 2023-01-31 04:43:27 +01:00
Dominik Maier
7c4acb3b22
Update README.md (#1026) 2023-01-31 04:34:01 +01:00
Dominik Maier
2cd3fb8fea
New Logo (#1025) 2023-01-31 04:32:47 +01:00
Dominik Maier
ff9208f107
Fixing python example (#1016)
* Fixing python example

* Fix python baby fuzzer

---------

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-01-30 20:03:07 +01:00
Fabian Freyer
afa506c0c8
libafl_frida: Allow compilation for iOS (#1023)
iOS does not have any TLS, so we don't need to keep track of it.
This allows compiling for the aarch64-apple-ios target.
2023-01-30 18:05:00 +01:00
Dominik Maier
33ddce2cea
Introduce MutatorId, Tuneable fixes (#1022)
* Add simpler APIs for TunableStage

* Make API usable

* Add TunableScheduledMutator APIs

* Introduce MutatorId

* More API

* Cleanup

* add sampling-based mutation scheduling

* reduce precision for sampling

* clippy
2023-01-30 18:04:42 +01:00
Dongjia "toka" Zhang
b927fc9b06
Add filename_path to MmapShMemProvider (#1014)
* change how it is named

* Add more comments

* more

* macOS 32bytes onlyu

* chg

* comment, fix
2023-01-26 00:53:37 +01:00
Dominik Maier
e5c220519e
LLMP Broker: timeouts for inactive clients (#1005)
* LLMP Timeouts

* Make broker timeouts optional

* fix warning

* fix warning
2023-01-25 12:03:23 +01:00
Andrea Fioraldi
92c0c5eeab
Fix second Forkserver Broken Pipe (#1013)
* Truncate at MAX_FILE

* AFL_MAP_SIZE

* todo
2023-01-24 20:50:56 +01:00
Addison Crump
00ec7e143c
fix for MapIndexesMetadata (#1008)
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-01-23 15:08:33 +01:00
Dongjia "toka" Zhang
fe51286586
TinyInst Update (#968)
* tmp

* more

* save

* TODO

* fix

* update to tinyinst on crates

* dep

* fmt

* shmem done

* cpp fmt

* clp

* fmt

* why??

* ver

* more makefile.toml

* windows test

* Update build_and_test.yml

* fix

* a

* install

* fmt

* fix

* only macos and win

* more

* The order matters

* remove

* fmt

* chg

* typo

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-01-23 11:11:53 +01:00
David CARLIER
3b68399cc9
libafl_cc fixes for clang 16 (#1010)
None constant being deprecated, it is recommended
to use the std::nullopt_t type instead.
2023-01-23 11:00:42 +01:00
Andrea Fioraldi
7fd9ac0952
SyncFromBrokerStage to sync from a broker with a different Input type (#997)
* ConverterLlmpEventManager

* docs

* SyncFromBrokerStage

* fix

* separate InputConverter

* nautilus

* nautilus_sync

* send testcases

* upd nautilus

* meta

* fix

* clippy

* fix

* Update build_and_test.yml

* fix

* fix

* Use find_libpython

* ci

* upd qemu
2023-01-20 17:16:29 +01:00
WorksButNotTested
5cdb7f7b05
Improve AARCH64 performance (#989) 2023-01-18 13:56:17 +01:00
Addison Crump
ebc886032f
Fixes for multiple subtle bugs with grimoire, mutators, and state (#1001)
* fix multiple subtle bugs with grimoire, mutators, and state

* obey the clippy overlord

* grimoire: skip over token after splice

* remove extraneous length check
2023-01-18 13:53:31 +01:00
Paul Walker
333a51aeaa
StacktraceObserver speedup using unresolved backtrace (#1002)
We don't use the symbols anyway, and it makes the call *way* faster.
2023-01-18 13:51:42 +01:00
Andrea Fioraldi
3c8a00bc42
Fix qemu user (#1003) 2023-01-18 13:38:49 +01:00
Dongjia "toka" Zhang
1446692f02
Fix stability UI (#1000)
* Update mod.rs

* fmt
2023-01-18 19:00:50 +09:00
van Hauser
15c1c0fb5e
Avoid no-op in ByteRandMutator (#999) 2023-01-17 11:07:50 +01:00
Andrea Fioraldi
7cf7d545a6
Update QEMU and fix snapshot restore mem leak (#998)
* Update qemu

* Fix leak

* upd

* fmt
2023-01-17 11:06:31 +01:00
Dominik Maier
97e88af0c5
OnDiskCorpus: Write metadata by default, metadata gzip compression (#995)
* Write metadata by default

* fix fuzzers

* Cleanup, gzip feature

* Fix casing for ondisk corpus

* fix fmt, clippy

* clippy

* clippy for gdiplus fuzzer

* fmt
2023-01-13 01:07:36 +01:00
Addison Crump
28786c943a
Grimoire fixes (#993)
* fixup grimoire/generalisation, remove GeneralizedInput in favour of metadata

* additional cleanup

* transformable inputs to solve the grimoire problem

* explicit use of 'transforming' to keep typing compatible with normal usage

* clippy fix

* fixes for nautilus, python

* explicit inlining for reflexive impl

* fix for tutorial

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-01-13 01:07:21 +01:00
Andrea Fioraldi
ec84c71eae
Corpus maps (#947)
* hashmap corpus for inmemory

* corpus_btreemap feature

* CorpusId

* queue

* MinimizerScheduler::remove

* fixes

* continue

* keys

* working corpus

* ok

* weighted left

* wip

* port weighted scheduler

* it compiles

* doc

* fix mutators

* fix queue

* fix iter

* tests

* fix

* fix

* fix

* py

* clippy

* clippy

* clippy

* cmin

* fix

* fix

* fix

* clippy

* remove Corpus::random_id
2023-01-09 14:15:07 +01:00
biazo
3345727c94
fixing linking issue on qemu build (#990)
* fixing linking issue

* insteading of linking lib we dont use. just disable them

* fixing the keyutils problem

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2023-01-09 10:10:14 +01:00
Dominik Maier
17cb317429
Fix early drop for frida transformer (#992)
* Fix early drop for frida transformer

* clippy
2023-01-08 18:19:30 +01:00
Dominik Maier
159e6ea480
Fix Launcher for M1, fix frida_libpng harness compilation, fix CI (#987)
* Fix harness compilation for frida_libpng

* M1: Always use fast cores

* always ignore result

* seeing if manualy installing libunistring fixes wget

* seeing if manualy installing wget fixes it, instead

* un-remove comment
2023-01-05 14:26:20 +01:00
WorksButNotTested
266677bb88
FRIDA: Fix previous_pc constant (#988)
Co-authored-by: Your Name <you@example.com>
2023-01-05 12:20:06 +01:00
WorksButNotTested
f27ca843e1
FRIDA x64 performance improvements (#985)
Co-authored-by: Your Name <you@example.com>
2023-01-05 11:51:58 +01:00
Dominik Maier
1bb37e4b98
Book: Explain SymCC constraint solving (follow up on #980) (#986)
* Make the kind of solving more clear (follow up on #980)

* Update docs/src/advanced_features/concolic.md

Co-authored-by: julihoh <julihoh@users.noreply.github.com>

Co-authored-by: julihoh <julihoh@users.noreply.github.com>
2023-01-05 11:51:31 +01:00
hexcoder
7d412693c8
Book review (#980)
* docs review

* docs review

* docs review wording

* docs review wording

* docs review wording

* wording

* nits

* wording

* wording

* nits

* docs_review wording

* wording

* wording

* wording

* Wording

* wording

* nits

* Wording

* fix main naming for afl++

* update symcc

Co-authored-by: Dominik Maier <dmnk@google.com>
2023-01-04 15:21:08 +01:00
Dongjia "toka" Zhang
d2985c5b2e
Clippy fix (#978)
* fix

* mac

* clp
2023-01-02 20:35:41 +09:00
Sparrrgh
43425cf103
Correct MIPS register naming in libafl_qemu (#977) 2022-12-31 09:23:50 +01:00
Dongjia "toka" Zhang
9458549fef
Remove declare -A (#976)
* fix

* fix

* debug

* debug

* older version

* newer version

* fix

* unix?

* fix
2022-12-30 02:02:38 +09:00
Erwan Grelet
3e38862837
Forkserver example with forkserver.c (#726) (#973)
* forkserver: Add an API to setup the shared memory region for edge coverage

This is inspired from and meant to be similar to afl-cc's instrumentation.
Remove ! return type from __afl_start_forkserver as it returns in several cases.

* Add example fuzzer using LibAFL's forkserver

The fuzzer is instrumented with libafl_cc as well.

Co-authored-by: ergrelet <ergrelet@users.noreply.github.com>
2022-12-28 22:16:27 +01:00
Dongjia "toka" Zhang
676a149497
Update CorpusWeightTestcaseScore (#975)
* fix

* clp

* fmt
2022-12-28 22:16:08 +01:00
Patrick Gersch
2b092f40fa
SimpleMonitor optionally displays user_monitor stats (#970)
* Adding with_user_monitor() to SimpleMonitor

* Satisfy clippy

* Satisfy fmt and pylibafl

* Fix leading whitespace
2022-12-26 11:20:30 +01:00
Dongjia "toka" Zhang
476cb7e7dc
Frida Makefile.toml fix (#969)
* frida build script fix

* fix

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml

* Update build_and_test.yml
2022-12-26 14:19:37 +09:00
Dominik Maier
75f12bd0eb
Remodelling Observers/Examples that rely on UB, API cleanups (#950)
* Tackling UB

* PtrMut -> MutPtr, moved mapobservers to non-UB

* QEMU fixes

* test fixes

* qemu

* Change all interfaces, fix all fuzzers

* fixes

* fix more fixes

* fmt

* fix qemu sugar

* fix some qemus

* atheris

* fmt

* more fmt

* most fmt

* more fix

* nyx fyx

* fix qemu

* clippy, fixes

* more fixes

* no unfix, only fix

* fix

* fix

* more clippy

* fixes

* ListObserver

* fmt, clippy

* fix qemu on arm

* update zlib target

* fix?

* fix

* added migration guide

* ignore doc

* fix symcc

* fix new win fuzzer

* Fixes, rename PTR_SIZE to PTR_NUM

* Try fix linking on win

* Trying to fix win linking

* more cov

* trying to fix win some more

* trying to fix mac

* trying to fix mac

* Fix tests

* Fix tests

* trying to fix win

* more mac

* giving up for windows

* fmt

* python3

* mac?

* undo windows tests
2022-12-24 14:20:44 +01:00
Dominik Maier
3a1e499d9d
Documentation fixes (#967)
* a few stylistic/grammar changes

* expression

* some wording and a different git clone command

The original `git clone` command did not work for me (permission denied).

* small wording changes

* review

* typo

* neutral

Co-authored-by: hexcoder <hexcoder-@users.noreply.github.com>
2022-12-21 12:44:42 +01:00
humpty99
de6ee8b161
Fix Nyx build script (#965)
due to the call to pushd on line 23 not being directed at packer, the wrong commit was being used and so that resulted in the wrong init.cpio.gz being generated which hangs when trying to run the libxml2 examples however using the right commit (86b159bafc0b2ba8feeaa8761a45b6201d34084f) fixes this problem.
2022-12-21 20:29:42 +09:00
Dongjia "toka" Zhang
d77d9d5f31
Frida: Make stalker.exclude() configurable from command line arguments (#956)
* remove exclude on windows

* linux x86_64

* option
2022-12-21 11:23:57 +01:00
Max Ammann
4d8b566a87
[Windows] Add libfuzzer example for windows with ASAN (#934)
* Add libfuzzer example for window with ASAN

* Fix formatting

* Add link

* Fix cpp format

* Skip windows fuzzers

* Fix format

* Fix testing fuzzer

* Fix taks name

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-21 10:41:58 +01:00
Dongjia "toka" Zhang
3c7dcac41d
Deduplicate crash handlers (#951)
* unix

* win

* std

* fmt

* more

* more

* win

* rename

* win

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-21 10:41:18 +01:00
Dongjia "toka" Zhang
038732bd92
no mold (#964) 2022-12-21 13:27:14 +09:00
Dongjia "toka" Zhang
f1b25fed65
Fix CI (#955)
* fix

* fmt

* Update build_and_test.yml

* no nightly

* fix

* why

* Update build_and_test.yml

* a

* a

* ok

* linux only

* fmt

* Update build_and_test.yml

* fix
2022-12-21 11:12:54 +09:00
hexcoder
b0df0a26a1
Docs: grammar fix (#961) 2022-12-21 00:19:38 +01:00
Dominik Maier
7ed1ac9c9b
Additional SymCC Build Fixes (#954) 2022-12-20 00:37:19 +01:00
Dominik Maier
e56d5318e4
Fix SymCC build (#952) 2022-12-19 13:48:07 +01:00
Dominik Maier
ccf6cc708a
Windows clippy fixes (#948) 2022-12-18 12:35:30 +01:00
radl97
016a4c3778
Human readable execs & run/exec rounding fix (#936)
* Calculate run/exec statistics as float to solve rounding issues

* Fixup

* Clippy fixes

* Clippy fixes

* Change execs_per_sec() to return float per suggestions

* Monitors: Write 2 decimal floating-point for execs/sec

* Prettify exec/sec

* Formatting & fix copy pasta

* Pretty-print floats in monitor: use mega and kilo SI suffices

* prettify -> prettify_float, apply suggestion

* Clippy

* Fix prometheus client cannot handle float values yet

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-16 23:46:33 +01:00
Sparrrgh
d04346c870
Add mips support for QemuTracerHelper (#941)
* Add mips support for QemuTracerHelper

* Formatting

Ran cargo +nightly fmt

* Removed unnecessary `any`

* Removed cfg guarding calls module

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2022-12-14 17:45:54 +01:00
omergreen
664e87809e
libafl-frida: disable LibAFL's default features in Cargo.toml (#939)
* disable libafl's default features in libafl-frida

to allow users to disable default features while using stuff from libafl-frida

* Update Cargo.toml

Co-authored-by: Dominik Maier <domenukk@gmail.com>
2022-12-14 01:59:17 +01:00
Andrea Fioraldi
55e220f0e8
CI: diff with main and HEAD^ (#945) 2022-12-14 01:10:36 +01:00
Andrea Fioraldi
162de0ceaf
Fix CI diffing (#944)
* fix build_and_test_fuzzers to diff from origin/main

* fix fuzzbench_forkserver
2022-12-13 21:19:44 +01:00
Ao Li
9e4a0513c6
Gramatron: Fix a typo in gnf_converter.py (#942)
This patch addresses the issue in #879, which fixes a typo in the `remove_left_recursion` method.
2022-12-13 17:27:16 +01:00
Andrea Fioraldi
08be5f732e
CI: Only test fuzzers with diffing deps (#940)
* build and test fuzzer crate

* diffing fuzzers ci only

* clippy

* clippy merda

* clippy merde

* improve it

* comment

* split ubuntu CI workflow

* fix
2022-12-13 14:10:34 +01:00
907 changed files with 117733 additions and 40364 deletions

View File

@ -6,22 +6,27 @@
"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"
],
"customizations": {
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["matklad.rust-analyzer", "microsoft.Docker"],
// Set *default* container specific settings.json values on container create.
"settings": {
"rust-analyzer.cargo.noDefaultFeatures": true
}
}
},
// 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",
// Install development components that shouldn't be in the main Dockerfile
"postCreateCommand": "rustup component add --toolchain nightly rustfmt clippy llvm-tools-preview && cargo install --locked cargo-make",
// 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.

View File

@ -13,6 +13,8 @@ Thank you for making LibAFL better!
**Describe the bug**
A clear and concise description of what the bug is.
If you want to present the backtrace, don't forget to run with `errors_backtrace` feature and log from `RUST_LOG`
In addition, please tell us what is your fuzzer's Cargo.toml
**To Reproduce**
Steps to reproduce the behavior:

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "daily"

View File

@ -2,25 +2,37 @@ name: build and test
on:
push:
branches: [ main ]
branches: [ main, "pr/**" ]
pull_request:
branches: [ main ]
workflow_dispatch:
merge_group:
env:
CARGO_TERM_COLOR: always
CARGO_NET_GIT_FETCH_WITH_CLI: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
common:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
os: [ ubuntu-latest, windows-latest, macOS-latest ]
runs-on: ${{ matrix.os }}
steps:
- name: Install mimetype
if: runner.os == 'Linux'
run: sudo apt-get install libfile-mimeinfo-perl
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
- name: Install mimetype
if: runner.os == 'Linux'
run: sudo apt-get install libfile-mimeinfo-perl
- name: install mdbook
uses: baptiste0928/cargo-install@v1.3.0
with:
@ -31,16 +43,17 @@ jobs:
crate: mdbook-linkcheck
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Install mimetype
with: { shared-key: "ubuntu" }
if: runner.os == 'Linux'
run: sudo apt-get install libfile-mimeinfo-perl
- uses: Swatinem/rust-cache@v2
if: runner.os != 'Linux'
- name: Check for binary blobs
if: runner.os == 'Linux'
run: ./scripts/check_for_blobs.sh
- name: default nightly
run: rustup default nightly
- 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'
@ -49,244 +62,485 @@ jobs:
run: cargo test
- name: Test libafl no_std
run: cd libafl && cargo test --no-default-features
- name: Test libafl_bolts no_std no_alloc
run: cd libafl_bolts && cargo test --no-default-features
- name: Test libafl_targets no_std
run: cd libafl_targets && cargo test --no-default-features
llvm-tester:
runs-on: ubuntu-22.04
continue-on-error: true
strategy:
matrix:
llvm-version: [ "16", "17" ] # Add 18 when KyleMayes/install-llvm-action enables it
steps:
- name: Remove Dotnet & Haskell
run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
with: { shared-key: "llvm-tester" }
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
version: "${{matrix.llvm-version}}"
- name: Build and test with llvm-${{ matrix.llvm-version }}
run: pwd && ls & cd libafl_cc && cargo build --release
ubuntu-doc-build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/ubuntu-prepare
- uses: Swatinem/rust-cache@v2
# ---- doc check ----
- name: Build Docs
run: RUSTFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps
ubuntu-doc-test:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/ubuntu-prepare
- uses: Swatinem/rust-cache@v2
# ---- doc check ----
- name: Test Docs
run: RUSTFLAGS="--cfg docsrs" cargo +nightly test --doc --all-features
ubuntu-miri:
runs-on: ubuntu-22.04
needs: ubuntu
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/ubuntu-prepare
- uses: Swatinem/rust-cache@v2
- name: Add nightly clippy
run: rustup toolchain install nightly --component miri --allow-downgrade
# --- miri undefined behavior test --
- name: Run miri tests
run: RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo +nightly miri test
ubuntu:
runs-on: ubuntu-22.04
steps:
- name: Remove Dotnet & Haskell
run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: set mold linker as default linker
uses: rui314/setup-mold@v1
- name: Install and cache deps
uses: awalsh128/cache-apt-pkgs-action@v1.1.0
with:
packages: llvm llvm-dev clang ninja-build clang-format-13 shellcheck libgtk-3-dev gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libslirp-dev
- name: get clang version
run: command -v llvm-config && clang -v
- name: Install cargo-hack
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
- name: Remove Dotnet & Haskell
run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Remove existing clang and LLVM
run: sudo apt purge llvm* clang* lld* lldb* opt*
- name: Install and cache deps
run: sudo apt update && sudo apt install ninja-build shellcheck libgtk-3-dev gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libslirp-dev libz3-dev
- name: Add nightly clippy
run: rustup toolchain install nightly --component clippy --component miri --allow-downgrade
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
with: { shared-key: "ubuntu" }
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
directory: ${{ runner.temp }}/llvm
version: 17
# 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: run shellcheck
run: shellcheck ./scripts/*.sh
# ---- build normal and examples ----
- name: Run a normal build
run: cargo build --verbose
- name: Build examples
run: cargo build --examples --verbose
# ---- format check ----
# pcguard edges and pcguard hitcounts are not compatible and we need to build them seperately
- name: Check pcguard edges
run: cargo check --features=sancov_pcguard_edges
- name: Format
run: cargo fmt -- --check
- name: Run clang-format style check for C/C++ programs.
run: clang-format-13 -n -Werror --style=file $(find . -type f \( -name '*.cpp' -o -iname '*.hpp' -o -name '*.cc' -o -name '*.cxx' -o -name '*.cc' -o -name '*.h' \) | grep -v '/target/' | grep -v 'libpng-1\.6\.37' | grep -v 'stb_image\.h' | grep -v 'dlmalloc\.c' | grep -v 'QEMU-Nyx')
- name: run shellcheck
run: shellcheck ./scripts/*.sh
- name: Run clippy
run: ./scripts/clippy.sh
# ---- doc check ----
- name: Build Docs
run: cargo doc
- name: Test Docs
run: cargo +nightly test --doc --all-features
ubuntu-clippy:
runs-on: ubuntu-22.04
steps:
- name: Remove Dotnet & Haskell
run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
# ---- build and feature check ----
- name: Run a normal build
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
- name: Install and cache deps
run: sudo apt update && sudo apt install ninja-build shellcheck libgtk-3-dev gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libslirp-dev libz3-dev
- name: Add nightly clippy
run: rustup toolchain install nightly --component clippy --allow-downgrade && rustup default nightly
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
with: { shared-key: "ubuntu" }
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
directory: ${{ runner.temp }}/llvm
version: 17
- name: Run clippy
run: ./scripts/clippy.sh
# --- test embedding the libafl_libfuzzer_runtime library
# Fix me plz
# - name: Test Build libafl_libfuzzer with embed
# run: cargo +nightly test --features=embed-runtime --manifest-path libafl_libfuzzer/Cargo.toml
ubuntu-check:
runs-on: ubuntu-22.04
needs: ubuntu
strategy:
matrix:
instance_idx: [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17" ]
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/ubuntu-prepare
- uses: Swatinem/rust-cache@v2
with: { shared-key: "ubuntu" }
# ---- build and feature check ----
# 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
# `sancov_pcguard_edges` is tested seperatelyc
run: python3 ./scripts/parallellize_cargo_check.py ${{ matrix.instance_idx }}
ubuntu-concolic:
runs-on: ubuntu-latest
needs: ubuntu
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
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
with: { shared-key: "ubuntu" }
- 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:
python-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
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Remove existing clang and LLVM
run: sudo apt purge llvm* clang*
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
directory: ${{ runner.temp }}/llvm
version: 17
- name: Install deps
run: sudo apt-get install -y ninja-build python3-dev python3-pip python3-venv libz3-dev
- name: Install maturin
run: python3 -m pip install maturin
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Run a maturin build
run: export LLVM_CONFIG=llvm-config-16 && cd ./bindings/pylibafl && python3 -m venv .env && . .env/bin/activate && pip install --upgrade --force-reinstall . && ./test.sh
- name: Run python test
run: . ./bindings/pylibafl/.env/bin/activate # && cd ./fuzzers/python_qemu/ && python3 fuzzer.py 2>&1 | grep "Bye"
cargo-fmt:
runs-on: ubuntu-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt
- uses: actions/checkout@v3
- name: Remove existing clang and LLVM
run: sudo apt purge llvm* clang*
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
directory: ${{ runner.temp }}/llvm
version: 17
- name: Format Check
run: ./scripts/fmt_all.sh check
fuzzers-preflight:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Fuzzer in CI Check
run: ./scripts/check_tested_fuzzers.sh
fuzzers:
needs:
- ubuntu
- fuzzers-preflight
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
os: [ ubuntu-latest ]
fuzzer:
- ./fuzzers/cargo_fuzz
- ./fuzzers/fuzzbench_fork_qemu
- ./fuzzers/libfuzzer_stb_image_sugar
- ./fuzzers/nyx_libxml2_standalone
- ./fuzzers/baby_fuzzer_gramatron
- ./fuzzers/tinyinst_simple
- ./fuzzers/baby_fuzzer_with_forkexecutor
- ./fuzzers/baby_no_std
- ./fuzzers/baby_fuzzer_swap_differential
- ./fuzzers/baby_fuzzer_grimoire
- ./fuzzers/baby_fuzzer
- ./fuzzers/libfuzzer_libpng_launcher
- ./fuzzers/libfuzzer_libpng_accounting
- ./fuzzers/forkserver_libafl_cc
- ./fuzzers/libfuzzer_libpng_tcp_manager
- ./fuzzers/backtrace_baby_fuzzers
- ./fuzzers/fuzzbench_qemu
- ./fuzzers/nyx_libxml2_parallel
- ./fuzzers/frida_gdiplus
- ./fuzzers/libfuzzer_stb_image_concolic
- ./fuzzers/nautilus_sync
- ./fuzzers/push_harness
- ./fuzzers/libfuzzer_libpng_centralized
- ./fuzzers/baby_fuzzer_nautilus
- ./fuzzers/fuzzbench_text
- ./fuzzers/libfuzzer_libpng_cmin
- ./fuzzers/forkserver_simple
- ./fuzzers/baby_fuzzer_unicode
- ./fuzzers/libfuzzer_libpng_norestart
- ./fuzzers/baby_fuzzer_multi
- ./fuzzers/libafl_atheris
- ./fuzzers/frida_libpng
- ./fuzzers/fuzzbench_ctx
- ./fuzzers/fuzzbench_forkserver_cmplog
- ./fuzzers/push_stage_harness
- ./fuzzers/libfuzzer_libmozjpeg
- ./fuzzers/libfuzzer_libpng_aflpp_ui
- ./fuzzers/libfuzzer_libpng
- ./fuzzers/baby_fuzzer_wasm
- ./fuzzers/fuzzbench
- ./fuzzers/libfuzzer_stb_image
- ./fuzzers/fuzzbench_forkserver
# - ./fuzzers/libfuzzer_windows_asan
# - ./fuzzers/dynamic_analysis
- ./fuzzers/baby_fuzzer_minimizing
- ./fuzzers/frida_executable_libpng
- ./fuzzers/tutorial
- ./fuzzers/baby_fuzzer_tokens
- ./fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor
- ./fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor
- ./fuzzers/backtrace_baby_fuzzers/command_executor
- ./fuzzers/backtrace_baby_fuzzers/forkserver_executor
- ./fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor
- ./fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor
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
- uses: actions/checkout@v3
- uses: ./.github/workflows/fuzzer-tester-prepare
- name: Build and run example fuzzers (Linux)
if: runner.os == 'Linux'
shell: bash
run: RUN_ON_CI=1 LLVM_CONFIG=llvm-config ./scripts/test_fuzzer.sh ${{ matrix.fuzzer }}
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
qemu: ${{ steps.filter.outputs.qemu }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
qemu:
- 'libafl_qemu/**'
- 'fuzzers/*qemu*/**'
fuzzers-qemu:
needs: changes
if: ${{ needs.changes.outputs.qemu == 'true' }}
strategy:
matrix:
os: [ubuntu-latest]
fuzzer:
- ./fuzzers/qemu_cmin
- ./fuzzers/qemu_systemmode
- ./fuzzers/qemu_coverage
- ./fuzzers/qemu_launcher
runs-on: [ self-hosted, qemu ]
container: registry.gitlab.com/qemu-project/qemu/qemu/ubuntu2204:latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/qemu-fuzzer-tester-prepare
- name: Build and run example QEMU fuzzers (Linux)
if: runner.os == 'Linux'
shell: bash
run: RUN_ON_CI=1 LLVM_CONFIG=llvm-config ./scripts/test_fuzzer.sh ${{ matrix.fuzzer }}
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
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: 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
nostd-clippy:
runs-on: ubuntu-latest
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: 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: libafl armv6m-none-eabi (32 bit no_std) clippy
run: cd ./libafl && cargo clippy --target thumbv6m-none-eabi --no-default-features
- name: Build no_std no_alloc bolts
run: cd ./libafl_bolts && cargo +nightly build -Zbuild-std=core --target aarch64-unknown-none --no-default-features -v --release && cd ../
build-docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build docker
run: docker build -t libafl .
- uses: actions/checkout@v3
- name: Build docker
run: docker build -t libafl .
windows:
windows-frida-libpng:
runs-on: windows-latest
needs:
- common
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Windows Build
run: cargo build --verbose
- name: Run clippy
uses: actions-rs/cargo@v1
with:
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
- uses: actions/checkout@v3
- uses: ./.github/workflows/windows-tester-prepare
- name: Build fuzzers/frida_libpng
run: cd fuzzers/frida_libpng/ && cargo make test
windows-frida-libfuzzer-stb-image:
runs-on: windows-latest
needs:
- common
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/windows-tester-prepare
- name: Build fuzzers/libfuzzer_stb_image
run: cd fuzzers/libfuzzer_stb_image && cargo build --release
windows-frida-gdiplus:
runs-on: windows-latest
needs:
- common
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/windows-tester-prepare
- name: Build fuzzers/frida_gdiplus
run: cd fuzzers/frida_gdiplus/ && cargo make test && cargo make test_cmplog
windows-tinyinst-simple:
runs-on: windows-latest
needs:
- common
steps:
- uses: actions/checkout@v3
- uses: ./.github/workflows/windows-tester-prepare
- name: install cxx bridge
run: cargo install cxxbridge-cmd
- name: Build fuzzers/tinyinst_simple
run: cd fuzzers/tinyinst_simple/ && cargo make test
windows-clippy:
runs-on: windows-latest
needs:
- common
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: actions/checkout@v3
- uses: ./.github/workflows/windows-tester-prepare
- uses: Swatinem/rust-cache@v2
- name: Run real clippy, not the fake one
shell: pwsh
run: .\scripts\clippy.ps1
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
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Add nightly clippy
run: rustup toolchain install nightly --component clippy --allow-downgrade && rustup default nightly
- name: Install deps
run: brew install z3 gtk+3
- name: Install cxxbridge
run: cargo install cxxbridge-cmd
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: MacOS Build
run: cargo build --verbose
- name: Increase map sizes
run: ./scripts/shmem_limits_macos.sh
- name: Run Tests
run: cargo test
- name: Clippy
run: cargo +nightly clippy --tests --all --exclude libafl_nyx --exclude symcc_runtime --exclude runtime_test
other_targets:
ios:
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
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: install ios
run: rustup target add aarch64-apple-ios
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Build iOS
run: cargo build --target aarch64-apple-ios && cd libafl_frida && cargo build --target aarch64-apple-ios && cd ..
android:
runs-on: ubuntu-22.04
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: nttld/setup-ndk@v1
with:
ndk-version: r25b
- 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 Android
run: cd libafl && cargo ndk -t arm64-v8a build --release
#run: cargo build --target aarch64-linux-android
# TODO: Figure out how to properly build stuff with clang
#- name: Add clang path to $PATH env
@ -298,34 +552,34 @@ jobs:
# run: C:\Rust\.cargo\bin\cargo.exe test --verbose
freebsd:
runs-on: macos-12
runs-on: ubuntu-22.04
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
- uses: actions/checkout@v3
- name: Test in FreeBSD
id: test
uses: vmactions/freebsd-vm@v1
with:
usesh: true
sync: rsync
copyback: false
mem: 2048
release: 13.2
prepare: |
pkg install -y curl bash sudo llvm16
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
run: |
freebsd-version
. "$HOME/.cargo/env"
rustup toolchain install nightly
export LLVM_CONFIG=/usr/local/bin/llvm-config16
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

View File

@ -0,0 +1,65 @@
name: Setup Rust Environment
description: Sets up the Rust environment for the CI workflow
runs:
using: composite
steps:
- uses: actions/checkout@v3
with:
submodules: true
fetch-depth: 0
- uses: Swatinem/rust-cache@v2
with: { shared-key: "${{ runner.os }}-shared-fuzzer-cache" }
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Add stable clippy
shell: bash
run: rustup toolchain install stable --component clippy --allow-downgrade
- name: Add nightly clippy
shell: bash
run: rustup toolchain install nightly --component clippy --allow-downgrade
- name: Add no_std toolchain
shell: bash
run: rustup toolchain install nightly-x86_64-unknown-linux-gnu ; rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
- name: Add wasm target
shell: bash
run: rustup target add wasm32-unknown-unknown
- name: Remove obsolete llvm (Linux)
if: runner.os == 'Linux'
shell: bash
run: sudo apt purge -y llvm* clang*
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
directory: ${{ runner.temp }}/llvm
version: 17
- name: Install deps
shell: bash
run: sudo apt update && sudo apt install -y nasm nlohmann-json3-dev ninja-build gcc-arm-linux-gnueabi g++-arm-linux-gnueabi gcc-aarch64-linux-gnu g++-aarch64-linux-gnu gcc-mipsel-linux-gnu g++-mipsel-linux-gnu gcc-powerpc-linux-gnu g++-powerpc-linux-gnu libc6-dev-i386-cross libc6-dev libc6-dev-i386 lib32gcc-11-dev lib32stdc++-11-dev libgtk-3-dev pax-utils libz3-dev
- name: pip install
shell: bash
run: python3 -m pip install msgpack jinja2 find_libpython
- name: enable mult-thread for `make`
shell: bash
run: export MAKEFLAGS="-j$(expr $(nproc) \+ 1)"
- name: install cargo-make
uses: baptiste0928/cargo-install@v1.3.0
with:
crate: cargo-make
- name: install wasm-pack
uses: baptiste0928/cargo-install@v1.3.0
with:
crate: wasm-pack
- name: install cxxbridge-cmd
uses: baptiste0928/cargo-install@v1.3.0
with:
crate: cxxbridge-cmd
- name: install chrome
uses: browser-actions/setup-chrome@v1
with:
chrome-version: stable
- name: Symlink Headers
if: runner.os == 'Linux'
shell: bash
run: sudo ln -s /usr/include/asm-generic /usr/include/asm

View File

@ -0,0 +1,47 @@
name: Setup QEMU Fuzzers environment
description: Sets up the QEMU fuzzers environment
runs:
using: composite
steps:
- uses: actions/checkout@v3
with:
submodules: true
fetch-depth: 0
- name: Install deps
shell: bash
run: apt update && apt install -y nasm ninja-build libc6-dev libgtk-3-dev pax-utils libz3-dev wget qemu-utils libsqlite3-dev gcc-arm-none-eabi sudo gcc g++ build-essential gcc-arm-linux-gnueabi g++-arm-linux-gnueabi
- uses: Swatinem/rust-cache@v2
with: { shared-key: "${{ runner.os }}-shared-fuzzer-cache" }
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Add stable clippy
shell: bash
run: rustup toolchain install stable --component clippy --allow-downgrade
- name: Add nightly clippy
shell: bash
run: rustup toolchain install nightly --component clippy --allow-downgrade
- name: Remove obsolete llvm (Linux)
if: runner.os == 'Linux'
shell: bash
run: sudo apt purge -y llvm* clang*
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
directory: ${{ runner.temp }}/llvm
version: 17
- name: pip install
shell: bash
run: python3 -m pip install msgpack jinja2 find_libpython
- name: enable mult-thread for `make`
shell: bash
run: export MAKEFLAGS="-j$(expr $(nproc) \+ 1)"
- name: install cargo-make
uses: baptiste0928/cargo-install@v1.3.0
with:
crate: cargo-make
- name: Symlink Headers
if: runner.os == 'Linux'
shell: bash
run: sudo ln -s /usr/include/asm-generic /usr/include/asm

View File

@ -0,0 +1,27 @@
name: Setup Rust Environment
description: Sets up the Rust environment for the CI workflow
runs:
using: composite
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
components: llvm-tools
- name: Remove existing clang and LLVM
shell: bash
run: sudo apt purge llvm* clang*
- name: Install and cache deps
shell: bash
run: sudo apt update && sudo apt install ninja-build clang-format shellcheck libgtk-3-dev gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libslirp-dev libz3-dev
- name: Install cargo-hack
shell: bash
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
shell: bash
run: rustup toolchain install nightly --allow-downgrade
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
directory: ${{ runner.temp }}/llvm
version: 17

View File

@ -0,0 +1,21 @@
name: Setup Rust Environment
description: Sets up the Rust environment for the CI workflow
runs:
using: composite
steps:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2
- name: Build docs
shell: pwsh
run: cargo doc
- uses: ilammy/msvc-dev-cmd@v1
- name: Set LIBCLANG_PATH
shell: pwsh
run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV
- name: install cargo-make
shell: pwsh
run: cargo install --force cargo-make

23
.gitignore vendored
View File

@ -21,6 +21,8 @@ vendor
*.obj
.cur_input
.cur_input_*
cur_input
.venv
crashes
@ -32,6 +34,8 @@ perf.data.old
.vscode
test.dict
.idea/
# Ignore all built fuzzers
fuzzer_*
AFLplusplus
@ -46,6 +50,7 @@ a
forkserver_test
__pycache__
*.lafl_lock
*.metadata
*atomic_file_testfile*
**/libxml2
@ -53,4 +58,20 @@ __pycache__
**/libxml2-*.tar.gz
libafl_nyx/QEMU-Nyx
libafl_nyx/packer
libafl_nyx/packer
.z3-trace
# No gdb history
.gdb_history
# No llvm IR
*.ll
*.tar.gz
# common harness names
harness
program
fuzzer
fuzzer_libpng*
forkserver_simple

3
.gitmodules vendored
View File

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

9
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,9 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: local
hooks:
- id: fmt
name: fmt
entry: scripts/fmt_all.sh check
language: script

18
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,18 @@
# How to Contribute to LibAFL
For bugs, feel free to open issues or contact us directly. Thank you for your support. <3
## Pull Request guideline
Even though we will gladly assist you in finishing up your PR, try to
- 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 +nightly fmt` on your code before pushing
- 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.
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.
### Pre-commit hooks
Some of these checks can be performed automatically during commit using [pre-commit](https://pre-commit.com/).
Once the package is installed, simply run `pre-commit install` to enable the hooks, the checks will run automatically before the commit becomes effective.

View File

@ -1,42 +1,49 @@
[workspace]
resolver = "2"
members = [
"libafl",
"libafl_derive",
"libafl_bolts",
"libafl_cc",
"libafl_targets",
"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",
"libafl_derive",
"libafl_frida",
"libafl_libfuzzer",
"libafl_nyx",
"libafl_qemu",
"libafl_sugar",
"libafl_targets",
"libafl_tinyinst",
"utils/build_and_test_fuzzers",
"utils/deexit",
"utils/gramatron/construct_automata",
"utils/libafl_benches",
"utils/gramatron/construct_automata",
]
default-members = [
"libafl",
"libafl_derive",
"libafl_bolts",
"libafl_cc",
"libafl_derive",
"libafl_targets",
]
exclude = [
"fuzzers",
"bindings",
"scripts",
"fuzzers",
"libafl_qemu/libafl_qemu_build",
"libafl_qemu/libafl_qemu_sys"
"libafl_qemu/libafl_qemu_sys",
"utils/noaslr",
"utils/gdb_qemu",
"utils/libafl_fmt",
"scripts",
]
[workspace.package]
version = "0.8.2"
version = "0.13.0"
[profile.release]
lto = true
codegen-units = 1
opt-level = 3
debug = true

View File

@ -1,10 +1,10 @@
# syntax=docker/dockerfile:1.2
FROM rust:bullseye AS libafl
FROM rust:1.76.0 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
RUN cargo install --locked sccache
ENV HOME=/root
ENV SCCACHE_CACHE_SIZE="1G"
@ -16,10 +16,18 @@ RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' \
mkdir ~/.cargo && \
echo "[build]\nrustc-wrapper = \"${RUSTC_WRAPPER}\"" >> ~/.cargo/config
RUN rustup default nightly
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
# Install clang 18, common build tools
ENV LLVM_VERSION=18
RUN apt update && apt install -y build-essential gdb git wget python3-venv ninja-build lsb-release software-properties-common gnupg cmake
# Workaround until https://github.com/llvm/llvm-project/issues/62475 is resolved
RUN set -ex &&\
echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-${LLVM_VERSION} main" > /etc/apt/sources.list.d/apt.llvm.org.list &&\
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc &&\
apt update &&\
apt-get install -y clang-${LLVM_VERSION} lldb-${LLVM_VERSION} lld-${LLVM_VERSION} clangd-${LLVM_VERSION} clang-tidy-${LLVM_VERSION} clang-format-${LLVM_VERSION} clang-tools-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev lld-${LLVM_VERSION} lldb-${LLVM_VERSION} llvm-${LLVM_VERSION}-tools libomp-${LLVM_VERSION}-dev libc++-${LLVM_VERSION}-dev libc++abi-${LLVM_VERSION}-dev libclang-common-${LLVM_VERSION}-dev libclang-${LLVM_VERSION}-dev libclang-cpp${LLVM_VERSION}-dev libunwind-${LLVM_VERSION}-dev libclang-rt-${LLVM_VERSION}-dev libpolly-${LLVM_VERSION}-dev
# Copy a dummy.rs and Cargo.toml first, so that dependencies are cached
WORKDIR /libafl
@ -28,21 +36,24 @@ 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 libafl/Cargo.toml libafl/build.rs libafl/README.md libafl/
COPY scripts/dummy.rs libafl/src/lib.rs
COPY libafl_bolts/Cargo.toml libafl_bolts/build.rs libafl_bolts/README.md libafl_bolts/
COPY libafl_bolts/examples libafl_bolts/examples
COPY scripts/dummy.rs libafl_bolts/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 libafl_qemu/Cargo.toml libafl_qemu/build.rs libafl_qemu/build_linux.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 libafl_qemu/libafl_qemu_sys/Cargo.toml libafl_qemu/libafl_qemu_sys/build.rs libafl_qemu/libafl_qemu_sys/build_linux.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/
@ -69,12 +80,16 @@ 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 libafl_nyx/Cargo.toml libafl_nyx/build.rs libafl_nyx/build_nyx_support.sh 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
# avoid pulling in the runtime, as this is quite an expensive build, until later
COPY libafl_libfuzzer/Cargo.toml libafl_libfuzzer/
COPY scripts/dummy.rs libafl_libfuzzer/src/lib.rs
COPY utils utils
RUN cargo build && cargo build --release
@ -95,6 +110,8 @@ 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_bolts/src libafl_bolts/src
RUN touch libafl_bolts/src/lib.rs
COPY libafl/src libafl/src
RUN touch libafl/src/lib.rs
COPY libafl_targets/src libafl_targets/src
@ -104,6 +121,8 @@ 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
COPY libafl_qemu/runtime libafl_qemu/runtime
COPY libafl_qemu/libqasan libafl_qemu/libqasan
RUN touch libafl_qemu/src/lib.rs
COPY libafl_qemu/src libafl_qemu/src
RUN touch libafl_frida/src/lib.rs
@ -112,11 +131,16 @@ 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
COPY libafl_libfuzzer/src libafl_libfuzzer/src
COPY libafl_libfuzzer/libafl_libfuzzer_runtime libafl_libfuzzer/libafl_libfuzzer_runtime
COPY libafl_libfuzzer/build.rs libafl_libfuzzer/build.rs
RUN touch libafl_libfuzzer/src/lib.rs
RUN cargo build && cargo build --release
# Copy fuzzers over
COPY fuzzers fuzzers
# RUN ./scripts/test_all_fuzzers.sh --no-fmt
# RUN ./scripts/test_fuzzer.sh --no-fmt
ENTRYPOINT [ "/bin/bash" ]
ENTRYPOINT [ "/bin/bash", "-c" ]
CMD ["/bin/bash"]

View File

@ -1,6 +1,6 @@
# LibAFL, the fuzzer library.
<img align="right" src="https://github.com/AFLplusplus/Website/raw/master/static/logo_256x256.png" alt="AFL++ Logo">
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/libafl_logo.svg" alt="LibAFL logo" width="250" heigh="250">
Advanced Fuzzing Library - Slot your own fuzzers together and extend their features using Rust.
@ -10,6 +10,7 @@ LibAFL is written and maintained by
* [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>
* [Addison Crump](https://github.com/addisoncrump) <me@addisoncrump.info>
## Why LibAFL?
@ -33,7 +34,7 @@ LibAFL offers integrations with popular instrumentation frameworks. At the momen
+ SanitizerCoverage, in [libafl_targets](./libafl_targets)
+ Frida, in [libafl_frida](./libafl_frida)
+ QEMU user-mode, in [libafl_qemu](./libafl_qemu)
+ QEMU user-mode and system mode, including hooks for emulation, in [libafl_qemu](./libafl_qemu)
+ TinyInst, in [libafl_tinyinst](./libafl_tinyinst) by [elbiazo](https://github.com/elbiazo)
## Getting started
@ -44,36 +45,39 @@ We highly recommend *not* to use e.g. your Linux distribition package as this is
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)
The LLVM tools (including clang, clang++) are needed (newer than LLVM 15.0.0 up to LLVM 18.1.3)
If you are using Debian/Ubuntu, again, we highly recommmend that you install the package from [here](https://apt.llvm.org/)
(In `libafl_concolic`, we only support LLVM version newer than 18)
- Cargo-make
We use cargo-make to build the fuzzers in `fuzzers/` directory. You can install it with
```
```sh
cargo install cargo-make
```
2. Clone the LibAFL repository with
```
```sh
git clone https://github.com/AFLplusplus/LibAFL
```
3. Build the library using
```
```sh
cargo build --release
```
4. Build the API documentation with
```
```sh
cargo doc
```
5. Browse the LibAFL book (WIP!) with (requires [mdbook](https://github.com/rust-lang/mdBook))
5. Browse the LibAFL book (WIP!) with (requires [mdbook](https://rust-lang.github.io/mdBook/index.html))
```
```sh
cd docs && mdbook serve
```
@ -81,9 +85,11 @@ We collect all example fuzzers in [`./fuzzers`](./fuzzers/).
Be sure to read their documentation (and source), this is *the natural way to get started!*
You can run each example fuzzer with
```
```sh
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.
@ -106,17 +112,11 @@ The best-tested fuzzer is [`./fuzzers/libfuzzer_libpng`](./fuzzers/libfuzzer_lib
+ 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).
+ [A LibAFL Introductory Workshop](https://www.atredis.com/blog/2023/12/4/a-libafl-introductory-workshop), by [Jordan Whitehead](https://github.com/jordan9001)
## Contributing
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
- 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
- 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.
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.
Please check out [CONTRIBUTING.md](CONTRIBUTING.md) for the contributing guideline.
## Cite
@ -149,11 +149,3 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
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.
</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>

17
TROPHIES.md Normal file
View File

@ -0,0 +1,17 @@
# Bugs found by `libafl` and `libafl_libfuzzer`
* pdf-rs
* <https://github.com/pdf-rs/pdf/issues/183>
* <https://github.com/pdf-rs/pdf/issues/184>
* <https://github.com/pdf-rs/pdf/issues/185>
* <https://github.com/pdf-rs/pdf/issues/186>
* <https://github.com/pdf-rs/pdf/issues/187>
* <https://github.com/pdf-rs/pdf/issues/189>
* nu-shell
* https://github.com/nushell/nushell/issues/10365
* https://github.com/nushell/nushell/issues/9417
* exrs
* https://github.com/johannesvollmer/exrs/pull/221
* pcre2
* https://github.com/PCRE2Project/pcre2/issues/275

1
bindings/pylibafl/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
dist/

View File

@ -1,13 +1,16 @@
[package]
name = "pylibafl"
version = "0.8.2"
version = "0.13.0"
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"] }
pyo3 = { version = "0.18.3", features = ["extension-module"] }
pyo3-log = "0.8.1"
libafl_sugar = { path = "../../libafl_sugar", version = "0.13.0", features = ["python"] }
libafl_bolts = { path = "../../libafl_bolts", version = "0.13.0", features = ["python"] }
[target.'cfg(target_os = "linux")'.dependencies]
libafl_qemu = { path = "../../libafl_qemu", version = "0.13.0", features = ["python"] }
[build-dependencies]
pyo3-build-config = { version = "0.17" }

View File

@ -0,0 +1,26 @@
[build-system]
requires = ["maturin[patchelf]>=0.14.10,<0.15"]
build-backend = "maturin"
[project]
name = "PyLibAFL"
version = "0.10.1"
description = "Advanced Fuzzing Library for Python"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "Apache-2.0"}
classifiers = [
"License :: OSI Approved :: Apache Software License",
"License :: OSI Approved :: MIT License",
"Programming Language :: Rust",
"Topic :: Security",
]
[project.urls]
repository = "https://github.com/AFLplusplus/LibAFL.git"
[tool.maturin]
bindings = "pylibafl"
manifest-path = "Cargo.toml"
python-source = "python"
all-features = true

View File

@ -1,121 +1,33 @@
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()
"#;
use pyo3::prelude::*;
/// Setup python modules for `libafl_qemu` and `libafl_sugar`.
///
/// # Errors
/// Returns error if python libafl setup failed.
#[pymodule]
#[pyo3(name = "pylibafl")]
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
pyo3_log::init();
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)?;
{
let qemu_module = PyModule::new(py, "qemu")?;
libafl_qemu::python_module(py, qemu_module)?;
m.add_submodule(qemu_module)?;
modules.set_item("pylibafl.qemu", qemu_module)?;
}
m.add_submodule(libafl_module)?;
modules.set_item("pylibafl.libafl", libafl_module)?;
let bolts_module = PyModule::new(py, "libafl_bolts")?;
libafl_bolts::pybind::python_module(py, bolts_module)?;
m.add_submodule(bolts_module)?;
modules.set_item("pylibafl.libafl_bolts", bolts_module)?;
Ok(())
}

View File

@ -1,94 +1,7 @@
from pylibafl.libafl import *
import pylibafl.sugar as sugar
import ctypes
import platform
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)
print("Starting to fuzz from python!")
fuzzer = sugar.InMemoryBytesCoverageSugar(input_dirs=["./in"], output_dir="out", broker_port=1337, cores=[0,1])
fuzzer.run(lambda b: print("foo"))

14
bindings/pylibafl/test.sh Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
mkdir in || true
echo "a" > ./in/a
timeout 10 python3 ./test.py
export exit_code=$?
if [ $exit_code -eq 124 ]; then
# 124 = timeout happened. All good.
exit 0
else
exit $exit_code
fi

1
docs/.gitignore vendored
View File

@ -1 +1,2 @@
book
!listings/**/*

View File

@ -0,0 +1,9 @@
[package]
name = "baby_fuzzer_listing_01"
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]

View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@ -0,0 +1,21 @@
[package]
name = "baby_fuzzer_listing_02"
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/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true

View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@ -0,0 +1,24 @@
[package]
name = "baby_fuzzer_listing_03"
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/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[features]
panic = []

View File

@ -0,0 +1,26 @@
extern crate libafl;
extern crate libafl_bolts;
use libafl::{
executors::ExitKind,
inputs::{BytesInput, HasTargetBytes},
};
use libafl_bolts::AsSlice;
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);
}

View File

@ -0,0 +1,24 @@
[package]
name = "baby_fuzzer_listing_04"
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/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[features]
panic = []

View File

@ -0,0 +1,87 @@
/* ANCHOR: use */
extern crate libafl;
extern crate libafl_bolts;
use std::path::PathBuf;
use libafl::{
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
fuzzer::StdFuzzer,
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
schedulers::QueueScheduler,
state::StdState,
};
use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice};
/* ANCHOR_END: use */
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);
/* ANCHOR: state */
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::new(),
// 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();
/* ANCHOR_END: state */
/* ANCHOR: event_manager */
// The Monitor trait defines how the fuzzer stats are displayed to the user
let mon = SimpleMonitor::new(|s| println!("{s}"));
// The event manager handles 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);
/* ANCHOR_END: event_manager */
/* ANCHOR: scheduler_fuzzer */
// A queue policy to get testcases from the corpus
let scheduler = QueueScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, (), ());
/* ANCHOR_END: scheduler_fuzzer */
/* ANCHOR: executor */
// 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");
/* ANCHOR_END: executor */
/* ANCHOR: generator */
// 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");
/* ANCHOR_END: generator */
}

View File

@ -0,0 +1,23 @@
[package]
name = "baby_fuzzer_listing_05"
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
[features]
panic = []

View File

@ -0,0 +1,116 @@
/* ANCHOR: use */
extern crate libafl;
extern crate libafl_bolts;
use libafl::{
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::StdFuzzer,
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
observers::StdMapObserver,
schedulers::QueueScheduler,
state::StdState,
};
use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice};
use std::path::PathBuf;
/* ANCHOR_END: use */
/* ANCHOR: signals */
// 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 };
}
fn main() {
// 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
};
/* ANCHOR_END: signals */
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
harness(&input);
/* ANCHOR: observer */
// Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::new("signals", &mut SIGNALS) };
/* ANCHOR_END: observer */
/* ANCHOR: state_with_feedback_and_objective */
// 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::new(),
// 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();
/* ANCHOR_END: state_with_feedback_and_objective */
// The Monitor trait defines how the fuzzer stats are displayed to the user
let mon = SimpleMonitor::new(|s| println!("{s}"));
// The event manager handles 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);
// A queue policy to get testcasess from the corpus
let scheduler = QueueScheduler::new();
/* ANCHOR: state_with_feedback_and_objective */
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
/* ANCHOR_END: state_with_feedback_and_objective */
/* ANCHOR: executor_with_observer */
// 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");
/* ANCHOR_END: executor_with_observer */
// 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");
/* ANCHOR: signals */
}
/* ANCHOR_END: signals */

View File

@ -0,0 +1,24 @@
[package]
name = "baby_fuzzer_listing_06"
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/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[features]
panic = []

View File

@ -0,0 +1,116 @@
/* ANCHOR: use */
extern crate libafl;
extern crate libafl_bolts;
use libafl::{
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer},
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
observers::StdMapObserver,
schedulers::QueueScheduler,
stages::mutational::StdMutationalStage,
state::StdState,
};
use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice};
use std::path::PathBuf;
/* ANCHOR_END: use */
// 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 };
}
fn main() {
// 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
};
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
harness(&input);
// Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::new("signals", &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::new(),
// 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();
// The Monitor trait defines how the fuzzer stats are displayed to the user
let mon = SimpleMonitor::new(|s| println!("{s}"));
// The event manager handles 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);
// 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");
// 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");
/* ANCHOR: mutational_stage */
// 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");
/* ANCHOR_END: mutational_stage */
}

32
docs/src/DEBUGGING.md Normal file
View File

@ -0,0 +1,32 @@
# General debugging tips
This file answers some commmon questions that arise when you are writing a fuzzer using LibAFL.
## Q. My fuzzer crashed but the stack trace is useless.
You can enable the `errors_backtrace` feature of the `libafl` crate. With this the stacktrace is meaningful.
## Q. I started the fuzzer but the corpus count is 0.
Unless the initial corpus is loaded with the "load_initial_inputs_forced" function, we only store the interesting inputs, which is the inputs that triggered the feedback. So this usually means that your input was not interesting or your target was simply not properly implemented.
Either way, what you can do is attach to the executable with gdb and set a breakpoint at where the new edges should be reported. If no instrumentation code is executed, then the the problem is in the instrumentation. If the instrumentation code is hit, but still the your input is not instrumented, then the problem could be that you are not passign the observer/feedback correctly to the fuzzer.
## Q. I started the fuzzer but the coverage is 0.
This could mean two things. Perhaps your target was not properly instrumented, or you are not using the correct observer, feedback feature.
In this case, again, what usually should do is to run the fuzzer with gdb and set a breakpoint at where the coverage is recorded (e.g. __sanitizer_coverage_trace_pcguard), and validate that the target is giving the feedback to the fuzzer.
## Q. I started the fuzzer but there's no output.
First, verify that your stdout and stderr are not redirected to `/dev/null`. If you get the log, then it should either fall into the previous 2 cases. Either the fuzzer crashed because you didn't have the initial seeds, or the coverage feedback is not working.
## Q. My fuzzer is slow.
Try running the fuzzer with the `introspection` feature of the `libafl`. This will show how much time is spent on each module of your fuzzer. Also you might be using a wrong size of the coverage map. If you see `2621440` for the size of the coverage map, you are doing it wrong. One possible mistake is the misuse of `libafl_targets::coverage::EDGES_MAP`
```
let map = StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP.len());
```
You should *never* use the `EDGES_MAP`'s size as this is just the size of the allocated size of the coverage map. Consider using something smaller or our default value `libafl_targets::LIBAFL_EDGES_MAP_SIZE_IN_USE`.
## Q. I still have problems with my fuzzer.
Finally, if you really have no idea what is going on, run your fuzzer with logging enabled. (You can use `env_logger`, `SimpleStdoutLogger`, `SimpleStderrLogger` from `libafl_bolts`. `fuzzbench_text` has an example to show how to use it.) (Don't forget to enable stdout and stderr), and you can open an issue or ask us in Discord.
## Q. My fuzzer died of ``Storing state in crashed fuzzer instance did not work''.
If the exit code is zero, then this is because either your harness exited or you are using fuzzer_loop_for and forgot to add `mgr.on_restart` at the end of the fuzzer. In the first case, you should patch your harness not to exit. (or use `utils/deexit`).
## Q. I can't leave the TUI screen
Type `q` then you leave TUI.

View File

@ -25,6 +25,7 @@
- [Architecture](./design/architecture.md)
- [Metadata](./design/metadata.md)
- [Migrating from LibAFL <0.9 to 0.9](./design/migration-0.9.md)
- [Migrating from LibAFL <0.11 to 0.11](./design/migration-0.11.md)
- [Message Passing](./message_passing/message_passing.md)
- [Spawning Instances](./message_passing/spawn_instances.md)

View File

@ -1,7 +1,8 @@
# 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.
For those uninitiated, the following text 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.
@ -92,18 +93,18 @@ In hybrid fuzzing, we combine this tracing + solving approach with more traditio
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.
These callbacks allow the runtime to construct a trace that is similar to the previous example.
### SymCC and its Runtimes
SymCC ships with 2 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.
* A 'simple' runtime that attempts to negate and analytically solve any branch conditions 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 them 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.
Check out the `symcc_runtime` docs for more information on how to build your own runtime.
### SymQEMU
@ -123,7 +124,7 @@ There are three main steps involved with building a hybrid fuzzer using LibAFL:
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.
For example, we need to have a runtime ready before we can do instrumentation with SymCC.
### Building a Runtime
@ -134,10 +135,12 @@ Check out the [example hybrid fuzzer's runtime](https://github.com/AFLplusplus/L
### Instrumentation
There are two main instrumentation methods to make use of concolic tracing in LibAFL:
* Using an **compile-time** instrumented target with **SymCC**.
* Using a **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.
This avoids building a separate instrumented target with concolic tracing instrumentation and so 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.
@ -158,25 +161,25 @@ Make sure you satisfy the [build requirements](https://github.com/eurecom-s3/sym
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.
Since we don't have a runtime there, we need to explicitly set the `--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.
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 its 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).
You can use the [`CommandExecutor`](https://docs.rs/libafl/latest/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 (set to 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).
This serialized representation can be deserialized in the fuzzer process for solving using a [`ConcolicObserver`](https://docs.rs/libafl/latest/libafl/observers/concolic/struct.ConcolicObserver.html) wrapped in a [`ConcolicTracingStage`](https://docs.rs/libafl/latest/libafl/stages/concolic/struct.ConcolicTracingStage.html), which will attach a [`ConcolicMetadata`](https://docs.rs/libafl/latest/libafl/observers/concolic/struct.ConcolicMetadata.html) to every [`TestCase`](https://docs.rs/libafl/latest/libafl/corpus/testcase/struct.Testcase.html).
The `ConcolicMetadata` can be used to replay the concolic trace and solved using an SMT-Solver.
The `ConcolicMetadata` can be used to replay the concolic trace and to solve the conditions 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.
The [`SimpleConcolicMutationalStage`](https://docs.rs/libafl/latest/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

View File

@ -17,7 +17,7 @@ If you are on Windows, you'll need to install llvm tools.
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:
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();
@ -28,9 +28,9 @@ For example in our `frida_libpng` example, we load the dynamic library and find
## `FridaInstrumentationHelper` and Runtimes
To use functionalities that Frida offers, we'll first need to obtain `Gum` object by `Gum::obtain()`.
To use functionalities that Frida offers, we'll first need to obtain a `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.
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 instrumentations.
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.
@ -53,12 +53,12 @@ Combined with any `Runtime` you'd like to use, you can initialize the `FridaInst
## Running the Fuzzer
After setting up the `FridaInstrumentationHelper`. You can obtain the pointer to the coverage map by calling `map_ptr_mut()`.
After setting up the `FridaInstrumentationHelper` you can obtain the pointer to the coverage map by calling `map_mut_ptr()`.
```rust,ignore
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr(
let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr(
"edges",
frida_helper.map_ptr_mut().unwrap(),
frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE,
));
```
@ -73,7 +73,7 @@ You can then link this observer to `FridaInProcessExecutor` as follows:
tuple_list!(
edges_observer,
time_observer,
AsanErrorsObserver::new(&ASAN_ERRORS)
AsanErrorsObserver::from_static_asan_errors()
),
&mut fuzzer,
&mut state,
@ -83,5 +83,5 @@ You can then link this observer to `FridaInProcessExecutor` as follows:
);
```
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.
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

@ -1,6 +1,6 @@
# 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.
It is possible to use LibAFL in `no_std` environments e.g. on custom platforms like microcontrollers, kernels, hypervisors, and more.
You can simply add LibAFL to your `Cargo.toml` file:
@ -16,7 +16,7 @@ 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.
The minimum amount of support LibAFL needs for a `no_std` environment 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

View File

@ -2,12 +2,12 @@
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:
Currently, `libafl_nyx` only supports [afl++](https://github.com/AFLplusplus/AFLplusplus)'s instruction type. 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
make all # this will not compile afl's additional extensions
```
Then you should compile the target with the afl++ compiler wrapper:
@ -20,9 +20,9 @@ export CXX=afl-clang-fast++
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>.
For binary-only fuzzing, Nyx uses intel-PT(Intel® Processor Trace). You can find the list of supported CPUs at <https://www.intel.com/content/www/us/en/support/articles/000056730/processors.html>.
## Preparing Nyx working directory
## Preparing the 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):
@ -49,7 +49,7 @@ 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.
In the [example fuzzer](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/nyx_libxml2_standalone/src/main.rs) you first 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 to write your code.
First, to create `Nyxhelper`:
@ -57,22 +57,21 @@ First, to create `Nyxhelper`:
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
let mut helper = NyxHelper::new(share_dir, cpu_id, true, parallel_mode, None).unwrap(); // we don't need to 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 observer = unsafe { StdMapObserver::from_mut_ptr("trace", helper.trace_bits, helper.map_size) };
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.
Finally, use them normally 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.
In the [example fuzzer](https://github.com/AFLplusplus/LibAFL/blob/main/fuzzers/nyx_libxml2_parallel/src/main.rs) you first 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`:
@ -91,7 +90,7 @@ let mut helper = NyxHelper::new(
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
Some(parent_cpu_id.id as u32), // the cpu-id of main instance, there is only one main instance, other instances will be treated as secondaries
)
.unwrap();
```
@ -99,13 +98,11 @@ let mut helper = NyxHelper::new(
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 observer = unsafe { StdMapObserver::from_mut_ptr("trace", helper.trace_bits, helper.map_size) }
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
```
Finally, open a `Launcher` as normal to start fuzzing:
Finally, open a `Launcher` as usual to start fuzzing:
```rust,ignore
match Launcher::builder()
@ -121,6 +118,6 @@ match Launcher::builder()
{
Ok(()) => (),
Err(Error::ShuttingDown) => println!("Fuzzing stopped by user. Good bye."),
Err(err) => panic!("Failed to run launcher: {:?}", err),
Err(err) => panic!("Failed to run launcher: {err:?}"),
}
```

View File

@ -17,7 +17,7 @@ You can find a complete version of this tutorial as an example fuzzer in [`fuzze
We use cargo to create a new Rust project with LibAFL as a dependency.
```sh
```console
$ cargo new baby_fuzzer
$ cd baby_fuzzer
```
@ -25,18 +25,11 @@ $ 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]
{{#include ../../listings/baby_fuzzer/listing-01/Cargo.toml}}
```
In order to use LibAFl we must add it as dependency adding `libafl = { path = "path/to/libafl/" }` under `[dependencies]`.
That path actually needs to point to the `libafl` directory within the cloned repo, not the root of the repo itself.
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.
@ -47,28 +40,10 @@ Alongside this setting, we add some optimization flags for the compilation, when
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
{{#include ../../listings/baby_fuzzer/listing-02/Cargo.toml}}
```
## The function under test
Opening `src/main.rs`, we have an empty `main` function.
@ -76,52 +51,32 @@ To start, we create the closure that we want to fuzz. It takes a buffer as input
`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);
}
{{#rustdoc_include ../../listings/baby_fuzzer/listing-03/src/main.rs}}
```
To test the crash manually, you can add a feature in `Cargo.toml` that enables the call that triggers the panic:
```toml
{{#include ../../listings/baby_fuzzer/listing-03/Cargo.toml:23:25}}
```
And then run the program with that feature activated:
```console
$ cargo run -F panic
```
And you should see the program crash as expected.
## 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.
One of the main components that a LibAFL-based fuzzer uses is the State, a container of the data that will evolve during the fuzzing process.
It 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();
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-04/src/main.rs:state}}
```
- 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.
@ -129,43 +84,26 @@ let mut state = StdState::new(
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.
- The 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.
- The 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);
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-04/src/main.rs:event_manager}}
```
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, (), ());
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-04/src/main.rs:scheduler_fuzzer}}
```
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");
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-04/src/main.rs:executor}}
```
It takes a reference to the harness, the state, and the event manager. We will discuss the second parameter later.
@ -175,41 +113,19 @@ Now we have the 4 major entities ready for running our tests, but we still canno
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());
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-04/src/main.rs:generator}}
```
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,
};
{{#rustdoc_include ../../listings/baby_fuzzer/listing-04/src/main.rs:use}}
```
When running, you should see something similar to:
```sh
```console
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/baby_fuzzer`
@ -225,60 +141,22 @@ Now we want to turn our simple fuzzer into a feedback-based one and increase the
**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:
As we don't rely on any instrumentation engine, we have to manually track the satisfied conditions by `signals_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
};
{{#rustdoc_include ../../listings/baby_fuzzer/listing-05/src/main.rs:signals}}
```
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 });
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-05/src/main.rs:observer}}
```
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());
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-05/src/main.rs:executor_with_observer}}
```
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.
@ -287,49 +165,23 @@ Now that the fuzzer can observe which condition is satisfied, we need a way to r
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.
**Objective Feedback** is another kind of Feedback which decides if an input is a "solution". It will save input to solutions(`./crashes` in our case) rather 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,
};
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-05/src/main.rs:state_with_feedback_and_objective}}
```
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer);
Once again, you need to add the necessary `use` directives for this to work properly:
// 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);
```rust
{{#rustdoc_include ../../listings/baby_fuzzer/listing-05/src/main.rs:use}}
```
## 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.
Now, 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.
@ -337,28 +189,20 @@ For instance, the `MutationalStage` executes the harness several times in a row,
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");
{{#rustdoc_include ../../listings/baby_fuzzer/listing-06/src/main.rs:mutational_stage}}
```
`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.
Again, we need to add the new `use` directives:
```text
```rust,ignore
{{#rustdoc_include ../../listings/baby_fuzzer/listing-06/src/main.rs:use}}
```
After adding this code, we have a proper fuzzer, that can run and find the input that panics the function in less than a second.
```console
$ cargo run
Compiling baby_fuzzer v0.1.0 (/home/andrea/Desktop/baby_fuzzer)
Finished dev [unoptimized + debuginfo] target(s) in 1.56s

View File

@ -9,4 +9,4 @@ Examples can be found under `./fuzzer`.
| 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|
|baby_no_std|a minimalistic example how to create a libafl based fuzzer that works on **`no_std`** environments like TEEs, Kernels or on bare metal|

View File

@ -4,8 +4,8 @@ The Corpus is where testcases are stored. We define a Testcase as an Input and a
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).
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 program under test 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.
Related to the Corpus is the way in which the next testcase (the fuzzer would ask for) is retrieved from the Corpus. The taxonomy for this handling in LibAFL is Scheduler, the entity representing the policy to pop testcases from the Corpus, in a FIFO fashion 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.
Speaking about the code, [`Corpus`](https://docs.rs/libafl/latest/libafl/corpus/trait.Corpus.html) and [`Scheduler`](https://docs.rs/libafl/latest/libafl/schedulers/trait.Scheduler.html) are traits.

View File

@ -9,11 +9,9 @@ So the Executor is for instance responsible to inform the program about the inpu
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.
In Rust, we bind this concept to the [`Executor`](https://docs.rs/libafl/latest/libafl/executors/trait.Executor.html) trait. A structure implementing this trait must implement [`HasObservers`](https://docs.rs/libafl/latest/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.
By default, we implement some commonly used Executors such as [`InProcessExecutor`](https://docs.rs/libafl/latest/libafl/executors/inprocess/type.InProcessExecutor.html) in which the target is a harness function providing in-process crash detection. Another Executor is the [`ForkserverExecutor`](https://docs.rs/libafl/latest/libafl/executors/forkserver/struct.ForkserverExecutor.html) that implements an AFL-like mechanism to spawn child processes to fuzz.
## InProcessExecutor
Let's begin with the base case; `InProcessExecutor`.
@ -24,7 +22,7 @@ When you want to execute the harness as fast as possible, you will most probably
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.
Next, we'll take a look at the `ForkserverExecutor`. In this case, it is `afl-cc` (from AFL/AFLplusplus) that compiles the harness code, and therefore, we can't use `EDGES_MAP` anymore. Fortunately 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 in.
As you can see from the forkserver example,
@ -33,7 +31,7 @@ As you can see from the forkserver example,
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();
let mut shmem_buf = shmem.as_slice_mut();
```
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`.
@ -48,7 +46,7 @@ See AFL++'s [_documentation_](https://github.com/AFLplusplus/AFLplusplus/blob/st
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.
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.
@ -59,9 +57,9 @@ On your fuzzer side, you can allocate a shared memory region and make the `EDGES
```rust,ignore
let mut shmem;
unsafe{
shmem = StdShMemProvider::new().unwrap().new_shmem(MAX_EDGES_NUM).unwrap();
shmem = StdShMemProvider::new().unwrap().new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap();
}
let shmem_buf = shmem.as_mut_slice();
let shmem_buf = shmem.as_slice_mut();
unsafe{
EDGES_PTR = shmem_buf.as_ptr();
}

View File

@ -10,17 +10,25 @@ The concept of "interestingness" is abstract, but typically it is related to a n
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.
In terms of code, the library offers the [`Feedback`](https://docs.rs/libafl/latest/libafl/feedbacks/trait.Feedback.html) trait.
It is used to implement functors that, given the state of the observers from the last execution, tells if the execution was interesting.
So to speak, it reduces the observations to a boolean result of [`is_interesting`](https://docs.rs/libafl/latest/libafl/feedbacks/trait.Feedback.html#tymethod.is_interesting) - or not.
For this, a `Feedback` can store anything it wants to persist in the fuzzers's state.
This might be, for instance, the cumulative map of all edges seen so far, in the case of a feedback based on edge coverage.
This can be achieved by adding `Metadata` in [`init_state`](https://docs.rs/libafl/latest/libafl/feedbacks/trait.Feedback.html#method.init_state) and accessing it later in `is_interesting`.
`Feedback` can also add custom metadata to a newly created [`Testcase`](https://docs.rs/libafl/latest/libafl/corpus/testcase/struct.Testcase.html) using [`append_metadata`](https://docs.rs/libafl/latest/libafl/feedbacks/trait.Feedback.html#method.append_metadata).
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).
Multiple Feedbacks can be combined into a boolean expression, 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/latest/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.
On top, logic operators like `feedback_or` and `feedback_and` have a `_fast` variant (e.g. `feedback_or_fast`) where the second feedback will not be evaluated, if the value of the first feedback operand already answers the `interestingness` question so as 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.
Using `feedback_and_fast` in combination with [`ConstFeedback`](https://docs.rs/libafl/latest/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.
While feedbacks are commonly used to decide if an [`Input`](https://docs.rs/libafl/latest/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 objectives would be a crash or a timeout, but they can also be used to detect if specific parts of the program have been reached, for sanitization, or a differential fuzzing success.
Objectives use the same trait as a normal [`Feedback`](https://docs.rs/libafl/latest/libafl/feedbacks/trait.Feedback.html) and the implementations can be used interchangeably.
The only difference is that `interesting` Objectives won't be mutated further, and are counted as `Solutions`, a successful fuzzing campaign.

View File

@ -6,4 +6,4 @@ 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.
In the code, [`Generator`](https://docs.rs/libafl/latest/libafl/generators/trait.Generator.html) is a trait.

View File

@ -6,10 +6,10 @@ In our model of an abstract fuzzer, we define the Input as the internal represen
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.
But it is not always the case. A program can expect inputs that are not linear byte arrays (e.g. a sequence of syscalls forming a use case or protocol) 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.
In the Rust code, an [`Input`](https://docs.rs/libafl/latest/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).
While most fuzzers use a normal `BytesInput`, more advanced ones use inputs that include special inputs for grammar fuzzing ([GramatronInput](https://docs.rs/libafl/latest/libafl/inputs/gramatron/struct.GramatronInput.html) or `NautilusInput` on Rust nightly), as well as the token-level [EncodedInput](https://docs.rs/libafl/latest/libafl/inputs/encoded/struct.EncodedInput.html).

View File

@ -1,9 +1,9 @@
# Mutator
The Mutator is an entity that takes one or more Inputs and generates a new derived one.
The Mutator is an entity that takes one or more Inputs and generates a new instance of Input derived by its inputs.
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.
There can be, for instance, a Mutator that applies more than a single type of mutation to 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.
In LibAFL, [`Mutator`](https://docs.rs/libafl/latest/libafl/mutators/trait.Mutator.html) is a trait.

View File

@ -4,10 +4,10 @@ An Observer is an entity that provides an information observed during the execut
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.
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 collect the time spent executing a run, the program output, or a more advanced observation, like maximum stack depth at runtime.
This information 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 terms of code, in the library this entity is described by the [`Observer`](https://docs.rs/libafl/latest/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.

View File

@ -1,9 +1,9 @@
# Stage
A Stage is an entity that operates on a single Input got from the Corpus.
A Stage is an entity that operates on a single Input received 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.
For instance, a Mutational Stage, given an input of the corpus, applies a Mutator and executes the generated input one or more times. 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 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.
There are several stages in the LibAFL codebase implementing the [`Stage`](https://docs.rs/libafl/latest/libafl/stages/trait.Stage.html) trait.

View File

@ -8,8 +8,8 @@ The LibAFL code reuse mechanism is based on components, rather than sub-classes,
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 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.
Beside the entities previously described, we introduce the [`Testcase`](https://docs.rs/libafl/latest/libafl/corpus/testcase/struct.Testcase.html) and [`State`](https://docs.rs/libafl/latest/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.
The State, in the implementation, contains only owned objects that are serializable, and it is serializable itself. Some fuzzers may want to serialize their 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).
Additionally, we group the entities that are "actions", like the `CorpusScheduler` and the `Feedbacks`, in a common place, the [`Fuzzer'](https://docs.rs/libafl/latest/libafl/fuzzer/struct.StdFuzzer.html).

View File

@ -5,10 +5,10 @@ A metadata in LibAFL is a self-contained structure that holds associated data to
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;
# extern crate libafl_bolts;
# extern crate serde;
use libafl::SerdeAny;
use libafl_bolts::SerdeAny;
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize, SerdeAny)]
@ -19,15 +19,15 @@ 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);`.
As an alternative to `derive(SerdeAny)` which is a proc-macro in `libafl_derive` the user can use `libafl_bolts::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).
Metadata objects are primarly intended to be used inside [`SerdeAnyMap`](https://docs.rs/libafl_bolts/latest/libafl_bolts/serdeany/serdeany_registry/struct.SerdeAnyMap.html) and [`NamedSerdeAnyMap`](https://docs.rs/libafl_bolts/latest/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.
Structs that want to have a set of metadata must implement the [`HasMetadata`](https://docs.rs/libafl/latest/libafl/state/trait.HasMetadata.html) trait.
By default, Testcase and State implement it and hold a SerdeAnyMap testcase.

View File

@ -0,0 +1,27 @@
# Migrating from LibAFL <0.11 to 0.11
We moved the old `libafl::bolts` module to its own crate called `libafl_bolts`.
For this, imports for types in LibAFL bolts have changed in version 0.11, everything else should remain the same.
## Reasons for This Change
With the change we can now use a lot of low-level features of LibAFL for projects that are unrelated to fuzzing, or just completely different to LibAFL.
Some cross-platform things in bolts include
* SerdeAnyMap: a map that stores and retrieves elements by type and is serializable and deserializable
* ShMem: A cross-platform (Windows, Linux, Android, MacOS) shared memory implementation
* LLMP: A fast, lock-free IPC mechanism via SharedMap
* Core_affinity: A maintained version of `core_affinity` that can be used to get core information and bind processes to cores
* Rands: Fast random number generators for fuzzing (like [RomuRand](http://www.romu-random.org/))
* MiniBSOD: get and print information about the current process state including important registers.
* Tuples: Haskel-like compile-time tuple lists
* Os: OS specific stuff like signal handling, windows exception handling, pipes, and helpers for `fork`
## What changed
You will need to move all `libafl::bolts::` imports to `libafl_bolts:::` and add the crate dependency in your Cargo.toml (and specify feature flags there).
As only exception, the `libafl::bolts::launcher::Launcher` has moved to `libafl::events::launcher::Launcher` since it has fuzzer and `EventManager` specific code.
If you are using `prelude`, you may need to also ad `libafl_bolts::prelude`.
That's it.
Enjoy using `libafl_bolts` in other projects.

View File

@ -0,0 +1,9 @@
# Migrating from <0.12 to 0.12
We deleted `TimeoutExecutor` and `TimeoutForkserverExecutor` and make it mandatory for `InProcessExecutor` and `ForkserverExecutor` to have the timeout. Now `InProcessExecutor` and `ForkserverExecutor` have the default timeout of 5 seconds.
## Reason for This Change.
In 99% of the case, it is advised to have the timeout for the fuzzer. This is because we do not want the fuzzer to stop forever just because the target has hit a path that resulted in a infinite-loop.
## What changed
You do not have to wrap the executor with `TimeoutExecutor` anymore. You can just use `InProcessExecutor::new()` to instantiate the executor with the default timeout or use `InProcessExecutor::timeout(duration)` to start the executor with the customized duration of timeout.

View File

@ -75,7 +75,7 @@ where
```
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
is no longer necessary to explicitly define 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.
@ -101,7 +101,7 @@ See `fuzzers/` for examples of these changes.
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,
In many scenarios, Input, Observer, 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.
@ -127,7 +127,7 @@ where
}
```
After 0.9, all `Corpus` implementations are required to implement `UsesInput` and `Corpus` no longer has a generic for
After 0.9, all `Corpus` implementations are required to implement `UsesInput`. Also `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
@ -160,3 +160,26 @@ Now, `Corpus` cannot be accidentally implemented for another type other than tha
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.
## Observer Changes
Additionally, we changed the Observer API, as the API in 0.8 led to undefined behavior.
At the same time, we used the change to simplify the common case: creating an `StdMapObserver`
from libafl_target's `EDGES_MAP`.
In the future, instead of using:
```rust,ignore
let edges = unsafe { &mut EDGES_MAP[0..EDGES_MAP_SIZE_IN_USE] };
let edges_observer = StdMapObserver::new("edges", edges);
```
creating the edges observer is as simple as using the new `std_edges_map_observer` function.
```rust,ignore
let edges_observer = unsafe { std_edges_map_observer("edges") };
```
Alternatively, `StdMapObserver::new` will still work, but now the whole method is marked as `unsafe`.
The reason is that the caller has to make sure `EDGES_MAP` (or other maps) are not moved or freed in memory,
for the lifetime of the `MapObserver`.
This means that the buffer should either be `static` or `Pin`.

View File

@ -6,7 +6,7 @@ LibAFL, as most of the Rust projects, can be built using `cargo` from the root d
$ cargo build --release
```
Note that the `--release` flag is optional for development, but you needed to add it to fuzzing at a decent speed.
Note that the `--release` flag is optional for development, but you need to add it to do fuzzing at a decent speed.
Slowdowns of 10x or more are not uncommon for Debug builds.
The LibAFL repository is composed of multiple crates.

View File

@ -10,7 +10,7 @@ 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.
For LibAFL, each crate has its self-contained purpose, and the user may not need to use all of them in their project.
Following the naming convention of the folders in the project's root, they are:
### [`libafl`](https://github.com/AFLplusplus/LibAFL/tree/main/libafl)
@ -31,20 +31,35 @@ You can choose the features by using `features = ["feature1", "feature2", ...]`
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
### [`libafl_bolts`](https://github.com/AFLplusplus/LibAFL/tree/main/libafl_bolts)
The `libafl_bolts` crate is a minimal tool shed filled with useful low-level rust features, not necessarily related to fuzzers.
In it, you'll find highlights like:
- `core_affinity` to bind the current process to cores
- `SerdeAnyMap` a map that can store typed values in a serializable fashion
- `minibsod` to dump the current process state
- `LLMP`, "low level message passing", a lock-free IPC mechanism
- `Rand`, different fast (non-cryptographically secure) RNG implementations like RomuRand
- `ShMem`, a platform independent shard memory implementation
- `Tuples`, a compiletime tuple implementation
... and much more.
### [`libafl_sugar`](https://github.com/AFLplusplus/LibAFL/tree/main/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`](https://github.com/AFLplusplus/LibAFL/tree/main/libafl_derive)
This a proc-macro crate paired with the `libafl` crate.
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`](https://github.com/AFLplusplus/LibAFL/tree/main/libafl_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.
@ -52,36 +67,36 @@ To enable and disable features at compile-time, the features are enabled and dis
Currently, the supported flags are:
- `pcguard_edges` defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges 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.
- `pcguard_hitcounts` defines the SanitizerCoverage trace-pc-guard hooks to track the executed edges with the hitcounts (like AFL) in a map.
- `libfuzzer` exposes a compatibility layer with libFuzzer style harnesses.
- `value_profile` defines the SanitizerCoverage trace-cmp hooks to track the matching bits of each comparison in a map.
### libafl_cc
### [`libafl_cc`](https://github.com/AFLplusplus/LibAFL/tree/main/libafl_cc)
This is a library that provides utils wrap compilers and create source-level fuzzers.
This is a library that provides utils to wrap compilers and create source-level fuzzers.
At the moment, only the Clang compiler is supported.
To understand it deeper, look through the tutorials and examples.
### libafl_frida
### [`libafl_frida`](https://github.com/AFLplusplus/LibAFL/tree/main/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
### [`libafl_qemu`](https://github.com/AFLplusplus/LibAFL/tree/main/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
### [`libafl_nyx`](https://github.com/AFLplusplus/LibAFL/tree/main/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
### [`libafl_concolic`](https://github.com/AFLplusplus/LibAFL/tree/main/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.

View File

@ -11,27 +11,27 @@ The first step is to download LibAFL and all dependencies that are not automatic
> previous command. Additionally, PowerShell-specific examples will use `>`
> rather than `$`.
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.
While technically you 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
$ git clone git@github.com:AFLplusplus/LibAFL.git
$ git clone https://github.com/AFLplusplus/LibAFL.git
```
You can alternatively, on a UNIX-like machine, download a compressed archive and extract it with:
Alternatively, on a UNIX-like machine, you can download a compressed archive and extract it with:
```sh
wget https://github.com/AFLplusplus/LibAFL/archive/main.tar.gz
$ tar xvf LibAFL-main.tar.gz
$ rm LibAFL-main.tar.gz
$ wget https://github.com/AFLplusplus/LibAFL/archive/main.tar.gz
$ tar xvf main.tar.gz
$ rm main.tar.gz
$ ls LibAFL-main # this is the extracted folder
```
## Clang installation
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 stable Rust still does not support features that some parts of LibAFL may need, such as weak linking, and LLVM builtins linking.
While most of the code is written 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.
For these parts, 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,

View File

@ -4,10 +4,10 @@ Fuzzers are important tools for security researchers and developers alike.
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 perspective of a power user, however, these tools are limited.
Their design does not treat extensibility as a first-class citizen.
Their designs do 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.
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 cannot just be combined for new projects.
By reinventing the wheel over and over, we may completely miss out on features that are complex to reimplement.
To tackle this issue, we created LibAFL, a library that is _not just another fuzzer_, but a collection of reusable pieces for individual fuzzers.
@ -24,11 +24,11 @@ Some highlight features currently include:
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-school 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.
- `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 also possible, using LLMP's `broker2broker` feature.
- `fast`: We do everything we can at compile time so that the runtime overhead is as minimal as it can get.
- `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.
- `bring your own target`: We support binary-only modes, like (full-system) 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,11 +1,11 @@
# The LibAFL Fuzzing Library
<img align="right" src="https://github.com/AFLplusplus/Website/raw/master/static/logo_256x256.png" alt="AFL++ Logo">
<img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/main/static/libafl_logo.svg" alt="LibAFL Logo" style="width: 256px; height: auto">
*by Andrea Fioraldi and Dominik Maier*
Welcome to LibAFL, the Advanced Fuzzing Library.
This book shall be a gentle introduction into the library.
This book shall be a gentle introduction to the library.
This version of the LibAFL book is coupled with the release 1.0 beta of the library.

View File

@ -3,7 +3,7 @@
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.
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

@ -1,8 +1,8 @@
# Message Passing
LibAFL offers a standard mechanism for message passing over processes and machines with a low overhead.
LibAFL offers a standard mechanism for message passing between 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`.
Depending on individual needs, LibAFL can also write testcase contents to disk, while still using events to notify other fuzzers, using the `CachedOnDiskCorpus` or similar.
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.
@ -12,7 +12,7 @@ The `EventManager` interface is used to send Events over the wire using `Low Lev
## 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.
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`.
@ -28,12 +28,12 @@ Shared maps, called shared memory for the sake of not colliding with Rust's `map
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.
It periodically checks all incoming client maps 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`.
Once the receiver maps the new page, it flags it as safe for unmapping by 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:
@ -54,10 +54,10 @@ After the broker received a new message from clientN, (`clientN_out->current_id
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
This additional memory resources serve 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`:
So the outgoing messages flow is like this over the outgoing broadcast `Shmem`:
```text
[broker]
@ -78,7 +78,7 @@ 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`.
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

View File

@ -4,18 +4,18 @@ 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`.
The straightforward way to do Multi-Threading is to use the [`LlmpRestartingEventManager`](https://docs.rs/libafl/latest/libafl/events/llmp/struct.LlmpRestartingEventManager.html), specifically to use [`setup_restarting_mgr_std`](https://docs.rs/libafl/latest/libafl/events/llmp/fn.setup_restarting_mgr_std.html).
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 not yet bound, this instance becomes the broker, binding itself 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.
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.
While it's called "restarting" manager, it uses `fork` on Unix-like operating systems as optimization and only actually restarts from scratch on Windows.
## Automated, with Launcher
@ -23,7 +23,7 @@ While it's called "restarting" manager, it uses `fork` on Unix operating systems
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()`:
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 an individual fuzzer. Then you can specify the `shmem_provider`,`broker_port`,`monitor`,`cores` and other stuff through `Launcher::builder()`:
```rust,ignore
Launcher::builder()
@ -42,13 +42,17 @@ To use launcher, first you need to write an anonymous function `let mut run_clie
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`.
If the launcher uses `fork`, it will hide child output, unless the settings indicate otherwise, or the `LIBAFL_DEBUG_OUTPUT` env variable is set.
On Windows, the Launcher will restart each client, while on Unix-alikes, 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.
2. To use multiple launchers for individual configurations, you can set `spawn_broker` to `false` on all instances but one.
3. Launcher will not select the cores automatically, so you need to specify the `cores` that you want.
4. On `Unix`, you can chose between a forking and non-forking version of Launcher by setting the `fork` feature in LibAFL. Some targets may not like forking, but it is faster than restarting processes from scratch. Windows will never fork.
5. For simple debugging, first set the `LIBAFL_DEBUG_OUTPUT` env variable to see if a child process printed anything.
6. For further debugging of fuzzer failures, it may make sense to replace `Launcher` temporarily with a [`SimpleEventManager`](https://docs.rs/libafl/latest/libafl/events/simple/struct.SimpleEventManager.html#method.new) and call your harness fn (`run_client(None, mgr, 0);`) directly, so that fuzzing runs in the same thread and is easier to debug, before moving back to `Launcher` after the bugfix.
For more examples, you can check out `qemu_launcher` and `libfuzzer_libpng_launcher` in [`./fuzzers/`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers).

View File

@ -2,4 +2,4 @@
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.
This tutorial will introduce you to 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

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

@ -0,0 +1,73 @@
[package]
name = "fret"
version = "0.8.2"
authors = ["Alwin Berger <alwin.berger@tu-dortmund.de>"]
edition = "2021"
[features]
default = ["std", "snapshot_fast", "restarting", "do_hash_notify_state", "config_stg", "fuzz_int", "trace_job_response_times", "shortcut", "trace_reads" ]
std = []
# Exec environemnt basics
snapshot_restore = []
snapshot_fast = [ "snapshot_restore" ]
singlecore = []
restarting = ['singlecore']
run_until_saturation = []
fuzz_int = []
shortcut = []
# information capture
observe_edges = [] # observe cfg edges
observe_hitcounts = [ "observe_edges" ] # reduces edge granularity
observe_systemstate = []
do_hash_notify_state = []
trace_job_response_times = [ "trace_stg" ]
trace_stg = [ "observe_systemstate" ]
trace_reads = [ "trace_stg" ]
# feedbacks
feed_stg = [ "trace_stg", "observe_systemstate" ]
# feed_stg_edge = [ "feed_stg"]
feed_stg_pathhash = [ "feed_stg"]
feed_stg_abbhash = [ "feed_stg"]
feed_stg_aggregatehash = [ "feed_stg"]
mutate_stg = [ "observe_systemstate" ]
feed_longest = [ ]
feed_afl = [ "observe_edges" ]
feed_genetic = []
gensize_1 = [ ]
gensize_10 = [ ]
gensize_100 = [ ]
gensize_1000 = [ ]
# schedulers
sched_genetic = []
sched_afl = []
sched_stg = []
# sched_stg_edge = ['sched_stg'] # every edge in the stg
sched_stg_pathhash = ['sched_stg'] # every path in the stg
sched_stg_abbhash = ['sched_stg'] # every path of abbs
sched_stg_aggregatehash = ['sched_stg'] # every aggregated path (order independent)
# overall_configs
config_genetic = ["gensize_100","feed_genetic","sched_genetic","trace_stg"]
config_afl = ["feed_afl","sched_afl","observe_hitcounts","trace_stg"]
config_frafl = ["feed_afl","sched_afl","feed_longest","trace_stg"]
config_stg = ["feed_stg_aggregatehash","sched_stg_aggregatehash","mutate_stg"]
[profile.release]
lto = true
codegen-units = 1
debug = true
[dependencies]
libafl = { path = "../../libafl/", features = ["multipart_inputs"] }
libafl_bolts = { path = "../../libafl_bolts/" }
libafl_qemu = { path = "../../libafl_qemu/", features = ["arm", "systemmode"] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
hashbrown = { version = "0.14.0", features = ["serde"] } # A faster hashmap, nostd compatible
petgraph = { version="0.6.5", features = ["serde-1"] }
ron = "0.7" # write serialized data - including hashmaps
rand = "0.5"
clap = { version = "4.4.11", features = ["derive"] }
csv = "1.3.0"
log = "0.4"
simple_moving_average = "1.0.2"
itertools = "0.13.0"

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,246 @@
import csv
import os
def_flags="--release --no-default-features --features std,snapshot_fast,restarting,do_hash_notify_state,fuzz_int,trace_job_response_times"
remote="remote/"
RUNTIME=57600
NUM_ITERS=10
rule build_default:
input:
"../Cargo.toml",
"../src"
output:
directory("bins/target_default")
shell:
"cargo build --target-dir {output} {def_flags}"
rule build_showmap:
input:
"bins/target_default"
output:
directory("bins/target_showmap")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_stg"
rule build_random:
input:
"bins/target_default"
output:
directory("bins/target_random")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},feed_longest"
rule build_frafl:
input:
"bins/target_default"
output:
directory("bins/target_frafl")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_frafl,feed_longest"
rule build_afl:
input:
"bins/target_default"
output:
directory("bins/target_afl")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_afl,observe_hitcounts"
rule build_stg:
input:
"bins/target_default"
output:
directory("bins/target_stg")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_stg"
rule build_stg_abbpath:
input:
"bins/target_default"
output:
directory("bins/target_stg_abbpath")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_stg_abbpath"
rule build_stg_edge:
input:
"bins/target_default"
output:
directory("bins/target_stg_edge")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_stg_edge"
rule build_feedgeneration1:
input:
"bins/target_default"
output:
directory("bins/target_feedgeneration1")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},feed_genetic,gensize_1"
rule build_feedgeneration10:
input:
"bins/target_default"
output:
directory("bins/target_feedgeneration10")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},feed_genetic,gensize_10"
rule build_feedgeneration100:
input:
"bins/target_default"
output:
directory("bins/target_feedgeneration100")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_genetic,gensize_100"
rule build_genetic100:
input:
"bins/target_default"
output:
directory("bins/target_genetic100")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_genetic,mutate_stg,gensize_100"
rule build_feedgeneration1000:
input:
"bins/target_default"
output:
directory("bins/target_feedgeneration1000")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_genetic,gensize_1000"
rule build_genetic1000:
input:
"bins/target_default"
output:
directory("bins/target_genetic1000")
shell:
"cp -r -a --reflink=auto {input} {output} && cargo build --target-dir {output} {def_flags},config_genetic,mutate_stg,gensize_1000"
rule run_bench:
input:
"build/{target}.elf",
"bins/target_{fuzzer}"
output:
multiext("timedump/{fuzzer}/{target}#{num}", ".time", ".log") # , ".case"
run:
with open('target_symbols.csv') as csvfile:
reader = csv.DictReader(csvfile)
line = next((x for x in reader if x['\ufeffkernel']==wildcards.target), None)
if line == None:
return False
kernel=line['\ufeffkernel']
fuzz_main=line['main_function']
fuzz_input=line['input_symbol']
fuzz_len=line['input_size']
bkp=line['return_function']
select_task=line['select_task']
if wildcards.fuzzer.find('random') >= 0:
script="""
export RUST_BACKTRACE=1
mkdir -p $(dirname {output[0]})
set +e
echo $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz --random -t {RUNTIME} -s {wildcards.num}
$(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz --random -t {RUNTIME} -s {wildcards.num} > {output[1]} 2>&1
exit 0
"""
else:
script="""
export RUST_BACKTRACE=1
mkdir -p $(dirname {output[0]})
set +e
echo $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz -t {RUNTIME} -s {wildcards.num}
$(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz -t {RUNTIME} -s {wildcards.num} > {output[1]} 2>&1
exit 0
"""
shell(script)
rule run_showmap:
input:
"{remote}build/{target}.elf",
"bins/target_showmap",
"{remote}timedump/{fuzzer}/{target}#{num}.case"
output:
"{remote}timedump/{fuzzer}/{target}#{num}_case.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['\ufeffkernel']==wildcards.target), None)
if line == None:
return False
kernel=line['\ufeffkernel']
fuzz_main=line['main_function']
fuzz_input=line['input_symbol']
fuzz_len=line['input_size']
bkp=line['return_function']
select_task=line['select_task']
script="""
export FUZZER=$(pwd)/{input[1]}/release/fret
mkdir -p $(dirname {output})
set +e
echo $FUZZER -n $(pwd)/{remote}/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num}_case -s {select_task} -t -a -r -g -k {input[0]} -c ./target_symbols.csv showmap -i {input[2]}
$FUZZER -n $(pwd)/{remote}/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num}_case -s {select_task} -t -a -r -g -k {input[0]} -c ./target_symbols.csv showmap -i {input[2]}
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}_case.trace.ron",
output:
"{remote}timedump/{fuzzer}/{target}#{num}_case.jobs.csv",
"{remote}timedump/{fuzzer}/{target}#{num}_case.resp.csv",
"{remote}timedump/{fuzzer}/{target}#{num}_case.abbs.csv"
run:
with open('target_symbols.csv') as csvfile:
reader = csv.DictReader(csvfile)
line = next((x for x in reader if x['\ufeffkernel']==wildcards.target), None)
if line == None:
return False
kernel=line['\ufeffkernel']
fuzz_main=line['main_function']
fuzz_input=line['input_symbol']
fuzz_len=line['input_size']
bkp=line['return_function']
select_task=line['select_task']
script="""
echo $(pwd)/../../../../state2gantt/target/debug/state2gantt -i {input} -a {output[0]} -r {output[1]} -p {output[2]} -t {select_task}
$(pwd)/../../../../state2gantt/target/debug/state2gantt -i {input} -a {output[0]} -r {output[1]} -p {output[2]} -t {select_task}
"""
shell(script)
rule trace2gantt:
input:
"{remote}timedump/{fuzzer}/{target}#{num}_case.jobs.csv",
"{remote}timedump/{fuzzer}/{target}#{num}_case.resp.csv"
output:
"{remote}timedump/{fuzzer}/{target}#{num}_case.jobs.html",
shell:
"Rscript $(pwd)/../../../../state2gantt/plot_response.r {input[0]} {input[1]} html"
rule quicktest:
input:
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['feedgeneration100', 'stg'], target=['release', 'waters', 'copter'], variant=['_full', '_bytes', '_int'], num=range(0,int( 1 ))),
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['genetic100', 'frafl'], target=['release', 'waters', 'copter'], variant=['_full', '_bytes', '_int'], num=range(0,int( NUM_ITERS/2 ))),
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['random'], target=['release', 'waters', 'copter'], variant=['_full', '_bytes', '_int'], num=range(0,int( NUM_ITERS/2 ))),
rule critical_set:
input:
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['feedgeneration100', 'stg'], target=['release', 'waters', 'copter'], variant=['_seq_full'], num=range(0,int( 10 ))),
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['random'], target=['release', 'waters', 'copter'], variant=['_seq_full'], num=range(0,int( 1 ))),
rule extended_set:
input:
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['feedgeneration100', 'stg'], target=['release', 'waters', 'copter'], variant=['_seq_full'], num=range(0,int( 10 ))),
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['feedgeneration100', 'stg'], target=['waters'], variant=['_seq_int','_seq_bytes'], num=range(0,int( 10 ))),
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['feedgeneration100', 'stg'], target=['copter'], variant=['_seq_bytes'], num=range(0,int( 10 ))),
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['random'], target=['copter', 'release', 'waters'], variant=['_seq_full'], num=range(0,int( 1 ))),
expand("timedump/{fuzzer}/{target}{variant}#{num}.time", fuzzer=['random'], target=['copter', 'waters'], variant=['_seq_full','_seq_int','_seq_bytes'], num=range(0,int( 1 ))),
rule all_bins:
input:
expand("bins/target_{target}",target=['random','frafl','stg','feedgeneration100','feedgeneration1000','genetic100','genetic1000'])

View File

@ -0,0 +1,15 @@
def_flags="--no-default-features --features std,snapshot_fast,restarting,do_hash_notify_state,trace_job_response_times,fuzz_int"
set -e
cargo build --target-dir ./bins/target_showmap ${def_flags},config_stg
cargo build --target-dir ./bins/target_random ${def_flags},feed_longest
cargo build --target-dir ./bins/target_frafl ${def_flags},config_frafl,feed_longest
cargo build --target-dir ./bins/target_afl ${def_flags},config_afl,observe_hitcounts
cargo build --target-dir ./bins/target_stg ${def_flags},config_stg
cargo build --target-dir ./bins/target_stgpath ${def_flags},feed_stg_abbhash,sched_stg_abbhash,mutate_stg
cargo build --target-dir ./bins/target_feedgeneration1 ${def_flags},feed_genetic,gensize_1
cargo build --target-dir ./bins/target_feedgeneration10 ${def_flags},feed_genetic,gensize_10
cargo build --target-dir ./bins/target_feedgeneration100 ${def_flags},feed_genetic,gensize_100
cargo build --target-dir ./bins/target_feedgeneration1000 ${def_flags},feed_genetic,gensize_1000
cargo build --target-dir ./bins/target_genetic100 ${def_flags},feed_genetic,mutate_stg,gensize_100
cargo build --target-dir ./bins/target_genetic1000 ${def_flags},feed_genetic,mutate_stg,gensize_1000

View File

@ -0,0 +1,38 @@
# Base case
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERS_DEMO=1 INTERRUPT_ACTIVATION=0
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/waters_seq.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERS_DEMO=1 INTERRUPT_ACTIVATION=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/waters_seq_int.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERS_DEMO=1 INTERRUPT_ACTIVATION=0 PARTITION_INPUTS=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/waters_par.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERS_DEMO=1 INTERRUPT_ACTIVATION=1 PARTITION_INPUTS=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/waters_par_int.elf
# V2
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERSV2_DEMO=1 INTERRUPT_ACTIVATION=0
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/watersv2_seq.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERSV2_DEMO=1 INTERRUPT_ACTIVATION=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/watersv2_seq_int.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERSV2_DEMO=1 INTERRUPT_ACTIVATION=0 PARTITION_INPUTS=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/watersv2_par.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC WATERSV2_DEMO=1 INTERRUPT_ACTIVATION=1 PARTITION_INPUTS=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/watersv2_par_int.elf
# other
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC INTERACT_DEMO=1 INTERRUPT_ACTIVATION=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/interact_int.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC INTERACT_DEMO=1 INTERRUPT_ACTIVATION=0
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/interact.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC RELEASE_DEMO=1 INTERRUPT_ACTIVATION=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/release.elf
make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC clean && make -C ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC COPTER_DEMO=1 INTERRUPT_ACTIVATION=1
cp ../../../../FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/build/RTOSDemo.axf build/copter.elf

View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
find $1 -type 'f' -iname "${2}#*.log" | while IFS="" read -r p || [ -n "$p" ]
do
LINE=$(tail -n 100 $p | grep -io "run time: .* corpus: [0-9]*" | tail -n 1)
echo $p: $LINE
LINE=$(grep -i "interesting corpus elements" $p | tail -n 1)
echo $p: $LINE
done

View File

@ -0,0 +1,13 @@
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/waters_seq_all.png ] && Rscript plot_multi.r remote waters_seq ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/waters_seq_int_all.png ] && Rscript plot_multi.r remote waters_seq_int ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/watersv2_seq_all.png ] && Rscript plot_multi.r remote watersv2_seq ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/watersv2_seq_int_all.png ] && Rscript plot_multi.r remote watersv2_seq_int ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/waters_par_all.png ] && Rscript plot_multi.r remote waters_par ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/waters_par_int_all.png ] && Rscript plot_multi.r remote waters_par_int ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/watersv2_par_all.png ] && Rscript plot_multi.r remote watersv2_par ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/watersv2_par_int_all.png ] && Rscript plot_multi.r remote watersv2_par_int ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/interact_all.png ] && Rscript plot_multi.r remote interact ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/interact_int_all.png ] && Rscript plot_multi.r remote interact_int ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/release_all.png ] && Rscript plot_multi.r remote release ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote/copter_all.png ] && Rscript plot_multi.r remote copter ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/remote &
wait

View File

@ -0,0 +1,28 @@
#!/usr/bin/env bash
declare -a PLOTS
COUNT=0
while IFS="" read -r p || [ -n "$p" ];
do
if [[ -z "$p" ]]; then
continue
fi
N="$(dirname "$p")/$(basename -s .case "$p")"
T="${N}_case.trace.ron"
P="${N}_case"
H="${N}_case.jobs.html"
echo "$COUNT $p -> $H"
IFS=" "
# PLOTS+=("$H")
PLOTS[$COUNT]="$H"
COUNT=$((COUNT+1))
# if [ ! -f "$T" ]; then
# snakemake -c1 "$T"
# fi
# if [ ! -f "$P.html" ]; then
# ~/code/FRET/state2gantt/driver.sh "$T"
# fi
done < <(find ./remote/timedump -maxdepth 2 -type 'f' -iregex '.*\.case')
# echo "${PLOTS[@]}"
snakemake -c 6 --keep-incomplete "${PLOTS[@]}"

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,335 @@
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="remote"
#target="waters"
target="watersv2"
#target="waters_int"
#target="watersv2_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)]
#if (length(MY_SELECTION) == 0)
# MY_SELECTION<-NULL
SAVE_FILE=TRUE
print(runtype)
print(target)
print(outputpath)
}
worst_cases <- list(waters=0, waters_int=0, tmr=405669, micro_longint=0, gen3=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]*.time$"
#RIBBON='sd'
#RIBBON='span'
RIBBON='both'
DRAW_WC = worst_case > 0
LEGEND_POS="bottomright"
#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(0,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,#"bottomright",
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','frafl')
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,14 @@
kernel,main_function,input_symbol,input_size,return_function,select_task,interrupts
interact_full,main_interact,FUZZ_INPUT,4096,trigger_Qemu_break,NONE,0#1000
interact_int,main_interact,FUZZ_INPUT,4096,trigger_Qemu_break,NONE,0#1000
interact_bytes,main_interact,FUZZ_INPUT,4096,trigger_Qemu_break,NONE,
waters_seq_full,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
waters_seq_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
waters_seq_bytes,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,
waters_seq_full_seq,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
release_seq_full,main_release,FUZZ_INPUT,4096,trigger_Qemu_break,T3,0#10000;1#5000;2#2000;3#3000
release_seq_int,main_release,FUZZ_INPUT,4096,trigger_Qemu_break,T3,0#10000;1#5000;2#2000;3#3000
release_seq_bytes,main_release,FUZZ_INPUT,4096,trigger_Qemu_break,T3,
copter_seq_full,main_osek,FUZZ_INPUT,4096,trigger_Qemu_break,FC,0#5000
copter_seq_int,main_osek,FUZZ_INPUT,4096,trigger_Qemu_break,FC,0#5000
copter_seq_bytes,main_osek,FUZZ_INPUT,4096,trigger_Qemu_break,SPAttitud,
1 kernel main_function input_symbol input_size return_function select_task interrupts
2 interact_full main_interact FUZZ_INPUT 4096 trigger_Qemu_break NONE 0#1000
3 interact_int main_interact FUZZ_INPUT 4096 trigger_Qemu_break NONE 0#1000
4 interact_bytes main_interact FUZZ_INPUT 4096 trigger_Qemu_break NONE
5 waters_seq_full main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
6 waters_seq_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
7 waters_seq_bytes main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129
8 waters_seq_full_seq main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
9 release_seq_full main_release FUZZ_INPUT 4096 trigger_Qemu_break T3 0#10000;1#5000;2#2000;3#3000
10 release_seq_int main_release FUZZ_INPUT 4096 trigger_Qemu_break T3 0#10000;1#5000;2#2000;3#3000
11 release_seq_bytes main_release FUZZ_INPUT 4096 trigger_Qemu_break T3
12 copter_seq_full main_osek FUZZ_INPUT 4096 trigger_Qemu_break FC 0#5000
13 copter_seq_int main_osek FUZZ_INPUT 4096 trigger_Qemu_break FC 0#5000
14 copter_seq_bytes main_osek FUZZ_INPUT 4096 trigger_Qemu_break SPAttitud

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 );
}

115
fuzzers/FRET/src/cli.rs Normal file
View File

@ -0,0 +1,115 @@
use clap::{Parser, Subcommand};
use std::path::PathBuf;
// Argument parsing ================================================================================
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
/// Kernel Image
#[arg(short, long, value_name = "FILE")]
pub kernel: PathBuf,
/// Sets a custom config file
#[arg(short, long, value_name = "FILE")]
pub config: PathBuf,
/// Sets the prefix of dumed files
#[arg(short='n', long, value_name = "FILENAME")]
pub dump_name: Option<PathBuf>,
/// do time dumps
#[arg(short='t', long)]
pub dump_times: bool,
/// do worst-case dumps
#[arg(short='a', long)]
pub dump_cases: bool,
/// do trace dumps (if supported)
#[arg(short='r', long)]
pub dump_traces: bool,
/// do graph dumps (if supported)
#[arg(short='g', long)]
pub dump_graph: bool,
/// select a task for measurments
#[arg(short='s', long)]
pub select_task: Option<String>,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand,Clone)]
pub enum Commands {
/// run a single input
Showmap {
/// take this input
#[arg(short, long)]
input: PathBuf,
},
/// start fuzzing campaign
Fuzz {
/// disable heuristic
#[arg(short, long)]
random: bool,
/// seed for randomness
#[arg(short, long)]
seed: Option<u64>,
/// runtime in seconds
#[arg(short, long)]
time: Option<u64>,
}
}
pub fn set_env_from_config(kernel : &PathBuf, path : &PathBuf) {
let is_csv = path.as_path().extension().map_or(false, |x| x=="csv");
if !is_csv {
let lines = std::fs::read_to_string(path).expect("Config file not found");
let lines = lines.lines().filter(
|x| x.len()>0
);
for l in lines {
let pair = l.split_once('=').expect("Non VAR=VAL line in config");
std::env::set_var(pair.0, pair.1);
}
} else {
let mut reader = csv::Reader::from_path(path).expect("CSV read from config failed");
let p = kernel.as_path();
let stem = p.file_stem().expect("Kernel filename error").to_str().unwrap();
for r in reader.records() {
let rec = r.expect("CSV entry error");
if stem == &rec[0] {
std::env::set_var("FUZZ_MAIN", &rec[1]);
std::env::set_var("FUZZ_INPUT", &rec[2]);
std::env::set_var("FUZZ_INPUT_LEN", &rec[3]);
std::env::set_var("BREAKPOINT", &rec[4]);
break;
}
}
}
}
pub fn get_interrupt_config(kernel : &PathBuf, path : &PathBuf) -> Vec<(usize,u32)>{
let is_csv = path.as_path().extension().map_or(false, |x| x=="csv");
if !is_csv {
panic!("Interrupt config must be inside a CSV file");
} else {
let mut reader = csv::Reader::from_path(path).expect("CSV read from config failed");
let p = kernel.as_path();
let stem = p.file_stem().expect("Kernel filename error").to_str().unwrap();
for r in reader.records() {
let rec = r.expect("CSV entry error");
if stem == &rec[0] {
let ret = rec[6].split(';').filter(|x| x != &"").map(|x| {
let pair = x.split_once('#').expect("Interrupt config error");
(pair.0.parse().expect("Interrupt config error"), pair.1.parse().expect("Interrupt config error"))
}).collect();
println!("Interrupt config {:?}", ret);
return ret;
}
}
}
return Vec::new();
}

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

@ -0,0 +1,732 @@
//! 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, ptr::addr_of_mut, ffi::OsStr};
use hashbrown::HashMap;
use libafl_bolts::{
core_affinity::Cores, ownedref::OwnedMutSlice, rands::StdRand, shmem::{ShMemProvider, StdShMemProvider}, tuples::tuple_list, AsSlice, SimpleStderrLogger
};
use libafl::{
common::{HasMetadata, HasNamedMetadata}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, events::{launcher::Launcher, EventConfig}, executors::ExitKind, feedback_or, feedback_or_fast, feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{multi::MultipartInput, BytesInput, HasTargetBytes, Input}, monitors::MultiMonitor, observers::{CanTrack, VariableMapObserver}, prelude::{havoc_mutations, minimizer::TopRatedsMetadata, CorpusId, Generator, HitcountsMapObserver, RandBytesGenerator, SimpleEventManager, SimpleMonitor, SimplePrintingMonitor, SimpleRestartingEventManager, StdScheduledMutator}, schedulers::QueueScheduler, stages::StdMutationalStage, state::{HasCorpus, StdState}, Error, Evaluator
};
use libafl_qemu::edges::EDGES_MAP_SIZE_IN_USE;
use libafl_qemu::{
edges::{self, edges_map_mut_ptr, QemuEdgeCoverageHelper, MAX_EDGES_FOUND}, elf::EasyElf, emu::Emulator, GuestAddr, GuestPhysAddr, QemuExecutor, QemuExitReason, QemuFilterList, QemuHooks, Regs, StdInstrumentationFilter
};
use rand::{SeedableRng, StdRng, Rng};
use crate::{
systemstate::{self, feedbacks::{DumpSystraceFeedback, SystraceErrorFeedback}, helpers::{get_function_range, load_symbol, try_load_symbol, QemuSystemStateHelper}, mutational::{input_bytes_to_interrupt_times, InterruptShiftStage, STGSnippetStage}, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, GraphMaximizerCorpusScheduler, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}}, time::{
clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP, QEMU_ICOUNT_SHIFT, QEMU_ISNS_PER_USEC}, qemustate::QemuStateRestoreHelper, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, RateLimitedMonitor, TimeMaximizerCorpusScheduler, TimeProbMassScheduler, TimeStateMaximizerCorpusScheduler}
}
};
use std::time::SystemTime;
use petgraph::dot::Dot;
use crate::systemstate::stg::STGFeedbackState;
use libafl::inputs::HasMutatorBytes;
use libafl_qemu::Qemu;
use crate::cli::Cli;
use crate::cli::Commands;
use crate::cli::set_env_from_config;
use clap::Parser;
use log;
use rand::RngCore;
// Constants ================================================================================
pub static mut RNG_SEED: u64 = 1;
pub const FIRST_INT : u32 = 200000;
pub const MAX_NUM_INTERRUPT: usize = 128;
pub const NUM_INTERRUPT_SOURCES: usize = 6; // Keep in sync with qemu-libafl-bridge/hw/timer/armv7m_systick.c:319 and FreeRTOS/FreeRTOS/Demo/CORTEX_M3_MPS2_QEMU_GCC/init/startup.c:216
pub const DO_NUM_INTERRUPT: usize = 128;
pub static mut MAX_INPUT_SIZE: usize = 32;
pub fn get_all_fn_symbol_ranges(elf: &EasyElf, api_range: std::ops::Range<GuestAddr>) -> HashMap<String,std::ops::Range<GuestAddr>> {
let mut api_addreses : HashMap<String,std::ops::Range<GuestAddr>> = HashMap::new();
let gob = elf.goblin();
let mut funcs : Vec<_> = gob.syms.iter().filter(|x| x.is_function() && api_range.contains(&x.st_value.try_into().unwrap())).collect();
funcs.sort_unstable_by(|x,y| x.st_value.cmp(&y.st_value));
for sym in &funcs {
let sym_name = gob.strtab.get_at(sym.st_name);
if let Some(sym_name) = sym_name {
// if ISR_SYMBOLS.contains(&sym_name) {continue;}; // skip select symbols, which correspond to ISR-safe system calls
if let Some(r) = get_function_range(elf, sym_name) {
api_addreses.insert(sym_name.to_string(), r);
}
}
}
for i in api_addreses.iter() {
println!("{} {:#x}..{:#x}", i.0, i.1.start, i.1.end);
}
return api_addreses;
}
#[allow(unused)]
extern "C" {
static mut libafl_interrupt_offsets : [[u32; MAX_NUM_INTERRUPT]; NUM_INTERRUPT_SOURCES];
static mut libafl_num_interrupts : [usize; NUM_INTERRUPT_SOURCES];
}
/// Takes a state, cli and a suffix, writes out the current worst case
macro_rules! do_dump_case {
( $s:expr,$cli:expr, $c:expr) => {
if ($cli.dump_cases) {
let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"case"} else {$c});
println!("Dumping worst case to {:?}", &dump_path);
let corpus = $s.corpus();
let mut worst = Duration::new(0,0);
let mut worst_input = None;
for i in 0..corpus.count() {
let tc = corpus.get(corpus.nth(i.into())).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().clone());
worst = tc.exec_time().expect("Testcase missing duration");
}
}
if let Some(wi) = worst_input {
wi.to_file(dump_path);
}
}
}
}
/// Takes a state, cli and a suffix, appends icount history
macro_rules! do_dump_times {
($state:expr, $cli:expr, $c:expr) => {
if $cli.dump_times {
let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"time"} else {$c});
let mut file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open(dump_path).expect("Could not open timedump");
if let Ok(ichist) = $state.metadata_mut::<IcHist>() {
for i in ichist.0.drain(..) {
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
}
}
}
};
}
/// Takes a state and a bool, writes out the current graph
macro_rules! do_dump_stg {
($state:expr, $cli:expr, $c:expr) => {
#[cfg(feature = "trace_stg")]
if $cli.dump_graph {
let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"dot"} else {$c});
println!("Dumping graph to {:?}", &dump_path);
if let Some(md) = $state.named_metadata_map_mut().get_mut::<STGFeedbackState>("stgfeedbackstate") {
let out = md.graph.map(|_i,x| x.color_print(), |_i,x| x.color_print());
let outs = Dot::with_config(&out, &[]).to_string();
let outs = outs.replace("\\\"","\"");
let outs = outs.replace(';',"\\n");
fs::write(dump_path,outs).expect("Failed to write graph");
}
}
};
}
/// Takes a state and a bool, writes out top rated inputs
macro_rules! do_dump_toprated {
($state:expr, $cli:expr, $c:expr) => {
if $cli.dump_cases {
{
let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"toprated"} else {$c});
println!("Dumping toprated to {:?}", &dump_path);
if let Some(md) = $state.metadata_map_mut().get_mut::<TopRatedsMetadata>() {
let mut uniq: Vec<CorpusId> = md.map.values().map(|x| x.clone()).collect();
uniq.sort();
uniq.dedup();
fs::write(dump_path,ron::to_string(&md.map).expect("Failed to serialize metadata")).expect("Failed to write graph");
}
}
}
};
}
// Fuzzer setup ================================================================================
#[allow(unused)]
pub fn fuzz() {
log::set_max_level(log::LevelFilter::Info);
SimpleStderrLogger::set_logger().unwrap();
let cli = Cli::parse();
set_env_from_config(&cli.kernel, &cli.config);
let interrupt_config = crate::cli::get_interrupt_config(&cli.kernel, &cli.config);
unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();}
if cli.dump_name.is_none() && (cli.dump_times || cli.dump_cases || cli.dump_traces || cli.dump_graph) {
panic!("Dump name not give but dump is requested");
}
let mut starttime = std::time::Instant::now();
// 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(
&cli.kernel,
&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 = load_symbol(&elf, &env::var("FUZZ_INPUT").unwrap_or_else(|_| "FUZZ_INPUT".to_owned()), true);
println!("FUZZ_INPUT @ {:#x}", input_addr);
let input_length_ptr = try_load_symbol(&elf, &env::var("FUZZ_LENGTH").unwrap_or_else(|_| "FUZZ_LENGTH".to_owned()), true);
let input_counter_ptr = try_load_symbol(&elf, &env::var("FUZZ_POINTER").unwrap_or_else(|_| "FUZZ_POINTER".to_owned()), true);
#[cfg(feature = "observe_systemstate")]
let curr_tcb_pointer = load_symbol(&elf, "pxCurrentTCB", false); // loads to the address specified in elf, without respecting program headers
#[cfg(feature = "observe_systemstate")]
println!("TCB pointer at {:#x}", curr_tcb_pointer);
#[cfg(feature = "observe_systemstate")]
let task_queue_addr = load_symbol(&elf, "pxReadyTasksLists", false);
#[cfg(feature = "observe_systemstate")]
let task_delay_addr = load_symbol(&elf, "pxDelayedTaskList", false);
#[cfg(feature = "observe_systemstate")]
let task_delay_overflow_addr = load_symbol(&elf, "pxOverflowDelayedTaskList", false);
#[cfg(feature = "observe_systemstate")]
let scheduler_lock = load_symbol(&elf, "uxSchedulerSuspended", false);
#[cfg(feature = "observe_systemstate")]
let scheduler_running = load_symbol(&elf, "xSchedulerRunning", false);
#[cfg(feature = "observe_systemstate")]
let critical_section = load_symbol(&elf, "uxCriticalNesting", false);
let app_start = load_symbol(&elf, "__APP_CODE_START__", false);
let app_end = load_symbol(&elf, "__APP_CODE_END__", false);
let app_range = app_start..app_end;
let api_start = load_symbol(&elf, "__API_CODE_START__", false);
let api_end = load_symbol(&elf, "__API_CODE_END__", false);
let api_range = api_start..api_end;
let job_done_addr = load_symbol(&elf, "trigger_job_done", false);
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; NUM_INTERRUPT_SOURCES];
}
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.");}
}
println!("API functions:");
let mut api_ranges = get_all_fn_symbol_ranges(&elf, api_range);
println!("APP functions:");
let app_fn_ranges = get_all_fn_symbol_ranges(&elf, app_range.clone());
let mut isr_ranges : HashMap<String,std::ops::Range<GuestAddr>> = systemstate::helpers::ISR_SYMBOLS.iter().filter_map(|x| (api_ranges.get(&x.to_string()).map(|y| (x.to_string(),y.clone())))).collect();
systemstate::helpers::ISR_SYMBOLS.iter().for_each(|x| {let _ =(app_fn_ranges.get(&x.to_string()).map(|y| (x.to_string(),y.clone()))).map(|y| isr_ranges.insert(y.0,y.1));}); // add used defined isr
let denylist : Vec<_> =isr_ranges.values().map(|x| x.clone()).collect();
let denylist = QemuFilterList::DenyList(denylist); // do not count isr jumps, which are useless
#[cfg(feature = "observe_systemstate")]
let mut isr_addreses : HashMap<GuestAddr, String> = systemstate::helpers::ISR_SYMBOLS.iter().filter_map(|x| (api_ranges.remove(&x.to_string()).map(|y| (y.start,x.to_string())))).collect();
#[cfg(feature = "observe_systemstate")]
systemstate::helpers::ISR_SYMBOLS.iter().for_each(|x| {let _ =(app_fn_ranges.get(&x.to_string()).map(|y| (x.to_string(),y.clone()))).map(|y| isr_addreses.insert(y.1.start, y.0));}); // add used defined isr
#[cfg(feature = "observe_systemstate")]
for i in systemstate::helpers::ISR_SYMBOLS {
if isr_ranges.get(&i.to_string()).is_none() {
if let Some(fr) = get_function_range(&elf, i) {
isr_addreses.insert(fr.start, i.to_string());
isr_ranges.insert(i.to_string(), fr);
}
}
}
#[cfg(feature = "observe_systemstate")]
let api_addreses : HashMap<GuestAddr, String> = api_ranges.iter().map(|(k,v)| (v.start,k.clone())).collect();
#[cfg(feature = "observe_systemstate")]
let api_ranges : Vec<_> = api_ranges.into_iter().collect();
#[cfg(feature = "observe_systemstate")]
let isr_ranges : Vec<_> = isr_ranges.into_iter().collect();
/// Setup the interrupt inputs. Noop if interrupts are not fuzzed
fn setup_interrupt_inputs(mut input : MultipartInput<BytesInput>, interrupt_config : &Vec<(usize,u32)>, mut random: Option<&mut StdRng>) -> MultipartInput<BytesInput> {
#[cfg(feature = "fuzz_int")]
for (i,_) in interrupt_config {
let name = format!("isr_{}_times",i);
if input.parts_by_name(&name).next().is_none() {
if let Some(random) = random.as_mut() {
input.add_part(name, BytesInput::new((0..MAX_NUM_INTERRUPT).map(|_| (random.next_u32()%(100*1000*QEMU_ISNS_PER_USEC)).to_le_bytes()).flatten().collect()));
} else {
input.add_part(name, BytesInput::new([0; MAX_NUM_INTERRUPT*4].to_vec()));
}
}
}
input
}
// Client setup ================================================================================
let run_client = |state: Option<_>, mut mgr, _core_id| {
// Initialize QEMU
let args: Vec<String> = vec![
"target/debug/fret",
"-icount",
&format!("shift={},align=off,sleep=off", QEMU_ICOUNT_SHIFT),
"-machine",
"mps2-an385",
"-cpu",
"cortex-m3",
"-monitor",
"null",
"-kernel",
&cli.kernel.as_os_str().to_str().expect("kernel path is not a string"),
"-serial",
"null",
"-nographic",
"-S",
// "-semihosting",
// "--semihosting-config",
// "enable=on,target=native",
#[cfg(not(feature = "snapshot_fast"))]
"-snapshot",
#[cfg(not(feature = "snapshot_fast"))]
"-drive",
#[cfg(not(feature = "snapshot_fast"))]
"if=none,format=qcow2,file=dummy.qcow2",
].into_iter().map(String::from).collect();
let env: Vec<(String, String)> = env::vars().collect();
let qemu = Qemu::init(&args, &env).expect("Emulator creation failed");
if let Some(main_addr) = main_addr {
qemu.set_breakpoint(main_addr);
unsafe {
match qemu.run() {
Ok(QemuExitReason::Breakpoint(_)) => {}
_ => panic!("Unexpected QEMU exit."),
}
}
qemu.remove_breakpoint(main_addr);
}
qemu.set_breakpoint(breakpoint); // BREAKPOINT
let devices = qemu.list_devices();
println!("Devices = {devices:?}");
#[cfg(feature = "snapshot_fast")]
let initial_snap = Some(qemu.create_fast_snapshot(true));
#[cfg(not(feature = "snapshot_fast"))]
let initial_snap = None;
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &MultipartInput<BytesInput>| {
unsafe {
#[cfg(feature = "fuzz_int")]
{
for &c in &interrupt_config {
let (i,_) = c;
let name = format!("isr_{}_times",i);
let input_bytes = input.parts_by_name(&name).next().map(|x| x.1.bytes()).unwrap_or(&[0u8; MAX_NUM_INTERRUPT*4]);
let t = input_bytes_to_interrupt_times(input_bytes, c);
for j in 0..t.len() {libafl_interrupt_offsets[i][j]=t[j];}
libafl_num_interrupts[i]=t.len();
}
// println!("Load: {:?}", libafl_interrupt_offsets[0..libafl_num_interrupts].to_vec());
}
let mut bytes = input.parts_by_name("bytes").next().unwrap().1.bytes();
let mut len = bytes.len();
if len > MAX_INPUT_SIZE {
bytes = &bytes[0..MAX_INPUT_SIZE];
len = MAX_INPUT_SIZE;
}
// Note: I could not find a difference between write_mem and write_phys_mem for my usecase
qemu.write_mem(input_addr, bytes);
if let Some(s) = input_length_ptr {
qemu.write_mem(s, &len.to_le_bytes())
}
qemu.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..qemu.num_cpus())
.map(|i| qemu.cpu_from_index(i))
.map(|cpu| -> Result<u32, _> { cpu.read_reg(Regs::Pc) });
match pcs
.find(|pc| (breakpoint..breakpoint + 5).contains(pc.as_ref().unwrap_or(&0)))
{
Some(_) => ExitKind::Ok,
Option::None => ExitKind::Crash,
}
}
};
// Create an observation channel to keep track of the execution time
let clock_time_observer = QemuClockObserver::new("clocktime", if cli.dump_times {cli.dump_name.clone().map(|x| x.with_extension("time"))} else {None} );
// Create an observation channel using the coverage map
#[cfg(feature = "observe_edges")]
let edges_observer = unsafe { VariableMapObserver::from_mut_slice(
"edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
addr_of_mut!(MAX_EDGES_FOUND),
)}.track_indices();
#[cfg(feature = "observer_hitcounts")]
let edges_observer = HitcountsMapObserver::new(edges_observer).track_indices();
#[cfg(feature = "observe_systemstate")]
let stg_coverage_observer = unsafe { VariableMapObserver::from_mut_slice(
"stg",
stg_map_mut_slice(),
addr_of_mut!(MAX_STG_NUM)
)}.track_indices();
#[cfg(feature = "observe_systemstate")]
let systemstate_observer = QemuSystemStateObserver::new(&cli.select_task);
// 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, &cli.select_task)
);
#[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(&edges_observer)
);
#[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 = "observe_systemstate"))]
let mut feedback = feedback_or!(
feedback,
DumpSystraceFeedback::with_dump(if cli.dump_traces {cli.dump_name.clone().map(|x| x.with_extension("trace.ron"))} else {None})
);
#[cfg(feature = "trace_stg")]
let mut feedback = feedback_or!(
feedback,
StgFeedback::new(if cli.dump_graph {cli.dump_name.clone()} else {None})
);
#[cfg(feature = "feed_stg_edge")]
let mut feedback = feedback_or!(
feedback,
MaxMapFeedback::new(&stg_coverage_observer)
);
// A feedback to choose if an input is producing an error
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new(), SystraceErrorFeedback::new(matches!(cli.command, Commands::Fuzz{..}), Some(10)));
// 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 = "sched_afl", feature = "sched_stg", feature = "sched_genetic")))]
let scheduler = QueueScheduler::new(); // fallback
#[cfg(feature = "sched_afl",)]
let scheduler = TimeMaximizerCorpusScheduler::new(&edges_observer,TimeProbMassScheduler::new());
#[cfg(feature = "sched_stg")]
let scheduler = GraphMaximizerCorpusScheduler::non_metadata_removing(&stg_coverage_observer,TimeProbMassScheduler::new());
#[cfg(feature = "sched_genetic")]
let scheduler = GenerationScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let qhelpers = tuple_list!();
#[cfg(feature = "observe_systemstate")]
let qhelpers = (QemuSystemStateHelper::new(api_addreses,api_ranges,isr_addreses,isr_ranges,input_addr..(input_addr+unsafe { MAX_INPUT_SIZE } as u32),curr_tcb_pointer,task_queue_addr,task_delay_addr,task_delay_overflow_addr,scheduler_lock,scheduler_running, critical_section,input_counter_ptr,app_range.clone(), job_done_addr), qhelpers);
#[cfg(feature = "observe_edges")]
let qhelpers = (QemuEdgeCoverageHelper::new(denylist, QemuFilterList::None), qhelpers);
let qhelpers = (QemuStateRestoreHelper::with_fast(initial_snap), qhelpers);
let mut hooks = QemuHooks::new(qemu.clone(),qhelpers);
let observer_list = tuple_list!();
#[cfg(feature = "observe_systemstate")]
let observer_list = (systemstate_observer, (stg_coverage_observer, observer_list)); // must come after clock
#[cfg(feature = "observe_edges")]
let observer_list = (edges_observer, observer_list);
let observer_list = (clock_time_observer, observer_list);
// Create a QEMU in-process executor
let mut executor = QemuExecutor::new(
&mut hooks,
&mut harness,
observer_list,
&mut fuzzer,
&mut state,
&mut mgr,
timeout
)
.expect("Failed to create QemuExecutor");
executor.break_on_timeout();
let mutations = havoc_mutations();
// Setup an havoc mutator with a mutational stage
let mutator = StdScheduledMutator::new(mutations);
let stages = (systemstate::report::SchedulerStatsStage::default(),());
let stages = (StdMutationalStage::new(mutator), stages);
#[cfg(feature = "mutate_stg")]
let mut stages = (STGSnippetStage::new(input_addr), stages);
#[cfg(feature = "fuzz_int")]
let mut stages = (InterruptShiftStage::new(&interrupt_config), stages);
if let Commands::Showmap { input } = cli.command.clone() {
let s = input.as_os_str();
// let show_input = BytesInput::new(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")
// });
let show_input = match MultipartInput::from_file(input.as_os_str()) {
Ok(x) => x,
Err(_) => {
println!("Interpreting input file as raw input");
setup_interrupt_inputs(MultipartInput::from([("bytes",BytesInput::new(input.as_os_str().as_encoded_bytes().to_vec()))]), &interrupt_config, None)
}
};
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, show_input)
.unwrap();
do_dump_times!(state, &cli, "");
do_dump_stg!(state, &cli, "");
} else if let Commands::Fuzz { random, time, seed } = cli.command {
if let Some(se) = seed {
unsafe {
let mut rng = StdRng::seed_from_u64(se);
let bound = 10000;
#[cfg(feature = "shortcut")]
let bound = 100;
for _ in 0..bound {
let inp2 = BytesInput::new((0..MAX_INPUT_SIZE).map(|_| rng.gen::<u8>()).collect());
let inp = setup_interrupt_inputs(MultipartInput::from([("bytes",inp2)]), &interrupt_config, Some(&mut rng));
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 time {
Option::None => {
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.unwrap();
},
Some(t) => {
println!("Iterations {}",t);
let num = t;
if random { unsafe {
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 inp2 = BytesInput::new((0..MAX_INPUT_SIZE).map(|_| rng.gen::<u8>()).collect());
let inp = setup_interrupt_inputs(MultipartInput::from([("bytes",inp2)]), &interrupt_config, Some(&mut rng));
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| {
let d = format!("{}.case",marker);
do_dump_case!(state, &cli, &d);
let _d = format!("{}.dot",marker);
do_dump_stg!(state, &cli, &_d);
let d = format!("{}.toprated",marker);
do_dump_toprated!(state, &cli, &d);
};
dumper(format!(".iter_{}",t));
do_dump_times!(state, &cli, "");
println!("Start running until saturation");
let mut last = state.metadata_map().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_map().get::<IcHist>().unwrap().1;
if after.0 > last.0 {
last=after;
}
do_dump_case!(state, &cli, "");
do_dump_stg!(state, &cli, "");
do_dump_toprated!(state, &cli, "");
}
}
}
do_dump_times!(state, &cli, "");
do_dump_case!(state, &cli, "");
do_dump_stg!(state, &cli, "");
do_dump_toprated!(state, &cli, "");
},
}
}
#[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 = Qemu::init(&args, &env).expect("Emu creation failed");
if let Some(main_addr) = main_addr {
emu.set_breakpoint(main_addr); // BREAKPOINT
}
unsafe {
emu.run();
let mut buf = [0u8].repeat(MAX_INPUT_SIZE);
emu.read_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 = RateLimitedMonitor::new();
#[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, 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),
}
}
}

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

@ -0,0 +1,8 @@
#[cfg(target_os = "linux")]
mod fuzzer;
#[cfg(target_os = "linux")]
pub mod time;
#[cfg(target_os = "linux")]
pub mod systemstate;
#[cfg(target_os = "linux")]
mod cli;

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

@ -0,0 +1,19 @@
//! A libfuzzer-like fuzzer using qemu for binary-only coverage
#[cfg(target_os = "linux")]
mod fuzzer;
#[cfg(target_os = "linux")]
mod time;
#[cfg(target_os = "linux")]
mod systemstate;
#[cfg(target_os = "linux")]
mod cli;
#[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,6 @@
# System-state heuristics
## Information flow
- ``fuzzer.rs`` resolves symbols and creates ``api_ranges`` and ``isr_ranges``
- ``helpers::QemuSystemStateHelper`` captures a series of ``RawFreeRTOSSystemState``
- ``observers::QemuSystemStateObserver`` divides this into ``ReducedFreeRTOSSystemState`` and ``ExecInterval``, the first contains the raw states and the second contains information about the flow between states
- ``stg::StgFeedback`` builds an stg from the intervals

View File

@ -0,0 +1,334 @@
use libafl::SerdeAny;
use libafl::prelude::UsesInput;
use libafl::common::HasNamedMetadata;
use std::path::PathBuf;
use crate::time::clock::QemuClockObserver;
use libafl::corpus::Testcase;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::hash::Hash;
use libafl::events::EventFirer;
use libafl::state::MaybeHasClientPerfMonitor;
use libafl::prelude::State;
use libafl::feedbacks::Feedback;
use libafl_bolts::Named;
use libafl::Error;
use hashbrown::HashMap;
use libafl::{executors::ExitKind, observers::ObserversTuple, common::HasMetadata};
use serde::{Deserialize, Serialize};
use super::ExecInterval;
use super::ReducedFreeRTOSSystemState;
use super::FreeRTOSSystemStateMetadata;
use super::observers::QemuSystemStateObserver;
use std::borrow::Cow;
//============================= Feedback
/// Shared Metadata for a systemstateFeedback
#[derive(Debug, Serialize, Deserialize, SerdeAny, Clone)]
pub struct SystemStateFeedbackState
{
name: Cow<'static, str>,
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
longest: Vec<ReducedFreeRTOSSystemState>,
}
impl Named for SystemStateFeedbackState
{
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl Default for SystemStateFeedbackState
{
fn default() -> Self {
Self {name: Cow::from("systemstate".to_string()), known_traces: HashMap::new(), longest: Vec::new() }
}
}
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NovelSystemStateFeedback
{
name: Cow<'static, str>,
last_trace: Option<Vec<ReducedFreeRTOSSystemState>>,
// known_traces: HashMap<u64,(u64,usize)>,
}
impl<S> Feedback<S> for NovelSystemStateFeedback
where
S: State + UsesInput + MaybeHasClientPerfMonitor + HasNamedMetadata,
S::Input: Default,
{
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>,
S::Input: Default
{
let observer : &QemuSystemStateObserver<S::Input> = observers.match_name::<QemuSystemStateObserver<S::Input>>("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_map_mut()
.get_mut::<SystemStateFeedbackState>("systemstate") {
Some(s) => s,
Option::None => {
let n=SystemStateFeedbackState::default();
state.named_metadata_map_mut().insert("systemstate",n);
state.named_metadata_map_mut().get_mut::<SystemStateFeedbackState>("systemstate").unwrap()
}
};
#[cfg(feature = "trace_job_response_times")]
let last_runtime = observer.last_runtime();
#[cfg(not(feature = "trace_job_response_times"))]
let last_runtime = clock_observer.last_runtime();
// 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) {
Option::None => {
is_novel = true;
feedbackstate.known_traces.insert(somehash,(1,last_runtime,observer.last_run.len()));
}
Some(s) => {
s.0+=1;
if s.1 < last_runtime {
s.1 = 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<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
let a = self.last_trace.take();
match a {
Some(s) => testcase.metadata_map_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
Option::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) -> &Cow<'static, str> {
&self.name
}
}
impl Default for NovelSystemStateFeedback
{
fn default() -> Self {
Self {name: Cow::from("NovelSystemStateFeedback".to_string()), last_trace: None }
}
}
//=========================== Debugging Feedback
/// A [`Feedback`] meant to dump the system-traces for debugging. Depends on [`QemuSystemStateObserver`]
#[derive(Debug)]
pub struct DumpSystraceFeedback
{
name: Cow<'static, str>,
dumpfile: Option<PathBuf>,
dump_metadata: bool,
last_states: Option<HashMap<u64, ReducedFreeRTOSSystemState>>,
last_trace: Option<Vec<ExecInterval>>,
}
impl<S> Feedback<S> for DumpSystraceFeedback
where
S: State + UsesInput + MaybeHasClientPerfMonitor,
{
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>
{
if self.dumpfile.is_none() {return Ok(false)};
let observer = observers.match_name::<QemuSystemStateObserver<S::Input>>("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) => {
let per_task_metadata = if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(&x.name) == observer.select_task.as_ref()).max_by(|a,b| (a.response-a.release).cmp(&(b.response-b.release))) {
// extract computation time spent in each task and abb
let t : Vec<_> = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.response && x.end_tick > worst_instance.release ).cloned().collect();
// task_name -> addr -> (count, time)
let mut ret : HashMap<String, HashMap<u32, (usize, usize, u64)>> = HashMap::new();
let mut t2 = t.clone();
t2.sort_by_key(|x| x.get_task_name_unchecked());
t2.chunk_by_mut(|x,y| x.get_task_name_unchecked() == y.get_task_name_unchecked()).for_each(|x| {
x.sort_by_key(|y| y.abb.as_ref().unwrap().start);
x.chunk_by(|y,z| y.abb.as_ref().unwrap().start == z.abb.as_ref().unwrap().start).for_each(|y| {
match ret.get_mut(&y[0].get_task_name_unchecked()) {
Option::None => {
ret.insert(y[0].get_task_name_unchecked(), HashMap::from([(y[0].abb.as_ref().unwrap().start, (y.len(), y.iter().filter(|x| x.is_abb_end()).count(), y.iter().map(|z| z.get_exec_time()).sum::<_>()))]));
}
Some(x) => {
x.insert(y[0].abb.as_ref().unwrap().start, (y.len(), y.iter().filter(|x| x.is_abb_end()).count(), y.iter().map(|z| z.get_exec_time()).sum()));
}
}
});
});
// dbg!(&ret);
ret
} else {HashMap::new()};
std::fs::write(s,ron::to_string(&(&observer.last_trace,&observer.last_states,&observer.job_instances,per_task_metadata)).expect("Error serializing hashmap")).expect("Can not dump to file");
self.dumpfile = None
},
Option::None => if self.dump_metadata {println!("{:?}\n{:?}",observer.last_run,names);}
};
// if self.dump_metadata {self.last_trace=Some(observer.last_trace.clone());}
Ok(false)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, _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_map_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) -> &Cow<'static, str> {
&self.name
}
}
impl DumpSystraceFeedback
{
/// Creates a new [`DumpSystraceFeedback`]
#[allow(unused)]
pub fn new() -> Self {
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: None, dump_metadata: false, last_trace: None, last_states: None }
}
#[allow(unused)]
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: dumpfile, dump_metadata: false, last_trace: None, last_states: None}
}
#[allow(unused)]
pub fn metadata_only() -> Self {
Self {name: Cow::from("Dumpsystemstate".to_string()), dumpfile: None, dump_metadata: true, last_trace: None, last_states: None}
}
}
#[derive(Debug, Default)]
pub struct SystraceErrorFeedback
{
name: Cow<'static, str>,
dump_case: bool,
max_reports: Option<usize>,
}
impl<S> Feedback<S> for SystraceErrorFeedback
where
S: State + UsesInput + MaybeHasClientPerfMonitor,
{
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<S::Input>>("systemstate")
.expect("QemuSystemStateObserver not found");
let is_err = (!observer.success || observer.do_report);
if let Some(m) = self.max_reports {
if m <= 0 {return Ok(false);}
if is_err {
self.max_reports = Some(m-1);
}
}
Ok(self.dump_case&&is_err)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, _testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
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 SystraceErrorFeedback
{
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl SystraceErrorFeedback
{
#[must_use]
pub fn new(dump_case: bool, max_reports: Option<usize>) -> Self {
Self {name: Cow::from(String::from("SystraceErrorFeedback")), dump_case, max_reports}
}
}

View File

@ -0,0 +1,122 @@
#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals,deref_nullptr,unused)]
use serde::{Deserialize, Serialize};
// Manual Types
use libafl_qemu::Qemu;
/*========== 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: &Qemu, 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: &Qemu, 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,543 @@
use std::ops::Range;
use hashbrown::HashMap;
use hashbrown::HashSet;
use libafl::prelude::ExitKind;
use libafl::prelude::UsesInput;
use libafl_qemu::elf::EasyElf;
use libafl_qemu::read_user_reg_unchecked;
use libafl_qemu::GuestAddr;
use libafl_qemu::GuestPhysAddr;
use libafl_qemu::QemuHooks;
use libafl_qemu::Hook;
use libafl_qemu::helpers::{QemuHelper, QemuHelperTuple};
use libafl_qemu::sys::TCGTemp;
use libafl_qemu::qemu::MemAccessInfo;
use crate::systemstate::RawFreeRTOSSystemState;
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
use crate::systemstate::NUM_PRIOS;
use super::freertos::void_ptr;
use super::freertos::TCB_t;
use super::freertos::rtos_struct::List_Item_struct;
use super::freertos::rtos_struct::*;
use super::freertos;
use super::CaptureEvent;
//============================= API symbols
pub const ISR_SYMBOLS : &'static [&'static str] = &[
// ISRs
"Reset_Handler","Default_Handler","Default_Handler2","Default_Handler3","Default_Handler4","Default_Handler5","Default_Handler6","vPortSVCHandler","xPortPendSVHandler","xPortSysTickHandler","ISR_0_Handler", "ISR_1_Handler", "ISR_2_Handler", "ISR_3_Handler", "ISR_4_Handler", "ISR_5_Handler", "ISR_6_Handler", "ISR_7_Handler", "ISR_8_Handler", "ISR_9_Handler", "ISR_10_Handler", "ISR_11_Handler", "ISR_12_Handler", "ISR_13_Handler"
];
pub const USR_ISR_SYMBOLS : &'static [&'static str] = &[
"ISR_0_Handler", "ISR_1_Handler", "ISR_2_Handler", "ISR_3_Handler", "ISR_4_Handler", "ISR_5_Handler", "ISR_6_Handler", "ISR_7_Handler", "ISR_8_Handler", "ISR_9_Handler", "ISR_10_Handler", "ISR_11_Handler", "ISR_12_Handler", "ISR_13_Handler"
];
/// 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;
}
/// Lookup a symbol in the ELF file, optionally resolve segment offsets
pub fn load_symbol(elf : &EasyElf, symbol : &str, do_translation : bool) -> GuestAddr {
try_load_symbol(elf, symbol, do_translation).expect(&format!("Symbol {} not found", symbol))
}
pub fn try_load_symbol(elf : &EasyElf, symbol : &str, do_translation : bool) -> Option<GuestAddr> {
let ret = elf
.resolve_symbol(symbol, 0);
if do_translation {
Option::map_or(ret, None, |x| Some(virt2phys(x as GuestPhysAddr,&elf) as GuestAddr))
} else {ret}
}
/// Try looking up the address range of a function in the ELF file
pub fn get_function_range(elf: &EasyElf, symbol: &str) -> Option<std::ops::Range<GuestAddr>> {
let gob = elf.goblin();
let mut funcs : Vec<_> = gob.syms.iter().filter(|x| x.is_function()).collect();
funcs.sort_unstable_by(|x,y| x.st_value.cmp(&y.st_value));
for sym in &gob.syms {
if let Some(sym_name) = gob.strtab.get_at(sym.st_name) {
if sym_name == symbol {
if sym.st_value == 0 {
return None;
} else {
//#[cfg(cpu_target = "arm")]
// Required because of arm interworking addresses aka bit(0) for thumb mode
let addr = (sym.st_value as GuestAddr) & !(0x1 as GuestAddr);
//#[cfg(not(cpu_target = "arm"))]
//let addr = sym.st_value as GuestAddr;
// look for first function after addr
let sym_end = funcs.iter().find(|x| x.st_value > sym.st_value);
if let Some(sym_end) = sym_end {
// println!("{} {:#x}..{} {:#x}", gob.strtab.get_at(sym.st_name).unwrap_or(""),addr, gob.strtab.get_at(sym_end.st_name).unwrap_or(""),sym_end.st_value & !0x1);
return Some(addr..((sym_end.st_value & !0x1) as GuestAddr));
}
return None;
};
}
}
}
return None;
}
//============================= Qemu Helper
/// A Qemu Helper with reads FreeRTOS specific structs from Qemu whenever certain syscalls occur, also inject inputs
#[derive(Debug)]
pub struct QemuSystemStateHelper {
// Address of API functions
api_fn_addrs: HashMap<GuestAddr, String>,
api_fn_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
// Address of interrupt routines
isr_addrs: HashMap<GuestAddr, String>,
isr_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
input_mem: Range<GuestAddr>,
tcb_addr: GuestAddr,
ready_queues: GuestAddr,
delay_queue: GuestAddr,
delay_queue_overflow: GuestAddr,
scheduler_lock_addr: GuestAddr,
scheduler_running_addr: GuestAddr,
critical_addr: GuestAddr,
input_counter: Option<GuestAddr>,
app_range: Range<GuestAddr>,
job_done_addrs: GuestAddr,
}
impl QemuSystemStateHelper {
#[must_use]
pub fn new(
api_fn_addrs: HashMap<GuestAddr, String>,
api_fn_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
isr_addrs: HashMap<GuestAddr, String>,
isr_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
input_mem: Range<GuestAddr>,
tcb_addr: GuestAddr,
ready_queues: GuestAddr,
delay_queue: GuestAddr,
delay_queue_overflow: GuestAddr,
scheduler_lock_addr: GuestAddr,
scheduler_running_addr: GuestAddr,
critical_addr: GuestAddr,
input_counter: Option<GuestAddr>,
app_range: Range<GuestAddr>,
job_done_addrs: GuestAddr,
) -> Self {
QemuSystemStateHelper {
api_fn_addrs,
api_fn_ranges,
isr_addrs,
isr_ranges,
input_mem,
tcb_addr: tcb_addr,
ready_queues: ready_queues,
delay_queue,
delay_queue_overflow,
scheduler_lock_addr,
scheduler_running_addr,
critical_addr,
input_counter: input_counter,
app_range,
job_done_addrs,
}
}
}
impl<S> QemuHelper<S> for QemuSystemStateHelper
where
S: UsesInput,
{
fn first_exec<QT>(&self, _hooks: &QemuHooks<QT, S>)
where
QT: QemuHelperTuple<S>,
{
// for wp in self.api_fn_addrs.keys() {
// _hooks.instruction(*wp, Hook::Function(exec_syscall_hook::<QT, S>), false);
// }
for wp in self.isr_addrs.keys() {
_hooks.instruction(*wp, Hook::Function(exec_isr_hook::<QT, S>), false);
}
_hooks.jmps(Hook::Function(gen_jmp_is_syscall::<QT, S>), Hook::Function(trace_jmp::<QT, S>));
#[cfg(feature = "trace_job_response_times")]
_hooks.instruction(self.job_done_addrs, Hook::Function(job_done_hook::<QT, S>), false);
#[cfg(feature = "trace_reads")]
_hooks.reads(Hook::Function(gen_read_is_input::<QT, S>), Hook::Empty,Hook::Empty,Hook::Empty,Hook::Empty,Hook::Function(trace_reads::<QT, S>));
unsafe { INPUT_MEM = self.input_mem.clone() };
}
// TODO: refactor duplicate code
fn pre_exec(&mut self, _emulator: libafl_qemu::Qemu, _input: &S::Input) {
unsafe {
CURRENT_SYSTEMSTATE_VEC.clear();
JOBS_DONE.clear();
}
}
fn post_exec<OT>(&mut self, emulator: libafl_qemu::Qemu, _input: &S::Input, _observers: &mut OT, _exit_kind: &mut ExitKind) {
trigger_collection(&emulator,(0, 0), CaptureEvent::End, self);
unsafe {
let c = emulator.cpu_from_index(0);
let pc = c.read_reg::<i32, u32>(15).unwrap();
if CURRENT_SYSTEMSTATE_VEC.len() == 0 {return;}
CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].edge = (pc,0);
CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].capture_point = (CaptureEvent::End,"Breakpoint".to_string());
}
// Find the first ISREnd of vPortSVCHandler and drop anything before
unsafe {
let mut index = 0;
while index < CURRENT_SYSTEMSTATE_VEC.len() {
if CaptureEvent::ISREnd == CURRENT_SYSTEMSTATE_VEC[index].capture_point.0 && CURRENT_SYSTEMSTATE_VEC[index].capture_point.1 == "xPortPendSVHandler" {
break;
}
index += 1;
}
CURRENT_SYSTEMSTATE_VEC.drain(..index);
}
}
}
fn read_freertos_list(systemstate : &mut RawFreeRTOSSystemState, emulator: &libafl_qemu::Qemu, target: GuestAddr) -> (freertos::List_t, bool) {
let read : freertos::List_t = freertos::emu_lookup::lookup(emulator, target);
let listbytes : GuestAddr = GuestAddr::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
let mut next_index = read.pxIndex;
for _j in 0..read.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);
if next_item.pvContainer != target {
// the list is being modified, abort by setting the list empty
eprintln!("Warning: attempted to read a list that is being modified");
let mut read=read;
read.uxNumberOfItems = 0;
return (read, false);
}
// 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));
}
return (read, true);
}
#[inline]
fn trigger_collection(emulator: &libafl_qemu::Qemu, edge: (GuestAddr, GuestAddr), event: CaptureEvent, h: &QemuSystemStateHelper) {
let listbytes : GuestAddr = GuestAddr::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
let mut systemstate = RawFreeRTOSSystemState::default();
match event {
CaptureEvent::APIStart => {
let s = h.api_fn_addrs.get(&edge.1).unwrap();
systemstate.capture_point=(CaptureEvent::APIStart, s.to_string());
},
CaptureEvent::APIEnd => {
let s = h.api_fn_addrs.get(&edge.0).unwrap();
systemstate.capture_point=(CaptureEvent::APIEnd, s.to_string());
},
CaptureEvent::ISRStart => {
let s = h.isr_addrs.get(&edge.1).unwrap();
systemstate.capture_point=(CaptureEvent::ISRStart, s.to_string());
},
CaptureEvent::ISREnd => {
let s = h.isr_addrs.get(&edge.0).unwrap();
systemstate.capture_point=(CaptureEvent::ISREnd, s.to_string());
},
CaptureEvent::End => {systemstate.capture_point=(CaptureEvent::End, "".to_string());},
CaptureEvent::Undefined => (),
}
if systemstate.capture_point.0 == CaptureEvent::Undefined {
// println!("Not found: {:#x} {:#x}", edge.0.unwrap_or(0), edge.1.unwrap_or(0));
}
systemstate.edge = ((edge.0),(edge.1));
systemstate.qemu_tick = get_icount(emulator);
let mut buf : [u8; 4] = [0,0,0,0];
match h.input_counter {
Some(s) => unsafe { emulator.read_mem(s, &mut buf); },
Option::None => (),
};
systemstate.input_counter = GuestAddr::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;
};
// println!("{:?}",std::str::from_utf8(&current_tcb.pcTaskName));
let critical : void_ptr = freertos::emu_lookup::lookup(emulator, h.critical_addr);
let suspended : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_lock_addr);
let _running : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_running_addr);
systemstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
// During ISRs it is only safe to extract structs if they are not currently being modified
if systemstate.capture_point.0==CaptureEvent::APIStart || systemstate.capture_point.0==CaptureEvent::APIEnd || (critical == 0 && suspended == 0 ) {
// Extract delay list
let mut target : GuestAddr = h.delay_queue;
target = freertos::emu_lookup::lookup(emulator, target);
let _temp = read_freertos_list(&mut systemstate, emulator, target);
systemstate.delay_list = _temp.0;
systemstate.read_invalid |= !_temp.1;
// Extract delay list overflow
let mut target : GuestAddr = h.delay_queue_overflow;
target = freertos::emu_lookup::lookup(emulator, target);
let _temp = read_freertos_list(&mut systemstate, emulator, target);
systemstate.delay_list_overflow = _temp.0;
systemstate.read_invalid |= !_temp.1;
// Extract suspended tasks (infinite wait), seems broken, always appreas to be modified
// let mut target : GuestAddr = h.suspended_queue;
// target = freertos::emu_lookup::lookup(emulator, target);
// systemstate.suspended_list = read_freertos_list(&mut systemstate, emulator, target);
// Extract priority lists
for i in 0..NUM_PRIOS {
let target : GuestAddr = listbytes*GuestAddr::try_from(i).unwrap()+h.ready_queues;
let _temp = read_freertos_list(&mut systemstate, emulator, target);
systemstate.prio_ready_lists[i] = _temp.0;
systemstate.read_invalid |= !_temp.1;
}
} else {
systemstate.read_invalid = true;
}
systemstate.mem_reads = unsafe { MEM_READ.take().unwrap_or_default() };
unsafe { CURRENT_SYSTEMSTATE_VEC.push(systemstate); }
}
//============================= Trace job response times
pub static mut JOBS_DONE : Vec<(u64, String)> = vec![];
pub fn job_done_hook<QT, S>(
hooks: &mut QemuHooks<QT, S>,
_state: Option<&mut S>,
_pc: GuestAddr,
)
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
let emulator = hooks.qemu();
let h = hooks.helpers().match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr);
if curr_tcb_addr == 0 {
return;
};
let current_tcb : TCB_t = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
let tmp = unsafe {std::mem::transmute::<[i8; 10],[u8; 10]>(current_tcb.pcTaskName)};
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
unsafe { JOBS_DONE.push((get_icount(emulator), name)); }
}
//============================= Trace interrupt service routines
pub fn exec_isr_hook<QT, S>(
hooks: &mut QemuHooks<QT, S>,
_state: Option<&mut S>,
pc: GuestAddr,
)
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
let emulator = hooks.qemu();
let h = hooks.helpers().match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
let src = read_rec_return_stackframe(emulator, 0xfffffffc);
trigger_collection(emulator, (src, pc), CaptureEvent::ISRStart, h);
// println!("Exec ISR Call {:#x} {:#x} {}", src, pc, get_icount(emulator));
}
//============================= Trace syscalls and returns
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) && in_any_range(&h.isr_ranges,src).is_none() {
if let Some(_) = in_any_range(&h.api_fn_ranges,dest) {
// println!("New jmp {:x} {:x}", src, dest);
// println!("API Call Edge {:x} {:x}", src, dest);
return Some(1);
// TODO: trigger collection right here
// otherwise there can be a race-condition, where LAST_API_CALL is set before the api starts, if the interrupt handler calls an api function, it will misidentify the callsite of that api call
}
} else if dest == 0 { // !h.app_range.contains(&src) &&
if let Some(_) = in_any_range(&h.api_fn_ranges, src) {
// println!("API Return Edge {:#x}", src);
return Some(2);
}
if let Some(_) = in_any_range(&h.isr_ranges, src) {
// println!("ISR Return Edge {:#x}", src);
return Some(3);
}
}
}
return None;
}
pub fn trace_jmp<QT, S>(
hooks: &mut QemuHooks<QT, S>,
_state: Option<&mut S>,
src: GuestAddr, mut dest: GuestAddr, id: u64
)
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
let h = hooks.helpers().match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
let emulator = hooks.qemu();
if id == 1 { // API call
trigger_collection(emulator, (src, dest), CaptureEvent::APIStart, h);
// println!("Exec API Call {:#x} {:#x} {}", src, dest, get_icount(emulator));
} else if id == 2 { // API return
// Ignore returns to other APIs or ISRs. We only account for the first call depth of API calls from user space.
if in_any_range(&h.api_fn_ranges, dest).is_none() && in_any_range(&h.isr_ranges, dest).is_none() {
let mut edge = (0, 0);
edge.0=in_any_range(&h.api_fn_ranges, src).unwrap().start;
edge.1=dest;
trigger_collection(emulator, edge, CaptureEvent::APIEnd, h);
// println!("Exec API Return Edge {:#x} {:#x} {}", src, dest, get_icount(emulator));
}
} else if id == 3 { // ISR return
dest = read_rec_return_stackframe(emulator, dest);
let mut edge = (0, 0);
edge.0=in_any_range(&h.isr_ranges, src).unwrap().start;
edge.1=dest;
trigger_collection(emulator, edge, CaptureEvent::ISREnd, h);
// println!("Exec ISR Return Edge {:#x} {:#x} {}", src, dest, get_icount(emulator));
}
}
//============================= Read Hooks
#[allow(unused)]
pub fn gen_read_is_input<QT, S>(
hooks: &mut QemuHooks<QT, S>,
_state: Option<&mut S>,
pc: GuestAddr,
_addr: *mut TCGTemp,
_info: MemAccessInfo,
) -> Option<u64>
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
if let Some(h) = hooks.helpers().match_first_type::<QemuSystemStateHelper>() {
if h.app_range.contains(&pc) {
// println!("gen_read {:x}", pc);
return Some(1);
}
}
return None;
}
static mut INPUT_MEM : Range<GuestAddr> = 0..0;
static mut MEM_READ : Option<Vec<(GuestAddr, u8)>> = None;
#[allow(unused)]
pub fn trace_reads<QT, S>(
hooks: &mut QemuHooks<QT, S>,
_state: Option<&mut S>,
_id: u64,
addr: GuestAddr,
_size: usize
)
where
S: UsesInput,
QT: QemuHelperTuple<S>,
{
if unsafe { INPUT_MEM.contains(&addr) } {
let emulator = hooks.qemu();
let mut buf : [u8; 1] = [0];
unsafe {emulator.read_mem(addr, &mut buf);}
if unsafe { MEM_READ.is_none() } {
unsafe { MEM_READ = Some(Vec::from([(addr, buf[0])])) };
} else {
unsafe { MEM_READ.as_mut().unwrap().push((addr, buf[0])) };
}
// println!("exec_read {:x} {}", addr, size);
}
}
//============================= Utility functions
fn get_icount(emulator : &libafl_qemu::Qemu) -> u64 {
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()).neg.can_do_io;
(*c.raw_ptr()).neg.can_do_io = true;
let r = libafl_qemu::sys::icount_get_raw();
(*c.raw_ptr()).neg.can_do_io = can_do_io;
r
}
}
fn read_rec_return_stackframe(emu : &libafl_qemu::Qemu, lr : GuestAddr) -> GuestAddr {
let lr_ = lr & u32::MAX-1;
if lr_ == 0xfffffffc || lr_ == 0xFFFFFFF8 || lr_ == 0xFFFFFFF0 {
unsafe {
// if 0xFFFFFFF0/1 0xFFFFFFF8/9 -> "main stack" MSP
let mut buf = [0u8; 4];
let sp : GuestAddr = if lr_ == 0xfffffffc || lr_ == 0xFFFFFFF0 { // PSP
read_user_reg_unchecked(emu) as u32
} else {
emu.read_reg(13).unwrap()
};
let ret_pc = sp+0x18; // https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/exception-entry-and-return
emu.read_mem(ret_pc, buf.as_mut_slice());
return u32::from_le_bytes(buf);
// elseif 0xfffffffc/d
}} else {
return lr;
};
}
pub fn in_any_range<'a>(ranges: &'a Vec<(String, Range<u32>)>, addr : GuestAddr) -> Option<&'a std::ops::Range<GuestAddr>> {
for (_,r) in ranges {
if r.contains(&addr) {return Some(r);}
}
return None;
}

View File

@ -0,0 +1,532 @@
//! systemstate referes to the State of a FreeRTOS fuzzing target
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use hashbrown::HashSet;
use libafl_bolts::HasRefCnt;
use libafl_qemu::GuestAddr;
use std::hash::Hasher;
use std::hash::Hash;
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use itertools::Itertools;
use freertos::TCB_t;
pub mod freertos;
pub mod helpers;
pub mod observers;
pub mod feedbacks;
pub mod schedulers;
pub mod stg;
pub mod mutational;
pub mod report;
// Constants
const NUM_PRIOS: usize = 15;
//============================= Struct definitions
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CaptureEvent {
APIStart, /// src,dst
APIEnd, /// src,dst
ISRStart, /// _,dst
ISREnd, /// src,_
End, /// src,_
#[default]
Undefined,
}
/*
Hierarchy of tracing data:
- RawFreeRTOSSystemState: Raw data from Qemu, represents a particular instant
- ReducedFreeRTOSSystemState: Generalized state of the system, without execution context
- ExecInterval: Some interval of execution between instants
- AtomicBasicBlock: A single-entry multiple-exit region between api calls. May be used referenced in multiple intervals.
- JobInstance: A single execution of a task, records the place and input read
- TaskJob: Generalized Job instance, records the worst inputs seen so far
*/
// ============================= State info
/// Raw info Dump from Qemu
#[derive(Debug, Default)]
pub struct RawFreeRTOSSystemState {
qemu_tick: u64,
current_tcb: TCB_t,
prio_ready_lists: [freertos::List_t; NUM_PRIOS],
delay_list: freertos::List_t,
delay_list_overflow: freertos::List_t,
dumping_ground: HashMap<u32,freertos::rtos_struct>,
read_invalid: bool,
input_counter: u32,
edge: (GuestAddr,GuestAddr),
capture_point: (CaptureEvent,String),
mem_reads: Vec<(u32, u8)>
}
/// 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)]
pub struct RefinedTCB {
pub task_name: String,
pub priority: u32,
pub base_priority: u32,
mutexes_held: u32,
// notify_value: u32,
notify_state: u8,
}
impl PartialEq for RefinedTCB {
fn eq(&self, other: &Self) -> bool {
let ret = self.task_name == other.task_name &&
self.priority == other.priority &&
self.base_priority == other.base_priority;
#[cfg(feature = "do_hash_notify_state")]
let ret = ret && self.notify_state == other.notify_state;
ret
}
}
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(feature = "do_hash_notify_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],
}
}
}
}
/// Reduced information about a systems state, without any execution context
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct ReducedFreeRTOSSystemState {
// pub tick: u64,
pub current_task: RefinedTCB,
ready_list_after: Vec<RefinedTCB>,
delay_list_after: Vec<RefinedTCB>,
read_invalid: bool,
// edge: (Option<GuestAddr>,Option<GuestAddr>),
// pub capture_point: (CaptureEvent,String),
// input_counter: u32
}
impl PartialEq for ReducedFreeRTOSSystemState {
fn eq(&self, other: &Self) -> bool {
self.current_task == other.current_task && self.ready_list_after == other.ready_list_after &&
self.delay_list_after == other.delay_list_after && self.read_invalid == other.read_invalid
// && self.edge == other.edge
// && self.capture_point == other.capture_point
}
}
impl Hash for ReducedFreeRTOSSystemState {
fn hash<H: Hasher>(&self, state: &mut H) {
self.current_task.hash(state);
self.ready_list_after.hash(state);
self.delay_list_after.hash(state);
self.read_invalid.hash(state);
}
}
impl ReducedFreeRTOSSystemState {
// fn get_tick(&self) -> u64 {
// self.tick
// }
pub fn print_lists(&self) -> String {
let mut ret = String::from("+");
for j in self.ready_list_after.iter() {
ret.push_str(format!(" {}", j.task_name).as_str());
}
ret.push_str("\n-");
for j in self.delay_list_after.iter() {
ret.push_str(format!(" {}", j.task_name).as_str());
}
ret
}
pub fn get_hash(&self) -> u64 {
let mut h = DefaultHasher::new();
self.hash(&mut h);
h.finish()
}
}
impl fmt::Display for ReducedFreeRTOSSystemState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ready = self.ready_list_after.iter().map(|x| x.task_name.clone()).collect::<Vec<_>>().join(" ");
let delay = self.delay_list_after.iter().map(|x| x.task_name.clone()).collect::<Vec<_>>().join(" ");
write!(f, "Valid: {} | Current: {} | Ready: {} | Delay: {}", u32::from(!self.read_invalid), self.current_task.task_name, ready, delay)
}
}
// ============================= Interval info
// #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
// pub enum ExecLevel {
// APP = 0,
// API = 1,
// ISR = 2,
// }
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct ExecInterval {
pub start_tick: u64,
pub end_tick: u64,
pub start_state: u64,
pub end_state: u64,
pub start_capture: (CaptureEvent, String),
pub end_capture: (CaptureEvent, String),
pub level: u8,
tick_spend_preempted: u64,
pub abb: Option<AtomicBasicBlock>
}
impl ExecInterval {
pub fn get_exec_time(&self) -> u64 {
self.end_tick-self.start_tick-self.tick_spend_preempted
}
pub fn is_valid(&self) -> bool {
self.start_tick != 0 || self.end_tick != 0
}
pub fn invaildate(&mut self) {
self.start_tick = 0;
self.end_tick = 0;
}
/// Attach this interval to the later one, keep a record of the time spend preempted
pub fn try_unite_with_later_interval(&mut self, later_interval : &mut Self) -> bool {
if self.end_state!=later_interval.start_state || self.abb!=later_interval.abb || !self.is_valid() || !later_interval.is_valid() {
return false;
}
// assert_eq!(self.end_state, later_interval.start_state);
// assert_eq!(self.abb, later_interval.abb);
later_interval.tick_spend_preempted += self.tick_spend_preempted + (later_interval.start_tick-self.end_tick);
later_interval.start_tick = self.start_tick;
later_interval.start_state = self.start_state;
self.invaildate();
return true;
}
pub fn get_hash_index(&self) -> (u64, u64) {
return (self.start_state, self.abb.as_ref().expect("ABB not set").get_hash())
}
pub fn get_task_name(&self) -> Option<String> {
self.abb.as_ref().map(|x| x.instance_name.clone()).flatten()
}
pub fn get_task_name_unchecked(&self) -> String {
self.get_task_name().unwrap_or_else(|| "unknown".to_string())
}
pub fn is_abb_end(&self) -> bool {
match self.end_capture.0 {
CaptureEvent::APIStart | CaptureEvent::APIEnd | CaptureEvent::ISREnd | CaptureEvent::End => true,
_ => false
}
}
}
// ============================= Atomic Basic Block
/// A single-entry multiple-exit region between api calls. May be used referenced in multiple intervals.
#[derive(Default, Serialize, Deserialize, Clone)]
pub struct AtomicBasicBlock {
start: GuestAddr,
ends: HashSet<GuestAddr>,
level: u8,
instance_id: usize,
instance_name: Option<String>,
}
impl PartialEq for AtomicBasicBlock {
fn eq(&self, other: &Self) -> bool {
self.start == other.start && self.ends == other.ends && self.level == other.level && self.instance_name == other.instance_name
}
}
impl Eq for AtomicBasicBlock {}
impl Hash for AtomicBasicBlock {
fn hash<H: Hasher>(&self, state: &mut H) {
// Use a combination of the start address and the set of ending addresses to compute the hash value
self.start.hash(state);
let mut keys : Vec<_> = self.ends.iter().collect();
keys.sort();
self.level.hash(state);
self.instance_name.hash(state);
keys.hash(state);
}
}
impl fmt::Display for AtomicBasicBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut ends_str = String::new();
for end in &self.ends {
ends_str.push_str(&format!("0x{:#x}, ", end));
}
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(','))
}
}
impl fmt::Debug for AtomicBasicBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut ends_str = String::new();
for end in &self.ends {
ends_str.push_str(&format!("{:#x}, ", end));
}
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(','))
}
}
impl PartialOrd for AtomicBasicBlock {
fn partial_cmp(&self, other: &AtomicBasicBlock) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AtomicBasicBlock {
fn cmp(&self, other: &AtomicBasicBlock) -> std::cmp::Ordering {
if self.start.cmp(&other.start) == std::cmp::Ordering::Equal {
if self.level.cmp(&other.level) != std::cmp::Ordering::Equal {
return self.level.cmp(&other.level);
}
// If the start addresses are equal, compare by 'ends'
let end1 = if self.ends.len() == 1 { *self.ends.iter().next().unwrap() as u64 } else {
let mut temp = self.ends.iter().collect::<Vec<_>>().into_iter().collect::<Vec<&GuestAddr>>();
temp.sort_unstable();
let mut h = DefaultHasher::new();
temp.hash(&mut h);
h.finish()
};
let end2 = if other.ends.len() == 1 { *self.ends.iter().next().unwrap() as u64 } else {
let mut temp = other.ends.iter().collect::<Vec<_>>().into_iter().collect::<Vec<&GuestAddr>>();
temp.sort_unstable();
let mut h = DefaultHasher::new();
temp.hash(&mut h);
h.finish()
};
end1.cmp(&end2)
} else {
// If the start addresses are not equal, compare by 'start'
self.start.cmp(&other.start)
}
}
}
impl AtomicBasicBlock {
pub fn get_hash(&self) -> u64 {
let mut s = DefaultHasher::new();
self.hash(&mut s);
s.finish()
}
pub fn instance_eq(&self, other: &Self) -> bool {
self == other && self.instance_id == other.instance_id
}
}
fn get_task_names(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashSet<String> {
let mut ret: HashSet<_, _> = HashSet::new();
for state in trace {
ret.insert(state.current_task.task_name.to_string());
}
ret
}
libafl_bolts::impl_serdeany!(AtomicBasicBlock);
// ============================= Job instances
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct JobInstance {
pub name: String,
pub mem_reads: Vec<(u32, u8)>,
pub release: u64,
pub response: u64,
pub exec_ticks: u64,
pub ticks_per_abb: Vec<u64>,
pub abbs: Vec<AtomicBasicBlock>,
hash_cache: u64
}
impl PartialEq for JobInstance {
fn eq(&self, other: &Self) -> bool {
self.abbs == other.abbs
}
}
impl Eq for JobInstance {}
impl Hash for JobInstance {
fn hash<H: Hasher>(&self, state: &mut H) {
self.abbs.hash(state);
}
}
impl JobInstance {
pub fn get_hash(&mut self) -> u64 {
if self.hash_cache == 0 {
let mut s = DefaultHasher::new();
self.hash(&mut s);
self.hash_cache = s.finish();
}
self.hash_cache
}
pub fn get_hash_cached(&self) -> u64 {
if self.hash_cache == 0 {
let mut s = DefaultHasher::new();
self.hash(&mut s);
s.finish()
} else {
self.hash_cache
}
}
}
// ============================= Generalized job instances
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct TaskJob {
pub name: String,
pub worst_bytes: Vec<u8>,
pub woet_ticks: u64,
pub woet_per_abb: Vec<u64>,
pub abbs: Vec<AtomicBasicBlock>,
hash_cache: u64
}
impl PartialEq for TaskJob {
fn eq(&self, other: &Self) -> bool {
self.abbs == other.abbs
}
}
impl Eq for TaskJob {}
impl Hash for TaskJob {
fn hash<H: Hasher>(&self, state: &mut H) {
self.abbs.hash(state);
}
}
impl TaskJob {
pub fn get_hash(&mut self) -> u64 {
if self.hash_cache == 0 {
let mut s = DefaultHasher::new();
self.hash(&mut s);
self.hash_cache = s.finish();
}
self.hash_cache
}
pub fn get_hash_cached(&self) -> u64 {
if self.hash_cache == 0 {
let mut s = DefaultHasher::new();
self.hash(&mut s);
s.finish()
} else {
self.hash_cache
}
}
pub fn try_update(&mut self, other: &JobInstance) -> bool {
assert_eq!(self.get_hash(), other.get_hash_cached());
let mut ret = false;
if other.exec_ticks > self.woet_ticks {
self.woet_ticks = other.exec_ticks;
self.woet_per_abb = other.ticks_per_abb.clone();
self.worst_bytes = other.mem_reads.iter().sorted_by(|a,b| a.0.cmp(&b.0)).map(|x| x.1).collect();
ret = true;
}
ret
}
pub fn from_instance(input: &JobInstance) -> Self {
let c = input.get_hash_cached();
Self {
name: input.name.clone(),
worst_bytes: input.mem_reads.iter().map(|x| x.1.clone()).collect(),
woet_ticks: input.exec_ticks,
woet_per_abb: input.ticks_per_abb.clone(),
abbs: input.abbs.clone(),
hash_cache: c
}
}
pub fn map_bytes_onto(&self, input: &JobInstance, offset: Option<u32>) -> Vec<(u32,u8)> {
if input.mem_reads.len() == 0 {return vec![];}
let ret = input.mem_reads.iter().take(self.worst_bytes.len()).enumerate().filter_map(|(idx,(addr,oldbyte))| if self.worst_bytes[idx]!=*oldbyte {Some((*addr-offset.unwrap_or_default(), self.worst_bytes[idx]))} else {None}).collect();
// eprintln!("Mapped: {:?}", ret);
ret
}
}
// ============================= Per testcase metadata
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct FreeRTOSSystemStateMetadata {
pub inner: Vec<ReducedFreeRTOSSystemState>,
// TODO: Add abbs and memory reads
trace_length: usize,
indices: Vec<usize>, // Hashed enumeration of States
tcref: isize,
}
impl FreeRTOSSystemStateMetadata {
pub fn new(inner: Vec<ReducedFreeRTOSSystemState>) -> 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_bolts::impl_serdeany!(FreeRTOSSystemStateMetadata);

View File

@ -0,0 +1,598 @@
//| 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 hashbrown::HashMap;
use libafl_bolts::{rands::{
random_seed, Rand, StdRand
}, Named};
use libafl::{
common::{HasMetadata, HasNamedMetadata}, corpus::{self, Corpus}, events::{Event, EventFirer, EventProcessor, LogSeverity}, fuzzer::Evaluator, inputs::{HasMutatorBytes, HasTargetBytes, Input, MultipartInput}, mark_feature_time, prelude::{new_hash_feedback, AggregatorOps, CorpusId, MutationResult, Mutator, UserStats, UserStatsValue, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error
};
use libafl::prelude::State;
use petgraph::{graph::NodeIndex, graph::{self, DiGraph}};
use crate::{time::clock::{IcHist, QEMU_ISNS_PER_USEC}, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT, MAX_NUM_INTERRUPT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, CaptureEvent, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}};
use libafl::state::HasCurrentTestcase;
use std::borrow::Cow;
use simple_moving_average::SMA;
use super::{stg::{STGEdge, STGNode}, JobInstance};
// pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
// one isn per 2**4 ns
// virtual insn/sec 62500000 = 1/16 GHz
// 1ms = 62500 insn
// 1us = 62.5 insn
pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u32> {
let len = buf.len();
let mut start_tick;
let mut ret = Vec::with_capacity(min(DO_NUM_INTERRUPT, len/4));
for i in 0..DO_NUM_INTERRUPT {
let mut buf4b : [u8; 4] = [0,0,0,0];
if len >= (i+1)*4 {
for j in 0usize..4usize {
buf4b[j]=buf[i*4+j];
}
start_tick = u32::from_le_bytes(buf4b);
if start_tick < FIRST_INT {start_tick=0;}
ret.push(start_tick);
} else {break;}
}
ret.sort_unstable();
// obey the minimum inter arrival time while maintaining the sort
for i in 0..ret.len() {
if ret[i]==0 {continue;}
for j in i+1..ret.len()-1 {
if ret[j]-ret[i] < config.1 as u32 * QEMU_ISNS_PER_USEC {
// ret[j] = u32::saturating_add(ret[i],config.1 * QEMU_ISNS_PER_USEC);
ret[j] = 0; // remove the interrupt
ret.sort_unstable();
} else {break;}
}
}
ret
}
pub fn interrupt_times_to_input_bytes(interrupt_times: &[u32]) -> Vec<u8> {
let mut ret = Vec::with_capacity(interrupt_times.len()*4);
for i in interrupt_times {
ret.extend(u32::to_le_bytes(*i));
}
ret
}
//======================= Custom mutator
fn is_interrupt_handler(graph: &DiGraph<STGNode, STGEdge>, node: NodeIndex) -> bool {
graph.edges_directed(node as NodeIndex, petgraph::Direction::Incoming).any(|x| x.weight().event == CaptureEvent::ISRStart)
}
fn has_interrupt_handler_non_systick(graph: &DiGraph<STGNode, STGEdge>, node: NodeIndex) -> bool {
graph.edges_directed(node as NodeIndex, petgraph::Direction::Outgoing).any(|x| x.weight().event == CaptureEvent::ISRStart && x.weight().name!="xPortSysTickHandler")
}
fn is_candidate_for_new_branches(graph: &DiGraph<STGNode, STGEdge>, node: NodeIndex) -> bool {
!has_interrupt_handler_non_systick(graph, node) && !is_interrupt_handler(graph, node)
}
// TODO: this can be much more efficient, if the graph stored snapshots of the state and input progress was tracked
/// Determines if a given node in the state transition graph (STG) is a candidate for introducing new branches.
pub fn try_force_new_branches(interrupt_ticks : &[u32], fbs: &STGFeedbackState, meta: &STGNodeMetadata, config: (usize, u32)) -> Option<Vec<u32>> {
let mut new = false;
let mut new_interrupt_times = Vec::new();
for (num,&interrupt_time) in interrupt_ticks.iter().enumerate() {
let lower_bound = if num==0 {FIRST_INT} else {interrupt_ticks[num-1].saturating_add(config.1 * QEMU_ISNS_PER_USEC)};
let next = if interrupt_ticks.len()>num+1 {interrupt_ticks[num+1]} else {u32::MAX};
for exec_interval in meta.intervals().iter().filter(|x| x.start_tick >= lower_bound as u64 && x.start_tick < next as u64) {
if !(exec_interval.start_capture.0==CaptureEvent::ISRStart) { // shortcut to skip interrupt handers without node lookup
let node_index = fbs.state_abb_hash_index.get(&exec_interval.get_hash_index()).unwrap();
if !has_interrupt_handler_non_systick(&fbs.graph, node_index.clone()) {
let new_time = exec_interval.start_tick.saturating_add((exec_interval.end_tick+exec_interval.start_tick)/4);
new_interrupt_times.push(new_time.try_into().expect("ticks > u32"));
if (new_time + config.1 as u64) < next as u64 { // the new interrupt is not too close to the next one
new_interrupt_times.extend(interrupt_ticks.iter().skip(num).cloned());
} else { // the new interrupt is too close to the next one, skip the next one
new_interrupt_times.extend(interrupt_ticks.iter().skip(num+1).cloned());
}
new=true;
break;
}
}
}
if new {break;}
new_interrupt_times.push(interrupt_time);
}
if new {Some(new_interrupt_times)} else {None}
}
/// The default mutational stage
#[derive(Clone, Debug)]
pub struct InterruptShiftStage<E, EM, Z> {
#[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, Z)>,
interrup_config: Vec<(usize,u32)>,
success: simple_moving_average::SingleSumSMA<f32, f32, 50>
}
impl<E, EM, Z> InterruptShiftStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
{
pub fn new(config : &Vec<(usize,u32)>) -> Self {
Self { phantom: PhantomData, interrup_config: config.clone(), success: simple_moving_average::SingleSumSMA::from_zero(1.0) }
}
}
static mut num_stage_execs : u64 = 0;
static mut sum_reruns : u64 = 0;
static mut sum_interesting_reruns : u64 = 0;
impl<E, EM, Z, I> InterruptShiftStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
EM: EventFirer,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
<Z::State as UsesInput>::Input: Input,
Z::State: UsesInput<Input = MultipartInput<I>>,
I: HasMutatorBytes + Default
{
fn report_stats(&self, state: &mut <InterruptShiftStage<E, EM, Z> as UsesState>::State, manager: &mut EM) {
unsafe {
let _ = manager.fire(
state,
Event::UpdateUserStats {
name: Cow::from("InterruptShiftStage"),
value: UserStats::new(
UserStatsValue::String(Cow::from(format!("{} -> {}/{} {:.1}% ", num_stage_execs, sum_interesting_reruns, sum_reruns, sum_interesting_reruns as f32 * 100.0 / sum_reruns as f32))),
AggregatorOps::None,
),
phantom: PhantomData,
},
);
}
}
}
impl<E, EM, Z, I> Stage<E, EM, Z> for InterruptShiftStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
EM: EventFirer,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
<Z::State as UsesInput>::Input: Input,
Z::State: UsesInput<Input = MultipartInput<I>>,
I: HasMutatorBytes + Default
{
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Self::State,
manager: &mut EM
) -> Result<(), Error> {
if self.interrup_config.len() == 0 {return Ok(());} // configuration implies no interrupts
let mut myrand = StdRand::new();
myrand.set_seed(state.rand_mut().next());
unsafe {num_stage_execs+=1;}
let mut rerun_count = 0; // count how many times we rerun the executor
let mut interesting_rerun_count = 0; // count how many reruns were interesting
// Try many times to find a mutation that is not already in the corpus
let loopbound = max(1, (self.success.get_average()*100.0) as usize);
for _ in 0..loopbound {
// Choose which isr to mutate
let interrup_config = match myrand.choose(&self.interrup_config) {
Some(s) => s,
Option::None => {
self.report_stats(state, manager);
return Ok(())
}
};
let name = format!("isr_{}_times", interrup_config.0);
// manager.log(state, LogSeverity::Info, format!("Mutation {}/{}", loopbound, loopcount))?;
let curr_case = state.current_testcase()?;
let curr_input = curr_case.input().as_ref().unwrap();
let mut new_input = curr_input.clone();
let new_interrupt_part : &mut I = if new_input.parts_by_name(&name).next().is_some() {
new_input.parts_by_name_mut(&name).next().unwrap()
} else {
new_input.add_part(String::from(&name), I::default()); new_input.parts_by_name_mut(&name).next().unwrap()
}.1;
let old_interrupt_times = input_bytes_to_interrupt_times(new_interrupt_part.bytes(), *interrup_config);
let mut new_interrupt_times = Vec::with_capacity(MAX_NUM_INTERRUPT);
let mut do_rerun = false;
// if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time
{
#[cfg(feature = "mutate_stg")]
{
let metadata = state.metadata_map();
let maxtick = {metadata.get::<IcHist>().unwrap().1.0};
drop(new_interrupt_part.drain(..).collect::<Vec<u8>>());
{
let choice = myrand.between(1,100);
if choice <= 25 || *old_interrupt_times.get(0).unwrap_or(&u32::MAX) as u64 > maxtick { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts
do_rerun = true;
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();
for _ in 0..myrand.between(0,min(MAX_NUM_INTERRUPT, (maxtick as usize * 3) / (interrup_config.1 as usize * QEMU_ISNS_PER_USEC as usize * 2))) {
new_interrupt_times.push(myrand.between(0, min(maxtick, u32::MAX as u64) as usize).try_into().expect("ticks > u32"));
}
}
else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases
let feedbackstate = match state
.named_metadata_map()
.get::<STGFeedbackState>("stgfeedbackstate") {
Some(s) => s,
Option::None => {
panic!("STGfeedbackstate not visible")
}
};
if let Some(meta) = curr_case.metadata_map().get::<STGNodeMetadata>() {
if let Some(t) = try_force_new_branches(&old_interrupt_times, feedbackstate, meta, *interrup_config) {
do_rerun = true;
new_interrupt_times=t;
}
}
// let tmp = current_case.metadata_map().get::<STGNodeMetadata>();
// if tmp.is_some() {
// let trace = tmp.expect("STGNodeMetadata not found");
// let mut node_indices = vec![];
// for i in (0..trace.intervals.len()).into_iter() {
// if let Some(abb) = &trace.intervals[i].abb {
// if let Some(idx) = feedbackstate.state_abb_hash_index.get(&(trace.intervals[i].start_state,abb.get_hash())) {
// node_indices.push(Some(idx));
// continue;
// }
// }
// node_indices.push(None);
// }
// // let mut marks : HashMap<u32, usize>= HashMap::new(); // interrupt -> block hit
// // for i in 0..trace.intervals.len() {
// // let curr = &trace.intervals[i];
// // let m = interrupt_offsets[0..num_interrupts].iter().filter(|x| (curr.start_tick..curr.end_tick).contains(&((**x) as u64)));
// // for k in m {
// // marks.insert(*k,i);
// // }
// // }
// // walk backwards trough the trace and try moving the interrupt to a block that does not have an outgoing interrupt edge or ist already hit by a predecessor
// for i in (0..num_interrupts).rev() {
// let mut lb = FIRST_INT;
// let mut ub : u32 = trace.intervals[trace.intervals.len()-1].end_tick.try_into().expect("ticks > u32");
// if i > 0 {
// lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME});
// }
// if i < num_interrupts-1 {
// ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME});
// }
// let alternatives : Vec<_> = (0..trace.intervals.len()).filter(|x|
// node_indices[*x].is_some() &&
// (trace.intervals[*x].start_tick < (lb as u64) && (lb as u64) < trace.intervals[*x].end_tick
// || trace.intervals[*x].start_tick > (lb as u64) && trace.intervals[*x].start_tick < (ub as u64))
// ).collect();
// let not_yet_hit : Vec<_> = alternatives.iter().filter(
// |x| feedbackstate.graph.edges_directed(*node_indices[**x].unwrap(), petgraph::Direction::Outgoing).any(|y| y.weight().event != CaptureEvent::ISRStart)).collect();
// if not_yet_hit.len() > 0 {
// let replacement = &trace.intervals[*myrand.choose(not_yet_hit).unwrap()];
// interrupt_offsets[i] = (myrand.between(replacement.start_tick as usize,
// replacement.end_tick as usize)).try_into().expect("ticks > u32");
// // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
// do_rerun = true;
// break;
// }
// }
// }
}
else { // old version of the alternative search
new_interrupt_times = old_interrupt_times.clone();
let tmp = curr_case.metadata_map().get::<STGNodeMetadata>();
if tmp.is_some() {
let trace = tmp.expect("STGNodeMetadata not found");
// calculate hits and identify snippets
let mut last_m = false;
let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
for i in 0..trace.intervals().len() {
let curr = &trace.intervals()[i];
let m = old_interrupt_times.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.0.task_name);
} else if last_m {
marks.push((curr, i, 2));
// println!("2: {}",curr.current_task.0.task_name);
} else {
marks.push((curr, i, 0));
}
last_m = m;
}
for i in 0..old_interrupt_times.len() {
// bounds based on minimum inter-arrival time
let mut lb = FIRST_INT;
let mut ub : u32 = trace.intervals()[trace.intervals().len()-1].end_tick.try_into().expect("ticks > u32");
if i > 0 {
// use the new times, because changes to preceding timings are not accounted for yet
lb = u32::saturating_add(new_interrupt_times[i-1], interrup_config.1 * QEMU_ISNS_PER_USEC);
}
if i < old_interrupt_times.len()-1 {
ub = u32::saturating_sub(new_interrupt_times[i+1], interrup_config.1 * QEMU_ISNS_PER_USEC);
}
// get old hit and handler
let old_hit = marks.iter().filter(
|x| x.0.start_tick < (old_interrupt_times[i] as u64) && (old_interrupt_times[i] as u64) < x.0.end_tick
).next();
let old_handler = match old_hit {
Some(s) => if s.1 < old_interrupt_times.len()-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 > (lb as u64) && x.0.start_tick < (ub as u64))
).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 = old_interrupt_times[i];
let choice = myrand.choose(untouched).unwrap();
new_interrupt_times[i] = myrand.between(choice.0.start_tick as usize, choice.0.end_tick as usize)
.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).unwrap();
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 = new_interrupt_times[i];
new_interrupt_times[i] = (myrand.between(replacement.0.start_tick as usize,
replacement.0.end_tick as usize) + extra as usize).try_into().expect("ticks > u32");
// println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
do_rerun = true;
}
}
// 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;
// }
new_interrupt_part.extend(&interrupt_times_to_input_bytes(&new_interrupt_times));
}
}
}
}
#[cfg(not(feature = "trace_stg"))]
{
if myrand.between(1,100) <= 25 { // we have no hint if interrupt times will change anything
do_rerun = true;
let metadata = state.metadata_map();
let maxtick = {metadata.get::<IcHist>().unwrap().1.0};
new_interrupt_times = Vec::with_capacity(MAX_NUM_INTERRUPT);
for i in 0..myrand.between(0,min(MAX_NUM_INTERRUPT, (maxtick as usize * 3) / (interrup_config.1 as usize * QEMU_ISNS_PER_USEC as usize * 2))) {
new_interrupt_times.push(myrand.between(0, min(maxtick, u32::MAX as u64) as usize).try_into().expect("ticks > u32"));
}
}
}
new_interrupt_part.extend(&interrupt_times_to_input_bytes(&new_interrupt_times));
}
drop(curr_case);
if do_rerun {
rerun_count+=1;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, new_input)?;
if corpus_idx.is_some() { unsafe{interesting_rerun_count+=1;}} else
if corpus_idx.is_none() && loopbound<=0 { break;}
} else {if loopbound<=0 {break;}}
}
unsafe {
sum_reruns+=rerun_count;
sum_interesting_reruns+=interesting_rerun_count;
if rerun_count>0 {self.success.add_sample(interesting_rerun_count as f32 / rerun_count as f32);}
}
self.report_stats(state, manager);
Ok(())
}
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
Ok(true)
}
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
Ok(())
}
}
impl<E, EM, Z> UsesState for InterruptShiftStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
{
type State = Z::State;
}
pub fn try_worst_snippets(bytes : &[u8], fbs: &STGFeedbackState, meta: &STGNodeMetadata) -> Option<Vec<u8>> {
let mut new = false;
let mut ret = Vec::new();
for (num,interval) in meta.intervals().iter().enumerate() {
todo!();
}
if new {Some(ret)} else {None}
}
static mut num_snippet_stage_execs : u64 = 0;
static mut num_snippet_rerun : u64 = 0;
static mut num_snippet_success : u64 = 0;
/// The default mutational stage
#[derive(Clone, Debug, Default)]
pub struct STGSnippetStage<E, EM, Z> {
#[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, Z)>,
input_addr: u32
}
impl<E, EM, Z> STGSnippetStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
{
pub fn new(input_addr: u32) -> Self {
Self { phantom: PhantomData, input_addr }
}
}
impl<E, EM, Z, I> STGSnippetStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
EM: EventFirer,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
<Z::State as UsesInput>::Input: Input,
Z::State: UsesInput<Input = MultipartInput<I>>,
I: HasMutatorBytes + Default
{
fn report_stats(&self, state: &mut <STGSnippetStage<E, EM, Z> as UsesState>::State, manager: &mut EM) {
unsafe {
let _ = manager.fire(
state,
Event::UpdateUserStats {
name: Cow::from("STGSnippetStage"),
value: UserStats::new(
UserStatsValue::String(Cow::from(format!("{} -> {}/{} {:.1}% ", num_snippet_stage_execs, num_snippet_success, num_snippet_rerun, num_snippet_success as f32 * 100.0 / num_snippet_rerun as f32))),
AggregatorOps::None,
),
phantom: PhantomData,
},
);
}
}
}
impl<E, EM, Z, I> Stage<E, EM, Z> for STGSnippetStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
EM: EventFirer,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
<Z::State as UsesInput>::Input: Input,
Z::State: UsesInput<Input = MultipartInput<I>>,
I: HasMutatorBytes + Default
{
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Self::State,
manager: &mut EM
) -> Result<(), Error> {
let mut myrand = StdRand::new();
myrand.set_seed(state.rand_mut().next());
let mut do_rerun = false;
let current_case = state.current_testcase()?;
let old_input = current_case.input().as_ref().unwrap();
let mut new_input = old_input.clone();
let new_bytes = new_input.parts_by_name_mut("bytes").next().expect("bytes not found in multipart input").1.bytes_mut();
// dbg!(current_case.metadata_map());
// eprintln!("Run mutator {}", current_case.metadata_map().get::<STGNodeMetadata>().is_some());
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() {
let feedbackstate = match state
.named_metadata_map()
.get::<STGFeedbackState>("stgfeedbackstate") {
Some(s) => s,
Option::None => {
panic!("STGfeedbackstate not visible")
}
};
// Maximize all snippets
// dbg!(meta.jobs().len());
for jobinst in meta.jobs().iter() {
match feedbackstate.worst_task_jobs.get(&jobinst.get_hash_cached()) {
Some(worst) => {
let new = worst.map_bytes_onto(jobinst, Some(self.input_addr));
do_rerun |= new.len() > 0;
for (addr, byte) in new {
if (addr as usize) < new_bytes.len() {
new_bytes[addr as usize] = byte;
}
}
},
Option::None => {}
}
}
}
drop(current_case);
unsafe {num_snippet_stage_execs+=1;}
if do_rerun {
unsafe {num_snippet_rerun+=1;}
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, new_input)?;
if corpus_idx.is_some() { unsafe{num_snippet_success+=1; self.report_stats(state, manager);}}
} else if {unsafe{num_snippet_stage_execs}} % 5 == 0 {self.report_stats(state, manager);}
Ok(())
}
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
Ok(true)
}
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
Ok(())
}
}
impl<E, EM, Z> UsesState for STGSnippetStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
{
type State = Z::State;
}

View File

@ -0,0 +1,682 @@
use libafl::prelude::ExitKind;
use libafl::prelude::UsesInput;
use libafl::HasMetadata;
use libafl_bolts::HasLen;
use libafl_bolts::Named;
use libafl::Error;
use libafl::observers::Observer;
use serde::{Deserialize, Serialize};
use hashbrown::{HashMap, HashSet};
use crate::systemstate::CaptureEvent;
use crate::time::clock::IcHist;
use crate::time::clock::FUZZ_START_TIMESTAMP;
use std::time::SystemTime;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::borrow::Cow;
use super::helpers::USR_ISR_SYMBOLS;
use super::JobInstance;
use super::{ AtomicBasicBlock, ExecInterval};
use super::{
CURRENT_SYSTEMSTATE_VEC,
RawFreeRTOSSystemState,
RefinedTCB,
ReducedFreeRTOSSystemState,
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
helpers::JOBS_DONE,
};
//============================= Observer
/// The Qemusystemstate Observer retrieves the systemstate
/// that will get updated by the target.
#[derive(Serialize, Deserialize, Debug)]
#[allow(clippy::unsafe_derive_deserialize)]
pub struct QemuSystemStateObserver<I>
{
pub last_run: Vec<ReducedFreeRTOSSystemState>,
pub last_states: HashMap<u64, ReducedFreeRTOSSystemState>,
pub last_trace: Vec<ExecInterval>,
pub last_reads: Vec<Vec<(u32, u8)>>,
pub last_input: I,
pub job_instances: Vec<JobInstance>,
pub do_report: bool,
pub worst_job_instances: HashMap<String, JobInstance>,
pub select_task: Option<String>,
pub success: bool,
name: Cow<'static, str>,
}
impl<S> Observer<S> for QemuSystemStateObserver<S::Input>
where
S: UsesInput + HasMetadata,
S::Input: Default
{
#[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 = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
unsafe {
let temp = refine_system_states(CURRENT_SYSTEMSTATE_VEC.split_off(0));
// fix_broken_trace(&mut temp.1);
self.last_run = temp.0.clone();
// println!("{:?}",temp);
let temp = states2intervals(temp.0, temp.1);
self.last_trace = temp.0;
self.last_reads = temp.1;
self.last_states = temp.2;
self.success = temp.3;
#[cfg(feature="trace_job_response_times")]
{
let metadata =_state.metadata_map_mut();
let releases = get_releases(&self.last_trace, &self.last_states);
// println!("Releases: {:?}",&releases);
let jobs_done = JOBS_DONE.split_off(0);
let (job_instances, do_report) = get_release_response_pairs(&releases, &jobs_done);
self.do_report = do_report;
let job_instances = job_instances.into_iter().map(|x| {
let intervals = self.last_trace.iter().enumerate().filter(|y| y.1.start_tick <= x.1 && y.1.end_tick >= x.0 && x.2 == y.1.get_task_name_unchecked()).map(|(idx,x)| (x, &self.last_reads[idx])).collect::<Vec<_>>();
let (abbs, rest) : (Vec<_>, Vec<_>) = intervals.chunk_by(|a,b| a.0.abb.as_ref().unwrap().instance_eq(b.0.abb.as_ref().unwrap())).into_iter().map(|intervals| (intervals[0].0.abb.as_ref().unwrap().clone(), (intervals.iter().fold(0, |sum, x| sum+x.0.get_exec_time()), intervals.iter().fold(Vec::new(), |mut sum, x| {sum.extend(x.1.iter()); sum})))).unzip();
let (ticks_per_abb, mem_reads) : (Vec<_>, Vec<_>) = rest.into_iter().unzip();
JobInstance {
name: x.2.clone(),
mem_reads: mem_reads.into_iter().flatten().collect(), // TODO: add read values
release: x.0,
response: x.1,
exec_ticks: ticks_per_abb.iter().sum(),
ticks_per_abb: ticks_per_abb,
abbs: abbs,
hash_cache: 0
}
}).collect::<Vec<_>>();
// println!("Instances: {:?}",&job_instances);
self.job_instances = job_instances;
let observer = &self;
let mut worst_case_per_task : HashMap<String, JobInstance> = HashMap::new();
observer.job_instances.iter().for_each(|x| {
if worst_case_per_task.get(&x.name).is_some() {
let old = worst_case_per_task.get_mut(&x.name).unwrap();
if x.exec_ticks > old.exec_ticks {
old.exec_ticks=x.exec_ticks;
}
} else {
worst_case_per_task.insert(x.name.clone(), x.clone());
}
});
self.worst_job_instances = worst_case_per_task;
// copy-paste form clock observer
{
let hist = metadata.get_mut::<IcHist>();
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
match hist {
Option::None => {
metadata.insert(IcHist(vec![(self.last_runtime(), timestamp)],
(self.last_runtime(), timestamp)));
}
Some(v) => {
v.0.push((self.last_runtime(), timestamp));
if v.1.0 < self.last_runtime() {
v.1 = (self.last_runtime(), timestamp);
}
}
}
}
}
}
// let abbs = extract_abbs_from_trace(&self.last_run);
// println!("{:?}",abbs);
// let abbs = trace_to_state_abb(&self.last_run);
// println!("{:?}",abbs);
self.last_input=_input.clone();
Ok(())
}
}
impl<I> Named for QemuSystemStateObserver<I>
{
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl<I> HasLen for QemuSystemStateObserver<I>
{
#[inline]
fn len(&self) -> usize {
self.last_run.len()
}
}
impl<I> QemuSystemStateObserver<I>
where I: Default {
pub fn new(select_task: &Option<String>) -> Self {
Self{last_run: vec![], last_trace: vec![], last_reads: vec![], last_input: I::default(), worst_job_instances: HashMap::new(), do_report: false, select_task: select_task.clone(), name: Cow::from("systemstate".to_string()), last_states: HashMap::new(), success: false, job_instances: vec![]}
}
pub fn last_runtime(&self) -> u64 {
self.select_task.as_ref().map(|x| self.worst_job_instances.get(x).map(|y| y.response-y.release).unwrap_or(0).clone()).unwrap_or(unsafe{libafl_qemu::sys::icount_get_raw()})
}
}
impl<I> Default for QemuSystemStateObserver<I>
where I: Default {
fn default() -> Self {
Self::new(&None)
}
}
//============================= 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
/// returns:
/// - a Vec of ReducedFreeRTOSSystemStates
/// - a Vec of metadata tuples (qemu_tick, capture_event, capture_name, edge, mem_reads)
fn refine_system_states(mut input: Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (u32, u32), Vec<(u32, u8)>)>) {
let mut ret = (Vec::<_>::new(), Vec::<_>::new());
for mut i in input.drain(..) {
let cur = RefinedTCB::from_tcb_owned(i.current_tcb);
// println!("Refine: {} {:?} {:?} {:x}-{:x}", cur.task_name, i.capture_point.0, i.capture_point.1.to_string(), i.edge.0, i.edge.1);
// collect ready list
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);
}
// collect delay list
let mut delay_list : Vec::<RefinedTCB> = tcb_list_to_vec_cached(i.delay_list, &mut i.dumping_ground).iter().map(|x| RefinedTCB::from_tcb(x)).collect();
let mut delay_list_overflow : Vec::<RefinedTCB> = tcb_list_to_vec_cached(i.delay_list_overflow, &mut i.dumping_ground).iter().map(|x| RefinedTCB::from_tcb(x)).collect();
delay_list.append(&mut delay_list_overflow);
delay_list.sort_by(|a,b| a.task_name.cmp(&b.task_name));
ret.0.push(ReducedFreeRTOSSystemState {
current_task: cur,
ready_list_after: collector,
delay_list_after: delay_list,
read_invalid: i.read_invalid,
// input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
});
ret.1.push((i.qemu_tick, i.capture_point.0, i.capture_point.1.to_string(), i.edge, i.mem_reads));
}
return ret;
}
// Find all task release times.
fn get_releases(trace: &Vec<ExecInterval>, states: &HashMap<u64, ReducedFreeRTOSSystemState>) -> Vec<(u64, String)> {
let mut ret = Vec::new();
let mut initial_released = false;
for (_n, i) in trace.iter().enumerate() {
// The first release starts from xPortPendSVHandler
if !initial_released && i.start_capture.0 == CaptureEvent::ISREnd && i.start_capture.1 == "xPortPendSVHandler" {
let start_state = states.get(&i.start_state).expect("State not found");
initial_released = true;
start_state.ready_list_after.iter().for_each(|x| {
ret.push((i.start_tick, x.task_name.clone()));
});
continue;
}
// A timed release is SysTickHandler isr block that moves a task from the delay list to the ready list.
if i.start_capture.0 == CaptureEvent::ISRStart && ( i.start_capture.1 == "xPortSysTickHandler" || USR_ISR_SYMBOLS.contains(&i.start_capture.1.as_str()) ) {
// detect race-conditions, get start and end state from the nearest valid intervals
if states.get(&i.start_state).map(|x| x.read_invalid).unwrap_or(true) {
let mut start_index=None;
for n in 1.._n {
if let Some(interval_start) = trace.get(_n-n) {
let start_state = states.get(&interval_start.start_state).unwrap();
if !start_state.read_invalid {
start_index = Some(_n-n);
break;
}
} else {break;}
};
let mut end_index=None;
for n in (_n+1)..trace.len() {
if let Some(interval_end) = trace.get(n) {
let end_state = states.get(&interval_end.end_state).unwrap();
if !end_state.read_invalid {
end_index = Some(n);
break;
}
} else {break;}
};
if let Some(Some(start_state)) = start_index.map(|x| states.get(&trace[x].start_state)) {
if let Some(Some(end_state)) = end_index.map(|x| states.get(&trace[x].end_state)) {
end_state.ready_list_after.iter().for_each(|x| {
if x.task_name != end_state.current_task.task_name && x.task_name != start_state.current_task.task_name && !start_state.ready_list_after.iter().any(|y| x.task_name == y.task_name) {
ret.push((i.end_tick, x.task_name.clone()));
}
});
}
}
} else
// canonical case, userspace -> isr -> userspace
if i.end_capture.0 == CaptureEvent::ISREnd {
let start_state = states.get(&i.start_state).expect("State not found");
let end_state = states.get(&i.end_state).expect("State not found");
end_state.ready_list_after.iter().for_each(|x| {
if x.task_name != end_state.current_task.task_name && x.task_name != start_state.current_task.task_name && !start_state.ready_list_after.iter().any(|y| x.task_name == y.task_name) {
ret.push((i.end_tick, x.task_name.clone()));
}
});
// start_state.delay_list_after.iter().for_each(|x| {
// if !end_state.delay_list_after.iter().any(|y| x.task_name == y.task_name) {
// ret.push((i.end_tick, x.task_name.clone()));
// }
// });
} else if i.end_capture.0 == CaptureEvent::ISRStart {
// Nested interrupts. Fast-forward to the end of the original interrupt, or the first valid state thereafter
// TODO: this may cause the same release to be registered multiple times
let mut isr_has_ended = false;
let start_state = states.get(&i.start_state).expect("State not found");
for n in (_n+1)..trace.len() {
if let Some(interval_end) = trace.get(n) {
if interval_end.end_capture.1 == i.start_capture.1 || isr_has_ended {
let end_state = states.get(&interval_end.end_state).unwrap();
isr_has_ended = true;
if !end_state.read_invalid {
end_state.ready_list_after.iter().for_each(|x| {
if x.task_name != end_state.current_task.task_name && x.task_name != start_state.current_task.task_name && !start_state.ready_list_after.iter().any(|y| x.task_name == y.task_name) {
ret.push((i.end_tick, x.task_name.clone()));
}
});
break;
}
}
} else {break;}
};
// if let Some(interval_end) = trace.get(_n+2) {
// if interval_end.start_capture.0 == CaptureEvent::ISREnd && interval_end.end_capture.0 == CaptureEvent::ISREnd && interval_end.end_capture.1 == i.start_capture.1 {
// let start_state = states.get(&i.start_state).expect("State not found");
// let end_state = states.get(&interval_end.end_state).expect("State not found");
// end_state.ready_list_after.iter().for_each(|x| {
// if x.task_name != end_state.current_task.task_name && x.task_name != start_state.current_task.task_name && !start_state.ready_list_after.iter().any(|y| x.task_name == y.task_name) {
// ret.push((i.end_tick, x.task_name.clone()));
// }
// });
// }
// }
}
}
// Release driven by an API call. This produces a lot of false positives, as a job may block multiple times per instance. Despite this, aperiodic jobs not be modeled otherwise. If we assume the first release is the real one, we can filter out the rest.
if i.start_capture.0 == CaptureEvent::APIStart {
let api_start_state = states.get(&i.start_state).expect("State not found");
let api_end_state = {
let mut end_index = _n;
for n in (_n)..trace.len() {
if trace[n].end_capture.0 == CaptureEvent::APIEnd || trace[n].end_capture.0 == CaptureEvent::End {
end_index = n;
break;
} else if n > _n && trace[n].level == 0 { // API Start -> ISR Start+End -> APP Continue
end_index = n-1; // any return to a regular app block is a fair point of comparison for the ready list, because scheduling has been performed
break;
}
};
states.get(&trace[end_index].end_state).expect("State not found")
};
api_end_state.ready_list_after.iter().for_each(|x| {
if x.task_name != api_start_state.current_task.task_name && !api_start_state.ready_list_after.iter().any(|y| x.task_name == y.task_name) {
ret.push((i.end_tick, x.task_name.clone()));
// eprintln!("Task {} released by API call at {:.1}ms", x.task_name, crate::time::clock::tick_to_time(i.end_tick).as_micros() as f32/1000.0);
}
});
}
}
ret
}
fn get_release_response_pairs(rel: &Vec<(u64, String)>, resp: &Vec<(u64, String)>) -> (Vec<(u64, u64, String)>, bool) {
let mut maybe_error = false;
let mut ret = Vec::new();
let mut ready : HashMap<&String, u64> = HashMap::new();
let mut last_response : HashMap<&String, u64> = HashMap::new();
let mut r = rel.iter().peekable();
let mut d = resp.iter().peekable();
loop {
while let Some(peek_rel) = r.peek() {
// Fill releases as soon as possible
if !ready.contains_key(&peek_rel.1) {
ready.insert(&peek_rel.1, peek_rel.0);
r.next();
} else {
if let Some(peek_resp) = d.peek() {
if peek_resp.0 > peek_rel.0 { // multiple releases before response
// It is unclear which release is real
// maybe_error = true;
// eprintln!("Task {} released multiple times before response ({:.1}ms and {:.1}ms)", peek_rel.1, crate::time::clock::tick_to_time(ready[&peek_rel.1]).as_micros()/1000, crate::time::clock::tick_to_time(peek_rel.0).as_micros()/1000);
// ready.insert(&peek_rel.1, peek_rel.0);
r.next();
} else {
// releases have overtaken responses, wait until the ready list clears up a bit
break;
}
} else {
// no more responses
break;
}
}
}
if let Some(next_resp) = d.next() {
if ready.contains_key(&next_resp.1) {
if ready[&next_resp.1] >= next_resp.0 {
if let Some(lr) = last_response.get(&next_resp.1) {
maybe_error = true;
// eprintln!("Task {} response at {:.1}ms before next release at {:.1}ms. Fallback to last response at {:.1}ms.", next_resp.1, crate::time::clock::tick_to_time(next_resp.0).as_micros() as f32/1000.0, crate::time::clock::tick_to_time(ready[&next_resp.1]).as_micros() as f32/1000.0, crate::time::clock::tick_to_time(*lr).as_micros() as f32/1000.0);
// Sometimes a task is released immediately after a response. This might not be detected.
// Assume that the release occured with the last response
ret.push((*lr, next_resp.0, next_resp.1.clone()));
last_response.insert(&next_resp.1, next_resp.0);
} else {
// eprintln!("Task {} released after response", next_resp.1);
}
} else {
// assert!(peek_resp.0 >= ready[&peek_resp.1]);
last_response.insert(&next_resp.1, next_resp.0);
ret.push((ready[&next_resp.1], next_resp.0, next_resp.1.clone()));
ready.remove(&next_resp.1);
}
} else {
maybe_error = true;
if let Some(lr) = last_response.get(&next_resp.1) {
// eprintln!("Task {} response at {:.1}ms not found in ready list. Fallback to last release at {:.1}ms.", next_resp.1, crate::time::clock::tick_to_time(next_resp.0).as_micros() as f32/1000.0, crate::time::clock::tick_to_time(*lr).as_micros() as f32/1000.0);
// Sometimes a task is released immediately after a response. This might not be detected.
// Assume that the release occured with the last response
ret.push((*lr, next_resp.0, next_resp.1.clone()));
last_response.insert(&next_resp.1, next_resp.0);
} else {
eprintln!("Task {} response at {:.1}ms not found in ready list", next_resp.1, crate::time::clock::tick_to_time(next_resp.0).as_micros() as f32/1000.0);
}
}
} else {
// TODO: should remaining released tasks be counted as finished?
return (ret,maybe_error);
}
}
}
/// Transform the states and metadata into a list of ExecIntervals, along with a HashMap of states, a list of HashSets marking memory reads and a bool indicating success
/// returns:
/// - a Vec of ExecIntervals
/// - a Vec of HashSets marking memory reads during these intervals
/// - a HashMap of ReducedFreeRTOSSystemStates by hash
/// - a bool indicating success
fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, CaptureEvent, String, (u32, u32), Vec<(u32, u8)>)>) -> (Vec<ExecInterval>, Vec<Vec<(u32, u8)>>, HashMap<u64, ReducedFreeRTOSSystemState>, bool) {
if trace.len() == 0 {return (Vec::new(), Vec::new(), HashMap::new(), true);}
let mut isr_stack : VecDeque<u8> = VecDeque::from([]); // 2+ = ISR, 1 = systemcall, 0 = APP. Trace starts with an ISREnd and executes the app
let mut level_of_task : HashMap<&str, u8> = HashMap::new();
let mut ret: Vec<ExecInterval> = vec![];
let mut reads: Vec<Vec<(u32, u8)>> = vec![];
let mut edges: Vec<(u32, u32)> = vec![];
let mut last_hash : u64 = trace[0].get_hash();
let mut table : HashMap<u64, ReducedFreeRTOSSystemState> = HashMap::new();
table.insert(last_hash, trace[0].clone());
for i in 0..trace.len()-1 {
let curr_name = trace[i].current_task.task_name.as_str();
// let mut interval_name = curr_name; // Name of the interval, either the task name or the isr/api funtion name
let level = match meta[i].1 {
CaptureEvent::APIEnd => { // API end always exits towards the app
if !level_of_task.contains_key(curr_name) {
level_of_task.insert(curr_name, 0);
}
*level_of_task.get_mut(curr_name).unwrap()=0;
0
},
CaptureEvent::APIStart => { // API start can only be called in the app
if !level_of_task.contains_key(curr_name) { // Should not happen, apps start from an ISR End. Some input exibited this behavior for unknown reasons
level_of_task.insert(curr_name, 0);
}
*level_of_task.get_mut(curr_name).unwrap()=1;
// interval_name = &meta[i].2;
1
},
CaptureEvent::ISREnd => {
// special case where the next block is an app start
if !level_of_task.contains_key(curr_name) {
level_of_task.insert(curr_name, 0);
}
// nested isr, TODO: Test level > 2
if isr_stack.len() > 1 {
// interval_name = ""; // We can't know which isr is running
isr_stack.pop_back().unwrap();
*isr_stack.back().unwrap()
} else {
isr_stack.pop_back();
// possibly go back to an api call that is still running for this task
if level_of_task.get(curr_name).unwrap() == &1 {
// interval_name = ""; // We can't know which api is running
}
*level_of_task.get(curr_name).unwrap()
}
},
CaptureEvent::ISRStart => {
// special case for isrs which do not capture their end
// if meta[i].2 == "ISR_0_Handler" {
// &2
// } else {
// regular case
// interval_name = &meta[i].2;
if isr_stack.len() > 0 {
let l = *isr_stack.back().unwrap();
isr_stack.push_back(l+1);
l+1
} else {
isr_stack.push_back(2);
2
}
// }
}
_ => 100
};
// if trace[i].2 == CaptureEvent::End {break;}
let next_hash=trace[i+1].get_hash();
if !table.contains_key(&next_hash) {
table.insert(next_hash, trace[i+1].clone());
}
ret.push(ExecInterval{
start_tick: meta[i].0,
end_tick: meta[i+1].0,
start_state: last_hash,
end_state: next_hash,
start_capture: (meta[i].1, meta[i].2.clone()),
end_capture: (meta[i+1].1, meta[i+1].2.clone()),
level: level,
tick_spend_preempted: 0,
abb: None
});
reads.push(meta[i+1].4.clone());
last_hash = next_hash;
edges.push((meta[i].3.1, meta[i+1].3.0));
}
let t = add_abb_info(&mut ret, &table, &edges);
(ret, reads, table, t)
}
/// Marks which abbs were executed at each interval
fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, edges: &Vec<(u32, u32)>) -> bool {
let mut id_count = 0;
let mut ret = true;
let mut task_has_started : HashSet<String> = HashSet::new();
let mut wip_abb_trace : Vec<Rc<RefCell<AtomicBasicBlock>>> = vec![];
// let mut open_abb_at_this_task_or_level : HashMap<(u8,&str),usize> = HashMap::new();
let mut open_abb_at_this_ret_addr_and_task : HashMap<(u32,&str),usize> = HashMap::new();
for i in 0..trace.len() {
let curr_name = &table[&trace[i].start_state].current_task.task_name;
// let last : Option<&usize> = last_abb_start_of_task.get(&curr_name);
// let open_abb = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""})).to_owned(); // apps/apis are differentiated by task name, isrs by nested level
let open_abb = open_abb_at_this_ret_addr_and_task.get(&(edges[i].0, if trace[i].level<2 {&curr_name} else {""})).to_owned(); // apps/apis are differentiated by task name, isrs by nested level
// println!("Edge {:x}-{:x}", edges[i].0.unwrap_or(0xffff), edges[i].1.unwrap_or(0xffff));
match trace[i].start_capture.0 {
// generic api abb start
CaptureEvent::APIStart => {
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: Some(trace[i].start_capture.1.clone())})));
id_count+=1;
},
// generic isr abb start
CaptureEvent::ISRStart => {
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: Some(trace[i].start_capture.1.clone())})));
id_count+=1;
},
// generic app abb start
CaptureEvent::APIEnd => {
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: if trace[i].level<2 {Some(curr_name.clone())} else {None}})));
id_count+=1;
},
// generic continued blocks
CaptureEvent::ISREnd => {
// special case app abb start
if trace[i].start_capture.1=="xPortPendSVHandler" && !task_has_started.contains(curr_name) {
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: 0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: Some(curr_name.clone())})));
id_count+=1;
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
task_has_started.insert(curr_name.clone());
} else {
if let Some(last) = open_abb_at_this_ret_addr_and_task.get(&(edges[i].0, if trace[i].level<2 {&curr_name} else {""})) {
let last = last.clone(); // required to drop immutable reference
wip_abb_trace.push(wip_abb_trace[last].clone());
// if the abb is interrupted again, it will need to continue at edge[i].1
open_abb_at_this_ret_addr_and_task.remove(&(edges[i].0, if trace[i].level<2 {&curr_name} else {""}));
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), last); // order matters!
} else {
// panic!();
// println!("Continued block with no start {} {} {:?} {:?} {:x}-{:x} {} {}", curr_name, trace[i].start_tick, trace[i].start_capture, trace[i].end_capture, edges[i].0, edges[i].1, task_has_started.contains(curr_name),trace[i].level);
// println!("{:x?}", open_abb_at_this_ret_addr_and_task);
ret = false;
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].1, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: if trace[i].level<1 {Some(curr_name.clone())} else {None}})));
id_count+=1;
}
}
},
_ => panic!("Undefined block start")
}
match trace[i].end_capture.0 {
// generic app abb end
CaptureEvent::APIStart => {
let _t = &wip_abb_trace[i];
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1);
open_abb_at_this_ret_addr_and_task.remove(&(edges[i].1, if trace[i].level<2 {&curr_name} else {""}));
},
// generic api abb end
CaptureEvent::APIEnd => {
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1);
open_abb_at_this_ret_addr_and_task.remove(&(edges[i].1, if trace[i].level<2 {&curr_name} else {""}));
},
// generic isr abb end
CaptureEvent::ISREnd => {
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1);
open_abb_at_this_ret_addr_and_task.remove(&(edges[i].1, if trace[i].level<2 {&curr_name} else {""}));
},
// end anything
CaptureEvent::End => {
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1);
open_abb_at_this_ret_addr_and_task.remove(&(edges[i].1, if trace[i].level<2 {&curr_name} else {""}));
},
CaptureEvent::ISRStart => (),
_ => panic!("Undefined block end")
}
// println!("{} {} {:x}-{:x} {:x}-{:x} {:?} {:?} {}",curr_name, trace[i].level, edges[i].0, edges[i].1, ((*wip_abb_trace[i])).borrow().start, ((*wip_abb_trace[i])).borrow().ends.iter().next().unwrap_or(&0xffff), trace[i].start_capture, trace[i].end_capture, trace[i].start_tick);
// println!("{:x?}", open_abb_at_this_ret_addr_and_task);
}
// drop(open_abb_at_this_task_or_level);
for i in 0..trace.len() {
trace[i].abb = Some((*wip_abb_trace[i]).borrow().clone());
}
return ret;
}
// /// restore the isr/api begin/end invariant
// fn fix_broken_trace(meta: &mut Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
// for i in meta.iter_mut() {
// if i.1 == CaptureEvent::APIStart && i.2.ends_with("FromISR") {
// i.1 = CaptureEvent::ISREnd;
// i.2 = "ISR_0_Handler".to_string();
// }
// }
// }
// /// invalidate subsequent intervals of equal states where an ISREnd follows an ISRStart. If the interrupt had no effect on the system we, are not interested.
// fn invalidate_ineffective_isr(trace: &mut Vec<ExecInterval>) {
// let mut i = 0;
// while i < trace.len() - 1 {
// if trace[i].is_valid() &&
// matches!(trace[i].start_capture.0, CaptureEvent::ISRStart) && matches!(trace[i].end_capture.0, CaptureEvent::ISREnd) &&
// trace[i].start_capture.1 == trace[i].end_capture.1 && trace[i].start_state == trace[i].end_state
// {
// trace[i].invaildate();
// }
// }
// }
// /// merge a sequence of intervals of the same state+abb. jump over all invalid blocks.
// fn merge_subsequent_abbs(trace: &mut Vec<ExecInterval>) {
// let mut i = 1;
// let mut lst_valid=0;
// while i < trace.len() - 1 {
// if trace[i].is_valid() {
// let mut temp = trace[i].clone();
// trace[lst_valid].try_unite_with_later_interval(&mut temp);
// trace[i] = temp;
// lst_valid = i;
// }
// }
// }

View File

@ -0,0 +1,161 @@
//! Stage to compute/report AFL stats
use core::{marker::PhantomData, time::Duration};
use libafl_bolts::current_time;
use itertools::Itertools;
use libafl::{
corpus::{Corpus, HasCurrentCorpusId}, events::EventFirer, prelude::{minimizer::TopRatedsMetadata, RemovableScheduler}, schedulers::minimizer::IsFavoredMetadata, stages::Stage, state::{HasCorpus, HasImported, UsesState}, Error, HasMetadata, HasScheduler
};
use libafl::{
events::Event,
monitors::{AggregatorOps, UserStats, UserStatsValue},
};
use std::borrow::Cow;
use serde_json::json;
/// The [`AflStatsStage`] is a simple stage that computes and reports some stats.
#[derive(Debug, Clone)]
pub struct SchedulerStatsStage<E, EM, Z> {
last_report_time: Duration,
// the interval that we report all stats
stats_report_interval: Duration,
phantom: PhantomData<(E, EM, Z)>,
}
impl<E, EM, Z> UsesState for SchedulerStatsStage<E, EM, Z>
where
E: UsesState,
{
type State = E::State;
}
impl<E, EM, Z> Stage<E, EM, Z> for SchedulerStatsStage<E, EM, Z>
where
E: UsesState,
EM: EventFirer<State = Self::State>,
Z: UsesState<State = Self::State> + HasScheduler,
<Z as HasScheduler>::Scheduler: RemovableScheduler,
Self::State: HasImported + HasCorpus + HasMetadata,
{
fn perform(
&mut self,
fuzzer: &mut Z,
_executor: &mut E,
state: &mut <Self as UsesState>::State,
_manager: &mut EM,
) -> Result<(), Error> {
// let Some(corpus_idx) = state.current_corpus_id()? else {
// return Err(Error::illegal_state(
// "state is not currently processing a corpus index",
// ));
// };
// let corpus_size = state.corpus().count();
let cur = current_time();
if cur.checked_sub(self.last_report_time).unwrap_or_default() > self.stats_report_interval {
if let Some(meta) = state.metadata_map().get::<TopRatedsMetadata>() {
let kc = meta.map.keys().count();
let mut v : Vec<_> = meta.map.values().cloned().collect();
v.sort_unstable();
v.dedup();
let vc = v.len();
#[cfg(feature = "std")]
{
let json = json!({
"relevant":vc,
"objects":kc,
});
_manager.fire(
state,
Event::UpdateUserStats {
name: Cow::from("Minimizer"),
value: UserStats::new(
UserStatsValue::String(Cow::from(json.to_string())),
AggregatorOps::None,
),
phantom: PhantomData,
},
)?;
}
#[cfg(not(feature = "std"))]
log::info!(
"pending: {}, pend_favored: {}, own_finds: {}, imported: {}",
pending_size,
pend_favored_size,
self.own_finds_size,
self.imported_size
);
self.last_report_time = cur;
// Experimental pruning
#[cfg(any(feature = "sched_stg",feature = "sched_afl"))]
{
const PRUNE_THRESHOLD: usize = 200;
if state.corpus().count() > PRUNE_THRESHOLD*vc {
println!("Pruning corpus, keeping {} / {}", PRUNE_THRESHOLD*vc, state.corpus().count());
let corpus = state.corpus_mut();
let currid = corpus.current();
let ids : Vec<_> = corpus.ids().filter_map(|x| {
let tc = corpus.get(x).unwrap().borrow();
let md = tc.metadata_map();
if md.get::<IsFavoredMetadata>().is_some() || &Some(x) == currid || v.contains(&&x) {
None
} else {
Some((x, tc.exec_time().clone()))
}
}).sorted_by_key(|x| x.1).take(usize::saturating_sub(corpus.count(),(PRUNE_THRESHOLD/2)*vc)).sorted_by_key(|x| x.0).unique().rev().collect();
for (cid, _) in ids {
let c = state.corpus_mut().remove(cid).unwrap();
fuzzer
.scheduler_mut()
.on_remove(state, cid, &Some(c))?;
}
}
}
}
}
Ok(())
}
#[inline]
fn restart_progress_should_run(&mut self, _state: &mut <Self as UsesState>::State) -> Result<bool, Error> {
// Not running the target so we wont't crash/timeout and, hence, don't need to restore anything
Ok(true)
}
#[inline]
fn clear_restart_progress(&mut self, _state: &mut <Self as UsesState>::State) -> Result<(), Error> {
// Not running the target so we wont't crash/timeout and, hence, don't need to restore anything
Ok(())
}
}
impl<E, EM, Z> SchedulerStatsStage<E, EM, Z> {
/// create a new instance of the [`AflStatsStage`]
#[must_use]
pub fn new(interval: Duration) -> Self {
Self {
stats_report_interval: interval,
..Default::default()
}
}
}
impl<E, EM, Z> Default for SchedulerStatsStage<E, EM, Z> {
/// the default instance of the [`AflStatsStage`]
#[must_use]
fn default() -> Self {
Self {
last_report_time: current_time(),
stats_report_interval: Duration::from_secs(3),
phantom: PhantomData,
}
}
}

View File

@ -0,0 +1,306 @@
//! 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};
use serde::{Deserialize, Serialize};
use libafl_bolts::{rands::Rand, AsIter, HasLen};
use libafl::{
common::HasMetadata, corpus::{Corpus, Testcase}, inputs::UsesInput, prelude::{CanTrack, CorpusId, RemovableScheduler}, schedulers::{minimizer::DEFAULT_SKIP_NON_FAVORED_PROB, Scheduler, TestcaseScore }, state::{HasCorpus, HasRand, State, UsesState}, Error, SerdeAny
};
use crate::time::worst::MaxTimeFavFactor;
use super::{stg::STGNodeMetadata, 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: f64,
}
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(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
let l = state.corpus()
.get(idx)?
.borrow()
.metadata_map()
.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(
// &mut self,
// state: &mut CS::State,
// idx: CorpusId,
// 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(&mut self, state: &mut CS::State) -> Result<CorpusId, Error> {
let mut idx = self.base.next(state)?;
while {
let l = state.corpus()
.get(idx)?
.borrow()
.metadata_map()
.get::<STGNodeMetadata>().map_or(0, |x| x.nodes().len());
let m = self.get_update_trace_length(state,l);
state.rand_mut().below(m as usize) > l
} && state.rand_mut().coinflip(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_map_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
}
}
#[allow(unused)]
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: State + UsesInput,
{
type State = S;
}
impl<S> Scheduler for GenerationScheduler<S>
where
S: State + HasCorpus + HasMetadata,
{
/// get first element in current gen,
/// if current_gen is empty, swap lists, sort by FavFactor, take top k and return first
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
let mut to_remove : Vec<(usize, f64)> = vec![];
let mut _to_return : usize = 0;
let corpus_len = state.corpus().count();
let mut _current_len = 0;
let gm = state.metadata_map_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) => {
_current_len = gm.current_gen.len();
gm.current_cursor+=1;
// println!("normal next: {}", (*c).0);
return Ok((*c).0.into())
},
Option::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;
// assert_eq!(to_return, 0);
gm.current_cursor=1;
gm.gen+=1;
_current_len = gm.current_gen.len();
}
};
// 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();
let cm = state.corpus_mut();
assert_eq!(corpus_len-to_remove.len(), _current_len);
assert_ne!(_current_len,0);
for i in to_remove {
cm.remove(i.0.into()).unwrap();
}
assert_eq!(cm.get(_to_return.into()).is_ok(),true);
// println!("switch next: {to_return}");
return Ok(_to_return.into());
}
/// Add the new input to the next generation
fn on_add(
&mut self,
state: &mut Self::State,
idx: CorpusId
) -> Result<(), Error> {
// println!("On Add {idx}");
let mut tc = state.corpus_mut().get(idx).expect("Newly added testcase not found by index").borrow_mut().clone();
let ff = MaxTimeFavFactor::compute(state, &mut tc).unwrap();
if let Some(gm) = state.metadata_map_mut().get_mut::<GeneticMetadata>() {
gm.next_gen.push((idx.into(),ff));
} else {
state.add_metadata(GeneticMetadata::new(vec![], vec![(idx.into(),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> RemovableScheduler for GenerationScheduler<S>
where
S: State + HasCorpus + HasMetadata,
{
/// Replaces the testcase at the given idx
fn on_replace(
&mut self,
state: &mut <Self as UsesState>::State,
idx: CorpusId,
testcase: &Testcase<<<Self as UsesState>::State as UsesInput>::Input>,
) -> Result<(), Error> {
Ok(())
}
/// Removes an entry from the corpus
fn on_remove(
&mut self,
state: &mut <Self as UsesState>::State,
idx: CorpusId,
testcase: &Option<Testcase<<<Self as UsesState>::State as UsesInput>::Input>>,
) -> Result<(), Error> {
Ok(())
}
}
impl<S> GenerationScheduler<S>
{
#[allow(unused)]
pub fn new() -> Self {
let gen_size = 100;
#[cfg(feature = "gensize_1")]
let gen_size= 1;
#[cfg(feature = "gensize_10")]
let gen_size= 10;
#[cfg(feature = "gensize_100")]
let gen_size= 100;
#[cfg(feature = "gensize_1000")]
let gen_size= 1000;
Self {
phantom: PhantomData,
gen_size
}
}
}

View File

@ -0,0 +1,709 @@
use hashbrown::HashSet;
use libafl::inputs::Input;
/// Feedbacks organizing SystemStates as a graph
use libafl::SerdeAny;
use libafl_bolts::ownedref::OwnedMutSlice;
use petgraph::graph::EdgeIndex;
use libafl::prelude::UsesInput;
use libafl::common::HasNamedMetadata;
use libafl::state::UsesState;
use libafl::prelude::State;
use libafl::schedulers::MinimizerScheduler;
use libafl_bolts::HasRefCnt;
use std::path::PathBuf;
use libafl::corpus::Testcase;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::hash::Hash;
use libafl::events::EventFirer;
use libafl::state::MaybeHasClientPerfMonitor;
use libafl::feedbacks::Feedback;
use libafl_bolts::Named;
use libafl::Error;
use libafl_qemu::edges::EDGES_MAP_SIZE_IN_USE;
use hashbrown::HashMap;
use libafl::{executors::ExitKind, observers::ObserversTuple, common::HasMetadata};
use serde::{Deserialize, Serialize};
use super::AtomicBasicBlock;
use super::CaptureEvent;
use super::ExecInterval;
use super::JobInstance;
use super::ReducedFreeRTOSSystemState;
use super::observers::QemuSystemStateObserver;
use super::TaskJob;
use petgraph::prelude::DiGraph;
use petgraph::graph::NodeIndex;
use petgraph::Direction;
use crate::time::clock::QemuClockObserver;
use crate::time::clock::FUZZ_START_TIMESTAMP;
use crate::time::worst::MaxTimeFavFactor;
use std::time::SystemTime;
use std::{fs::OpenOptions, io::Write};
use std::borrow::Cow;
use std::ops::Deref;
use std::ops::DerefMut;
use std::rc::Rc;
use petgraph::visit::EdgeRef;
//============================= Data Structures
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash)]
pub struct STGNode
{
base: ReducedFreeRTOSSystemState,
abb: AtomicBasicBlock,
}
impl STGNode {
pub fn _pretty_print(&self) -> String {
format!("{}\nl{} {:x}-{:x}\n{}", self.base.current_task.task_name, self.abb.level, self.abb.start, self.abb.ends.iter().next().unwrap_or_else(||&0xFFFF), self.base.print_lists())
}
pub fn color_print(&self) -> String {
let color = match self.abb.level {
1 => "\", shape=box, style=filled, fillcolor=\"lightblue",
2 => "\", shape=box, style=filled, fillcolor=\"yellow",
0 => "\", shape=box, style=filled, fillcolor=\"white",
_ => "\", style=filled, fillcolor=\"lightgray",
};
let message = match self.abb.level {
1 => format!("API Call"),
2 => format!("ISR"),
0 => format!("Task: {}",self.base.current_task.task_name),
_ => format!(""),
};
let mut label = format!("{}\nABB: {:x}-{:x}\nHash:{:X}\n{}", message, self.abb.start, self.abb.ends.iter().next().unwrap_or_else(||&0xFFFF), self.base.get_hash()>>48, self.base.print_lists());
label.push_str(color);
label
}
fn get_hash(&self) -> u64 {
let mut s = DefaultHasher::new();
self.base.hash(&mut s);
self.abb.hash(&mut s);
s.finish()
}
}
impl PartialEq for STGNode {
fn eq(&self, other: &STGNode) -> bool {
self.base==other.base
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
pub struct STGEdge
{
pub event: CaptureEvent,
pub name: String,
pub worst: Option<(u64, Vec<(u32, u8)>)>,
}
impl STGEdge {
pub fn _pretty_print(&self) -> String {
let mut short = match self.event {
CaptureEvent::APIStart => "Call: ",
CaptureEvent::APIEnd => "Ret: ",
CaptureEvent::ISRStart => "Int: ",
CaptureEvent::ISREnd => "IRet: ",
CaptureEvent::End => "End: ",
CaptureEvent::Undefined => "",
}.to_string();
short.push_str(&self.name);
short
}
pub fn color_print(&self) -> String {
let mut short = self.name.clone();
short.push_str(match self.event {
CaptureEvent::APIStart => "\", color=\"blue",
CaptureEvent::APIEnd => "\", color=\"black",
CaptureEvent::ISRStart => "\", color=red, style=\"dashed",
CaptureEvent::ISREnd => "\", color=red, style=\"solid",
CaptureEvent::End => "",
CaptureEvent::Undefined => "",
});
short
}
pub fn is_abb_end(&self) -> bool {
match self.event {
CaptureEvent::APIStart | CaptureEvent::APIEnd | CaptureEvent::ISREnd | CaptureEvent::End => true,
_ => false
}
}
}
impl Hash for STGEdge {
fn hash<H: Hasher>(&self, state: &mut H) {
self.event.hash(state);
self.name.hash(state);
}
}
/// Shared Metadata for a systemstateFeedback
#[derive(Debug, Serialize, Deserialize, SerdeAny, Clone)]
pub struct STGFeedbackState
{
name: Cow<'static, str>,
// aggregated traces as a graph
pub graph: DiGraph<STGNode, STGEdge>,
systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>,
pub state_abb_hash_index: HashMap<(u64, u64), NodeIndex>,
stgnode_index: HashMap<u64, NodeIndex>,
entrypoint: NodeIndex,
exitpoint: NodeIndex,
// Metadata about aggregated traces. aggegated meaning, order has been removed
worst_observed_per_aggegated_path: HashMap<Vec<AtomicBasicBlock>,u64>,
worst_observed_per_abb_path: HashMap<u64,u64>,
worst_observed_per_stg_path: HashMap<u64,u64>,
worst_abb_exec_count: HashMap<AtomicBasicBlock, usize>,
// Metadata about job instances
pub worst_task_jobs: HashMap<u64, TaskJob>,
}
impl Default for STGFeedbackState {
fn default() -> STGFeedbackState {
let mut graph = DiGraph::new();
let mut entry = STGNode::default();
entry.base.current_task.task_name="Start".to_string();
let mut exit = STGNode::default();
exit.base.current_task.task_name="End".to_string();
let systemstate_index = HashMap::from([(entry.base.get_hash(), entry.base.clone()), (exit.base.get_hash(), exit.base.clone())]);
let h_entry = entry.get_hash();
let h_exit = exit.get_hash();
let entrypoint = graph.add_node(entry.clone());
let exitpoint = graph.add_node(exit.clone());
let state_abb_hash_index = HashMap::from([((entry.base.get_hash(), entry.abb.get_hash()), entrypoint), ((exit.base.get_hash(), exit.abb.get_hash()), exitpoint)]);
let index = HashMap::from([(h_entry, entrypoint), (h_exit, exitpoint)]);
STGFeedbackState {
name: Cow::from("stgfeedbackstate".to_string()),
graph,
stgnode_index: index,
entrypoint,
exitpoint,
worst_observed_per_aggegated_path: HashMap::new(),
worst_observed_per_abb_path: HashMap::new(),
worst_observed_per_stg_path: HashMap::new(),
worst_abb_exec_count: HashMap::new(),
systemstate_index,
state_abb_hash_index,
worst_task_jobs: HashMap::new(),
}
}
}
impl Named for STGFeedbackState
{
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct STGNodeMetadata {
nodes: Vec<NodeIndex>,
edges: Vec<EdgeIndex>,
abbs: u64,
aggregate: u64,
top_abb_counts: Vec<u64>,
intervals: Vec<ExecInterval>,
jobs: Vec<JobInstance>,
indices: Vec<usize>,
tcref: isize,
}
impl STGNodeMetadata {
pub fn new(nodes: Vec<NodeIndex>, edges: Vec<EdgeIndex>, abbs: u64, aggregate: u64, top_abb_counts: Vec<u64>, intervals: Vec<ExecInterval>, jobs: Vec<JobInstance>) -> Self {
#[allow(unused)]
let mut indices : Vec<_> = vec![];
#[cfg(all(feature = "sched_stg",not(any(feature = "sched_stg_pathhash",feature = "sched_stg_abbhash",feature = "sched_stg_aggregatehash"))))]
{
indices = edges.iter().map(|x| x.index()).collect();
indices.sort_unstable();
indices.dedup();
}
#[cfg(feature = "sched_stg_pathhash")]
{
indices.push(get_generic_hash(&edges) as usize);
}
#[cfg(feature = "sched_stg_abbhash")]
{
indices.push(abbs as usize);
}
#[cfg(feature = "sched_stg_aggregatehash")]
{
// indices.push(aggregate as usize);
indices = top_abb_counts.iter().map(|x| (*x) as usize).collect();
}
Self {indices, intervals, jobs, nodes, abbs, aggregate, top_abb_counts, edges, tcref: 0}
}
pub fn nodes(&self) -> &Vec<NodeIndex> {
&self.nodes
}
pub fn edges(&self) -> &Vec<EdgeIndex> {
&self.edges
}
pub fn abbs(&self) -> u64 {
self.abbs
}
pub fn aggregate(&self) -> u64 {
self.aggregate
}
pub fn top_abb_counts(&self) -> &Vec<u64> {
&self.top_abb_counts
}
pub fn intervals(&self) -> &Vec<ExecInterval> {
&self.intervals
}
pub fn jobs(&self) -> &Vec<JobInstance> {
&self.jobs
}
}
impl Deref for STGNodeMetadata {
type Target = [usize];
/// Convert to a slice
fn deref(&self) -> &[usize] {
&self.indices
}
}
impl DerefMut for STGNodeMetadata {
/// Convert to a slice
fn deref_mut(&mut self) -> &mut [usize] {
&mut self.indices
}
}
impl HasRefCnt for STGNodeMetadata {
fn refcnt(&self) -> isize {
self.tcref
}
fn refcnt_mut(&mut self) -> &mut isize {
&mut self.tcref
}
}
libafl_bolts::impl_serdeany!(STGNodeMetadata);
pub type GraphMaximizerCorpusScheduler<CS, O> =
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>,STGNodeMetadata,O>;
// AI generated, human verified
/// Count the occurrences of each element in a vector, assumes the vector is sorted
fn count_occurrences_sorted<T>(vec: &Vec<T>) -> HashMap<&T, usize>
where
T: PartialEq + Eq + Hash + Clone,
{
let mut counts = HashMap::new();
if vec.is_empty() {
return counts;
}
let mut current_obj = &vec[0];
let mut current_count = 1;
for obj in vec.iter().skip(1) {
if obj == current_obj {
current_count += 1;
} else {
counts.insert(current_obj, current_count);
current_obj = obj;
current_count = 1;
}
}
// Insert the count of the last object
counts.insert(current_obj, current_count);
counts
}
//============================= Graph Feedback
pub static mut STG_MAP: [u16; EDGES_MAP_SIZE_IN_USE] = [0; EDGES_MAP_SIZE_IN_USE];
pub static mut MAX_STG_NUM: usize = 0;
pub unsafe fn stg_map_mut_slice<'a>() -> OwnedMutSlice<'a, u16> {
OwnedMutSlice::from_raw_parts_mut(STG_MAP.as_mut_ptr(), STG_MAP.len())
}
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct StgFeedback
{
name: Cow<'static, str>,
last_node_trace: Option<Vec<NodeIndex>>,
last_edge_trace: Option<Vec<EdgeIndex>>,
last_intervals: Option<Vec<ExecInterval>>,
last_abbs_hash: Option<u64>, // only set, if it was interesting
last_aggregate_hash: Option<u64>, // only set, if it was interesting
last_top_abb_hashes: Option<Vec<u64>>, // only set, if it was interesting
last_job_trace: Option<Vec<JobInstance>>, // only set, if it was interesting
dump_path: Option<PathBuf>
}
#[cfg(feature = "feed_stg")]
const INTEREST_EDGE : bool = true;
#[cfg(feature = "feed_stg")]
const INTEREST_NODE : bool = true;
#[cfg(feature = "feed_stg_pathhash")]
const INTEREST_PATH : bool = true;
#[cfg(feature = "feed_stg_abbhash")]
const INTEREST_ABBPATH : bool = true;
#[cfg(feature = "feed_stg_aggregatehash")]
const INTEREST_AGGREGATE : bool = true;
#[cfg(not(feature = "feed_stg"))]
const INTEREST_EDGE : bool = false;
#[cfg(not(feature = "feed_stg"))]
const INTEREST_NODE : bool = false;
#[cfg(not(feature = "feed_stg_pathhash"))]
const INTEREST_PATH : bool = false;
#[cfg(not(feature = "feed_stg_abbhash"))]
const INTEREST_ABBPATH : bool = false;
#[cfg(not(feature = "feed_stg_aggregatehash"))]
const INTEREST_AGGREGATE : bool = false;
const INTEREST_JOB_INSTANCE : bool = true;
fn set_observer_map(trace : &Vec<EdgeIndex>) {
unsafe {
for i in 0..MAX_STG_NUM {
STG_MAP[i] = 0;
}
for i in trace {
if MAX_STG_NUM < i.index() {
MAX_STG_NUM = i.index();
}
STG_MAP[i.index()]+=1;
}
}
}
fn get_generic_hash<H>(input: &H) -> u64
where
H: Hash,
{
let mut s = DefaultHasher::new();
input.hash(&mut s);
s.finish()
}
fn execinterval_to_abb_instances(trace: &Vec<ExecInterval>, read_trace: &Vec<Vec<(u32, u8)>>) -> HashMap<usize, (u64, Vec<(u32, u8)>)>{
let mut instance_time: HashMap<usize, (u64, Vec<(u32, u8)>)> = HashMap::new();
for (_i,interval) in trace.iter().enumerate() { // Iterate intervals
// sum up execution time and accesses per ABB
let temp = interval.abb.as_ref().map(|abb| abb.instance_id).unwrap_or(usize::MAX);
match instance_time.get_mut(&temp) {
Some(x) => {
x.0 += interval.get_exec_time();
x.1.extend(read_trace[_i].clone());
},
None => {
if temp != usize::MAX {
instance_time.insert(temp, (interval.get_exec_time(), read_trace[_i].clone()));
}
}
};
}
return instance_time;
}
impl StgFeedback {
pub fn new(dump_name: Option<PathBuf>) -> Self {
// Self {name: String::from("STGFeedback"), last_node_trace: None, last_edge_trace: None, last_intervals: None }
let mut s = Self::default();
s.dump_path = dump_name.map(|x| x.with_extension("stgsize"));
s
}
/// params:
/// tarce of intervals
/// hashtable of states
/// feedbackstate
/// produces:
/// tarce of node indexes representing the path trough the graph
/// newly discovered node?
/// side effect:
/// the graph gets new nodes and edge
fn update_stg_interval(trace: &Vec<ExecInterval>, read_trace: &Vec<Vec<(u32, u8)>>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool, bool) {
let mut return_node_trace = vec![fbs.entrypoint];
let mut return_edge_trace = vec![];
let mut interesting = false;
let mut updated = false;
if trace.is_empty() {
return (return_node_trace, return_edge_trace, interesting, updated);
}
let mut instance_time = execinterval_to_abb_instances(trace, read_trace);
// add all missing state+abb combinations to the graph
for (_i,interval) in trace.iter().enumerate() { // Iterate intervals
let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()};
let h_node = node.get_hash();
let next_idx = if let Some(idx) = fbs.stgnode_index.get(&h_node) {
// alredy present
*idx
} else {
// not present
let h = (node.base.get_hash(), node.abb.get_hash());
let idx = fbs.graph.add_node(node);
fbs.stgnode_index.insert(h_node, idx);
fbs.state_abb_hash_index.insert(h, idx);
interesting |= INTEREST_NODE;
updated = true;
idx
};
// connect in graph if edge not present
let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx);
if let Some(e_) = e {
return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_));
if let Some((time,accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) {
let ref_ = &mut fbs.graph.edge_weight_mut(e_.id()).unwrap().worst;
if ref_.is_some() {
let w = ref_.as_mut().unwrap();
if w.0 < *time {*w = (*time, accesses.clone())};
} else {
*ref_ = Some((*time, accesses.clone()));
}
}
} else {
let mut e__ = STGEdge{event: interval.start_capture.0, name: interval.start_capture.1.clone(), worst: None};
if e__.is_abb_end() {
if let Some((time,accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) {
e__.worst = Some((*time, accesses.clone()));
}
}
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, e__);
return_edge_trace.push(e_);
interesting |= INTEREST_EDGE;
updated = true;
}
return_node_trace.push(next_idx);
/*
Ideas:
Mark edges triggered by interrupts
Specify path with edges instead of nodes?
Form a coverage map over edges?
Sum up execution time per ABB
*/
}
// every path terminates at the end
if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exitpoint) {
let mut e__ = STGEdge { event: CaptureEvent::End, name: String::from("End"), worst: None};
if e__.is_abb_end() {
if let Some((time,accesses)) = instance_time.get_mut(&trace[trace.len()-1].abb.as_ref().unwrap().instance_id) {
e__.worst = Some((*time, accesses.clone()));
}
}
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exitpoint, e__);
return_edge_trace.push(e_);
interesting |= INTEREST_EDGE;
updated = true;
}
return_node_trace.push(fbs.exitpoint);
#[cfg(feature = "feed_stg")]
set_observer_map(&return_edge_trace);
(return_node_trace, return_edge_trace, interesting, updated)
}
fn abbs_in_exec_order(trace: &Vec<ExecInterval>) -> Vec<AtomicBasicBlock> {
let mut ret = Vec::new();
for i in 0..trace.len() {
if trace[i].abb != None &&
(trace[i].end_capture.0 == CaptureEvent::APIStart || trace[i].end_capture.0 == CaptureEvent::APIEnd || trace[i].end_capture.0 == CaptureEvent::End || trace[i].end_capture.0 == CaptureEvent::ISREnd) {
ret.push(trace[i].abb.as_ref().unwrap().clone());
}
}
ret
}
}
impl<S> Feedback<S> for StgFeedback
where
S: State + UsesInput + MaybeHasClientPerfMonitor + HasNamedMetadata,
S::Input: Default,
{
#[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>,
S::Input: Default,
{
let observer = observers.match_name::<QemuSystemStateObserver<S::Input>>("systemstate")
.expect("QemuSystemStateObserver not found");
let clock_observer = observers.match_name::<QemuClockObserver>("clocktime")
.expect("QemuClockObserver not found");
#[cfg(feature = "trace_job_response_times")]
let last_runtime = observer.last_runtime();
#[cfg(not(feature = "trace_job_response_times"))]
let last_runtime = clock_observer.last_runtime();
let feedbackstate = match state
.named_metadata_map_mut()
.get_mut::<STGFeedbackState>("stgfeedbackstate") {
Some(s) => s,
Option::None => {
let n=STGFeedbackState::default();
state.named_metadata_map_mut().insert("stgfeedbackstate",n);
state.named_metadata_map_mut().get_mut::<STGFeedbackState>("stgfeedbackstate").unwrap()
}
};
// --------------------------------- Update STG
let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_reads, &observer.last_states, feedbackstate);
// --------------------------------- Update job instances
for i in observer.worst_job_instances.iter() {
interesting |= INTEREST_JOB_INSTANCE && if let Some(x) = feedbackstate.worst_task_jobs.get_mut(&i.1.get_hash_cached()) {
// eprintln!("Job instance already present");
x.try_update(i.1)
} else {
// eprintln!("New Job instance");
feedbackstate.worst_task_jobs.insert(i.1.get_hash_cached(), TaskJob::from_instance(&i.1));
true
}
};
self.last_job_trace = Some(observer.job_instances.clone());
// dbg!(&observer.job_instances);
{
let h = get_generic_hash(&edgetrace);
if let Some(x) = feedbackstate.worst_observed_per_stg_path.get_mut(&h) {
let t = last_runtime;
if t > *x {
*x = t;
interesting |= INTEREST_PATH;
}
} else {
feedbackstate.worst_observed_per_stg_path.insert(h, last_runtime);
updated = true;
interesting |= INTEREST_PATH;
}
}
#[cfg(not(feature = "trace_job_response_times"))]
let tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace);
#[cfg(feature = "trace_job_response_times")]
let tmp = {
if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(x.name.clone()) == observer.select_task).max_by(|a,b| (a.response-a.release).cmp(&(b.response-b.release))) {
let t = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.response && x.end_tick > worst_instance.release ).cloned().collect();
StgFeedback::abbs_in_exec_order(&t)
} else {
if observer.select_task.is_none() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here
StgFeedback::abbs_in_exec_order(&observer.last_trace)
} else {
Vec::new()
}
}
};
if INTEREST_AGGREGATE || INTEREST_ABBPATH {
if INTEREST_ABBPATH {
let h = get_generic_hash(&tmp);
self.last_abbs_hash = Some(h);
// order of execution is relevant
if let Some(x) = feedbackstate.worst_observed_per_abb_path.get_mut(&h) {
let t = last_runtime;
if t > *x {
*x = t;
interesting |= INTEREST_ABBPATH;
}
} else {
feedbackstate.worst_observed_per_abb_path.insert(h, last_runtime);
interesting |= INTEREST_ABBPATH;
}
}
if INTEREST_AGGREGATE {
// aggegation by sorting, order of states is not relevant
let mut _tmp = tmp.clone();
_tmp.sort(); // use sort+count, because we need the sorted trace anyways
let counts = count_occurrences_sorted(&_tmp);
let mut top_indices = Vec::new();
for (k,c) in counts {
if let Some(reference) = feedbackstate.worst_abb_exec_count.get_mut(k) {
if *reference < c {
*reference = c;
top_indices.push(get_generic_hash(k));
}
} else {
top_indices.push(get_generic_hash(k));
feedbackstate.worst_abb_exec_count.insert(k.clone(), c);
}
}
self.last_top_abb_hashes = Some(top_indices);
self.last_aggregate_hash = Some(get_generic_hash(&_tmp));
if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&_tmp) {
let t = last_runtime;
if t > *x {
*x = t;
interesting |= INTEREST_AGGREGATE;
}
} else {
feedbackstate.worst_observed_per_aggegated_path.insert(_tmp, last_runtime);
interesting |= INTEREST_AGGREGATE;
}
}
}
// let out = feedbackstate.graph.map(|i,x| x.pretty_print(), |_,_| "");
// let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string();
// let outs = outs.replace(';',"\\n");
// fs::write("./mystg.dot",outs).expect("Failed to write graph");
self.last_node_trace = Some(nodetrace);
self.last_edge_trace = Some(edgetrace);
self.last_intervals = Some(observer.last_trace.clone());
if let Some(dp) = &self.dump_path {
if updated {
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open(dp).expect("Could not open stgsize");
writeln!(file, "{},{},{},{},{}", feedbackstate.graph.edge_count(), feedbackstate.graph.node_count(), feedbackstate.worst_observed_per_aggegated_path.len(),feedbackstate.worst_observed_per_stg_path.len(), timestamp).expect("Write to dump failed");
}
}
Ok(interesting)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
let meta = STGNodeMetadata::new(self.last_node_trace.take().unwrap_or_default(), self.last_edge_trace.take().unwrap_or_default(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap_or_default(), self.last_job_trace.take().unwrap_or_default());
testcase.metadata_map_mut().insert(meta);
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 StgFeedback
{
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}

View File

@ -0,0 +1,372 @@
use hashbrown::HashMap;
use libafl_bolts::Named;
use libafl::{
executors::ExitKind,
observers::Observer,
Error,
common::HasNamedMetadata,
observers::ObserversTuple, prelude::UsesInput,
};
use serde::{Deserialize, Serialize};
use std::{fs::OpenOptions, io::Write};
use libafl::events::EventFirer;
use libafl::state::MaybeHasClientPerfMonitor;
use libafl::prelude::State;
use libafl::feedbacks::Feedback;
use libafl::SerdeAny;
use libafl::common::HasMetadata;
use libafl::corpus::testcase::Testcase;
use core::{fmt::Debug, time::Duration};
use std::time::{SystemTime, UNIX_EPOCH};
use std::path::PathBuf;
use std::borrow::Cow;
use crate::systemstate::observers::QemuSystemStateObserver;
pub static mut FUZZ_START_TIMESTAMP : SystemTime = UNIX_EPOCH;
pub const QEMU_ICOUNT_SHIFT : u32 = 5;
pub const QEMU_ISNS_PER_SEC : u32 = u32::pow(10, 9) / u32::pow(2, QEMU_ICOUNT_SHIFT);
pub const QEMU_ISNS_PER_USEC : u32 = QEMU_ISNS_PER_SEC / 1000000;
pub const _QEMU_NS_PER_ISN : u32 = 1 << QEMU_ICOUNT_SHIFT;
pub const _TARGET_SYSCLK_FREQ : u32 = 25 * 1000 * 1000;
pub const _TARGET_MHZ_PER_MIPS : f32 = _TARGET_SYSCLK_FREQ as f32 / QEMU_ISNS_PER_SEC as f32;
pub const _TARGET_MIPS_PER_MHZ : f32 = QEMU_ISNS_PER_SEC as f32 / _TARGET_SYSCLK_FREQ as f32;
pub const _TARGET_SYSCLK_PER_QEMU_SEC : u32 = (_TARGET_SYSCLK_FREQ as f32 * _TARGET_MIPS_PER_MHZ) as u32;
pub const _QEMU_SYSCLK_PER_TARGET_SEC : u32 = (_TARGET_SYSCLK_FREQ as f32 * _TARGET_MHZ_PER_MIPS) as u32;
pub fn tick_to_time(ticks: u64) -> Duration {
Duration::from_nanos((ticks << QEMU_ICOUNT_SHIFT) as u64)
}
pub fn tick_to_ms(ticks: u64) -> f32 {
(Duration::from_nanos(ticks << QEMU_ICOUNT_SHIFT).as_micros() as f32/10.0).round()/100.0
}
//========== 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: Cow<'static, str>,
}
// impl FeedbackState for MaxIcountMetadata
// {
// fn reset(&mut self) -> Result<(), Error> {
// self.max_icount_seen = 0;
// Ok(())
// }
// }
impl Named for MaxIcountMetadata
{
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl MaxIcountMetadata
{
/// Create new `MaxIcountMetadata`
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
max_icount_seen: 0,
name: Cow::from(name),
}
}
}
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: Cow<'static, str>,
start_tick: u64,
end_tick: u64,
dump_path: Option<PathBuf>
}
impl QemuClockObserver {
/// Creates a new [`QemuClockObserver`] with the given name.
#[must_use]
pub fn new(name: &'static str, dump_path: Option<PathBuf>) -> Self {
Self {
name: Cow::from(name),
start_tick: 0,
end_tick: 0,
dump_path
}
}
/// 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 = libafl_qemu::sys::icount_get_raw() };
if let Some(td) = &self.dump_path {
// 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_map_mut();
let hist = metadata.get_mut::<IcHist>();
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
match hist {
Option::None => {
#[cfg(not(feature="trace_job_response_times"))]
{
metadata.insert(IcHist(vec![(self.end_tick - self.start_tick, timestamp)],
(self.end_tick - self.start_tick, timestamp)));
}
#[cfg(feature="trace_job_response_times")]
metadata.insert(IcHist(vec![],(0,timestamp)));
}
Some(v) => {
#[cfg(not(feature="trace_job_response_times"))]
{
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 {
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(110);
for i in std::mem::replace(&mut v.0, newv).into_iter() {
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
}
}
}
}
}
Ok(())
}
}
impl Named for QemuClockObserver {
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl Default for QemuClockObserver {
fn default() -> Self {
Self {
name: Cow::from(String::from("clock")),
start_tick: 0,
end_tick: 0,
dump_path: None
}
}
}
//========== 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>,
select_task: Option<String>,
name: Cow<'static, str>,
}
impl<S> Feedback<S> for ClockTimeFeedback
where
S: State + UsesInput + MaybeHasClientPerfMonitor + HasMetadata,
<S as UsesInput>::Input: Default
{
#[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>,
{
#[cfg(feature="trace_job_response_times")]
{
if self.select_task.is_some() {
let observer = observers.match_name::<QemuSystemStateObserver<S::Input>>("systemstate").unwrap();
self.exec_time = Some(Duration::from_nanos(observer.last_runtime()));
return Ok(false)
}
}
// 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()));
Ok(false)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_observers: &OT,
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) -> &Cow<'static, str> {
&self.name
}
}
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, select_task: Option<String>) -> Self {
Self {
exec_time: None,
select_task: select_task,
name: Cow::from(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, select_task: &Option<String>) -> Self {
Self {
exec_time: None,
select_task: select_task.clone(),
name: observer.name().clone(),
}
}
}
/// A [`Feedback`] rewarding increasing the execution cycles on Qemu.
#[derive(Debug)]
pub struct QemuClockIncreaseFeedback {
name: Cow<'static, str>,
}
impl<S> Feedback<S> for QemuClockIncreaseFeedback
where
S: State + UsesInput + HasNamedMetadata + MaybeHasClientPerfMonitor + 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_map_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<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, _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) -> &Cow<'static, str> {
&self.name
}
}
impl QemuClockIncreaseFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {name: Cow::from(String::from(name))}
}
}
impl Default for QemuClockIncreaseFeedback {
fn default() -> Self {
Self::new("MaxClock")
}
}

View File

@ -0,0 +1,3 @@
pub mod clock;
pub mod qemustate;
pub mod worst;

View File

@ -0,0 +1,97 @@
use libafl::prelude::UsesInput;
use libafl_qemu::sys::CPUArchState;
use libafl_qemu::FastSnapshotPtr;
use libafl_qemu::QemuHelper;
use libafl_qemu::QemuHelperTuple;
use libafl::executors::ExitKind;
use libafl_qemu::QemuHooks;
// TODO be thread-safe maybe with https://amanieu.github.io/thread_local-rs/thread_local/index.html
#[derive(Debug)]
pub struct QemuStateRestoreHelper {
#[allow(unused)]
has_snapshot: bool,
#[allow(unused)]
saved_cpu_states: Vec<CPUArchState>,
fastsnap: Option<FastSnapshotPtr>
}
impl QemuStateRestoreHelper {
#[must_use]
pub fn new() -> Self {
Self {
has_snapshot: false,
saved_cpu_states: vec![],
fastsnap: None
}
}
#[allow(unused)]
pub fn with_fast(fastsnap: Option<FastSnapshotPtr>) -> Self {
let mut r = Self::new();
r.fastsnap = fastsnap;
r
}
}
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<OT>(&mut self, _emulator: libafl_qemu::Qemu, _input: &S::Input, _observers: &mut OT, _exit_kind: &mut ExitKind) {
// unsafe { println!("snapshot post {}",emu::icount_get_raw()) };
}
fn pre_exec(&mut self, emulator: libafl_qemu::Qemu, _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) => unsafe { 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()) };
}
}

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