LibAFL icon indicating copy to clipboard operation
LibAFL copied to clipboard

`ExitKind::Ok` exposing the result of `libfuzzer_test_one_input`

Open alpaylan opened this issue 5 months ago • 6 comments

Currently, libfuzzer_test_one_input returns an i32 that is discarded when turning into ExitKind::Ok, whereas the value could potentially signal interestingness from the harness leveraged by domain-specific fuzzers. I suppose ExitKind is part of the public API so it wouldn't be possible to change it after this point, but perhaps an ExitKind::Value(i32) would come in handy?

alpaylan avatar Aug 20 '25 18:08 alpaylan

ExitKind::Value would be interesting, but it would need to be generic... I can see use cases including things like differential fuzzers where we would care about other types of values. Implementing this is nontrivial, though.

The LLVMFuzzerTestOneInput function has well-defined return values, though. We have functionality for processing this more precisely if needed (note that -2 is LibAFL specific behavior).

addisoncrump avatar Aug 23 '25 11:08 addisoncrump

The ability to have a generic result would be very nice but I guess it wouldn't be possible given the fact that the output type is capped by size to be an integer, so the return type must have a cardinality of 2^64, that is if we don't coerce it to return a pointer instead?

I hadn't seen the -2 case, that is a bit unfortunate I guess, but is it part of the public API? The harness wrap is only pub(crate) so it seems possible to change? What I can think of is to change the return type of https://github.com/AFLplusplus/LibAFL/blob/main/crates/libafl_libfuzzer/runtime/src/harness_wrap.cpp#L3 to be a tagged union that returns HarnessExitKind::Crash on the failure case instead of -2 and return HarnessExitKind::Ok on the success case, which would be constrained within the bounds of the library without leaking outside?

The LibFuzzer definition seems to me to be a fuzzer specific interpretation of the result value, so the default behavior could be to use 0 and 1 as keep/discard but it shouldn't be forced onto all potential fuzzers written using LibAFL?

alpaylan avatar Aug 25 '25 14:08 alpaylan

The ability to have a generic result would be very nice but I guess it wouldn't be possible given the fact that the output type is capped by size to be an integer, so the return type must have a cardinality of 2^64, that is if we don't coerce it to return a pointer instead?

We don't just fuzz libFuzzer targets :) Sometimes we might fuzz something with a different harness type, and want to have some structured return value.

I hadn't seen the -2 case

Don't worry about that, that just means "crash". We wouldn't export that to user.

it shouldn't be forced onto all potential fuzzers written using LibAFL?

It isn't; that's the libFuzzer compatibility code. What I'm suggesting is that, if we do want to support value collection from the target (outside of how we already do so with observers), it would need to be generic s.t. people can return whatever they like from their harness.

addisoncrump avatar Aug 25 '25 14:08 addisoncrump

Ah I see. I initially misunderstood the concern, sorry.

alpaylan avatar Aug 25 '25 15:08 alpaylan

So, just to summarise: this issue is a "nice to have" for a generic value present in the ExitKind::Ok and maybe a second generic value present in the ExitKind::Crash (vis-a-vis Result).

addisoncrump avatar Aug 26 '25 17:08 addisoncrump

Yes, that is correct I think. As an possible alternative to avoid breaking existing harnesses, having a new variant ExitKind::Value(T) could also be useful.

alpaylan avatar Aug 26 '25 18:08 alpaylan