-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Integrate FrameShift #2572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Integrate FrameShift #2572
Conversation
|
I will need to do a fuzzbench run on this (dunno where, asking around currently). |
include/envs.h
Outdated
| "AFL_GCC_ONLY_FRSV", "AFL_SAN_RECOVER", | ||
| "AFL_PRELOAD_DISCRIMINATE_FORKSERVER_PARENT", "AFL_FORKSRV_UID", | ||
| "AFL_FORKSRV_GID", "AFL_COMPILER_LAUNCHER", NULL}; | ||
| "AFL_FORKSRV_GID", "AFL_COMPILER_LAUNCHER", "AFL_FRAMESHIFT_ENABLED", NULL}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just AFL_FRAMESHIFT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also we should add info about the env into the docs I think
|
Most beneficial setup is likely empty corpus, running in fuzzbench configuration (cmplog + dictionaries). We saw coverage improvements both from empty corpus and from a single seed corpus. The main adversarial setup would be if there are e.g. thousands of seed files which would incur a big initial analysis overhead. I have access to a 128-core server, would be happy to run a full FuzzBench eval if you'd like. |
if you can, then please do! this would be the setup: |
This PR adds support for FrameShift (https://arxiv.org/pdf/2507.05421)
It can be enabled at runtime by setting the env var
AFL_FRAMESHIFT_ENABLED=1.Overview
FrameShift analysis runs once per newly discovered corpus entry in order to try to identify relation fields (i.e. size and offset fields) in the input format. If any are discovered, subsequent resizing mutations (inserts and deletes) will be tracked during the splicing and havoc phase in order to be able to fixup the corresponding relation fields.
The max analysis time per new input is controlled by the compile time definition
FRAMESHIFT_TIME_BUDGET_MS(by default 2 seconds).Evaluation
We evaluated AFL++ with and without FrameShift (on AFL++ v2.1c) on 16 targets and found that enabling FrameShift could confer statistically significant coverage increases of up to 60% (10 x 48 hour runs, p < 0.01) on a variety of targets, such as
lcms,bloaty,ms-tpm-20-ref,woff2,libpcap, andopenssl(refer to our paper for a full table). We also found that enabling FrameShift decreased time-to-trigger bugs on the Magma bug benchmark by about an hour on average during a 24 hour run (unpublished). Our paper eval ran AFL++ in FuzzBench configuration (with cmplog and dict2file).On text-based formats, we don't expect FrameShift to find anything useful and the extra analysis time will likely slow down fuzzing. On the
libxml2target for example, enabling FrameShift decreased coverage by about 12% when starting from a seeded corpus.Practical Usage Suggestions
Enabling FrameShift is likely the most useful when your target input format expects binary-serialized data that contains size or offset fields, especially when they are nested (i.e. most binary formats).
Since FrameShift analysis runs once-per corpus entry, analysis time will be largest either when starting with a large seed corpus or for targets with lots of coverage that grow quickly (i.e.
harfbuzz/freetype2). Keep in mind that the initial startup speed may be slower with FrameShift enabled since it will spend time running analysis instead of directly fuzzing. We expect that in very long fuzz runs (i.e. a week or longer), the analysis time will amortize out as the coverage growth plateaus.Code Changes
The core algorithm and implementation is in src/afl-fuzz-frameshift.c.
The main changes are:
AFL_FRAMESHIFT_ENABLED=1queue_entrystructure is extended with a newfs_meta_t *fs_metafield pointing to the learned relation(s) for the input, and au8 fs_statusindicator.fuzz_one_original, it will run theframeshift_stageon the input to try to learn relations.havocandsplicemutations are tracked and before running the input, the new relation values (if any) are re-serialized into the input.If you are running with
AFL_NO_UI=1, the logs will contain statistics about frameshift at the end of each line:Here:
t: total analysis runtime of the FrameShift stagest(search tests) number of times FrameShift ran a test input dynamicallyavgaverage analysis time per input (upper bounded byFRAMESHIFT_TIME_BUDGET_MS)foundnumber of inputs FrameShift found at least one relation in over number of tested inputsIf the
foundratio is very low, this likely means you are either starting from very unstructured data (i.e. an empty corpus) or you are fuzzing a format without size/offset fields.