CodeIntelligenceTesting / jazzer

Coverage-guided, in-process fuzzing for the JVM
https://code-intelligence.com
Apache License 2.0
980 stars 130 forks source link

Hook is not removed when generating coverage report #878

Open tkmikan opened 8 months ago

tkmikan commented 8 months ago

TLDR: Hooks are not removed after fuzz ends, while their classpath is removed.

Details: I am fuzzing some code taking user input as ArrayList size e.g.

someArrayList = new ArrayList<>(data.consumeInt());

If the fuzzer provides a large int, it will take large memory and long time, so I write a hook to avoid this like:

public final class HugeArrayHooks {
    @MethodHook(type = HookType.BEFORE, targetClassName = "java.util.ArrayList", targetMethod = "<init>", targetMethodDescriptor = "(I)V")
    public static void initHugeArray(MethodHandle method, Object thisObject, Object[] arguments, int hookId) {
        int size = (int) arguments[0];
        if (size > 0x10000) {
            throw new RuntimeException("too large");
        }
    }

}

However, with this hook, exception is raised when generating coverage report.

The cause is, my hook is effective for Pattern.java:1775 new ArrayList<>(10);, but the classpath argument does not work here, resulting in a NoClassDefFoundError.

Stacktrace:

Exception in thread "Thread-2" java.lang.NoClassDefFoundError: org/example/hook/HugeArrayHooks
    at java.base/java.util.regex.Pattern.compile(Pattern.java:1775)
    at java.base/java.util.regex.Pattern.<init>(Pattern.java:1430)
    at java.base/java.util.regex.Pattern.compile(Pattern.java:1069)
    at com.code_intelligence.jazzer.third_party.nonapi.io.github.classgraph.scanspec.AcceptReject.globToPattern(AcceptReject.java:585)
    at com.code_intelligence.jazzer.third_party.nonapi.io.github.classgraph.scanspec.AcceptReject$AcceptRejectWholeString.addToReject(AcceptReject.java:304)
    at com.code_intelligence.jazzer.third_party.io.github.classgraph.ClassGraph.rejectPackages(ClassGraph.java:891)
    at com.code_intelligence.jazzer.instrumentor.CoverageRecorder.analyzeAllUncoveredClasses(CoverageRecorder.kt:225)
    at com.code_intelligence.jazzer.instrumentor.CoverageRecorder.analyzeCoverage(CoverageRecorder.kt:193)
    at com.code_intelligence.jazzer.instrumentor.CoverageRecorder.computeFileCoverage(CoverageRecorder.kt:79)
    at com.code_intelligence.jazzer.instrumentor.CoverageRecorder.dumpCoverageReport(CoverageRecorder.kt:73)
    at com.code_intelligence.jazzer.instrumentor.CoverageRecorder.dumpCoverageReport$default(CoverageRecorder.kt:71)
    at com.code_intelligence.jazzer.instrumentor.CoverageRecorder.dumpCoverageReport(CoverageRecorder.kt)
    at com.code_intelligence.jazzer.driver.FuzzTargetRunner.shutdown(FuzzTargetRunner.java:445)
    at java.base/java.lang.Thread.run(Thread.java:833)

I haven't looked into jazzer's implementation about classloader and instrumention. Some possible fix may be use separate classloaders for fuzzing and others(not hook), or reload/restore after fuzzing.

fmeum commented 8 months ago

Could you provide the steps that lead to that stack trace? How are you running fuzzing with your hook and how are you collecting coverage?

tkmikan commented 8 months ago

To reproduce from jazzer examples, add the above hook function to com.example.ExampleFuzzerHooks, and

./jazzer --cp=examples/src/main/java --target_class=com.example.ExampleFuzzer --custom_hooks=com.example.ExampleFuzzerHooks --coverage_report=report
ghost commented 4 months ago

@tkmikan - thanks for the feedback on this issue. Are you still using Jazzer? You may have seen there haven't been any updates for a while.... We stopped maintaining Jazzer/Jazzer.js as open source. But we'd be happy to understand what you're trying to achieve with it, and help you if we can! For example, maybe our AI-powered fuzz testing platform is the superior choice... Ping me if interested? Ping me? david[dot]merian [at] code-intelligence[dot]com