blob: 97adf578e261b08e489efc35f93d2aea72c55579 [file] [log] [blame]
// Copyright 2021 Code Intelligence GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.code_intelligence.jazzer.api;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.security.SecureRandom;
/**
* Helper class with static methods that interact with Jazzer at runtime.
*/
final public class Jazzer {
/**
* A 32-bit random number that hooks can use to make pseudo-random choices
* between multiple possible mutations they could guide the fuzzer towards.
* Hooks <b>must not</b> base the decision whether or not to report a finding
* on this number as this will make findings non-reproducible.
* <p>
* This is the same number that libFuzzer uses as a seed internally, which
* makes it possible to deterministically reproduce a previous fuzzing run by
* supplying the seed value printed by libFuzzer as the value of the
* {@code -seed}.
*/
public static final int SEED = getLibFuzzerSeed();
private static final Class<?> JAZZER_INTERNAL;
private static final MethodHandle ON_FUZZ_TARGET_READY;
private static final MethodHandle TRACE_STRCMP;
private static final MethodHandle TRACE_STRSTR;
private static final MethodHandle TRACE_MEMCMP;
private static final MethodHandle TRACE_PC_INDIR;
private static final MethodHandle CONSUME;
private static final MethodHandle AUTOFUZZ_FUNCTION_1;
private static final MethodHandle AUTOFUZZ_FUNCTION_2;
private static final MethodHandle AUTOFUZZ_FUNCTION_3;
private static final MethodHandle AUTOFUZZ_FUNCTION_4;
private static final MethodHandle AUTOFUZZ_FUNCTION_5;
private static final MethodHandle AUTOFUZZ_CONSUMER_1;
private static final MethodHandle AUTOFUZZ_CONSUMER_2;
private static final MethodHandle AUTOFUZZ_CONSUMER_3;
private static final MethodHandle AUTOFUZZ_CONSUMER_4;
private static final MethodHandle AUTOFUZZ_CONSUMER_5;
static {
Class<?> jazzerInternal = null;
MethodHandle onFuzzTargetReady = null;
MethodHandle traceStrcmp = null;
MethodHandle traceStrstr = null;
MethodHandle traceMemcmp = null;
MethodHandle tracePcIndir = null;
MethodHandle consume = null;
MethodHandle autofuzzFunction1 = null;
MethodHandle autofuzzFunction2 = null;
MethodHandle autofuzzFunction3 = null;
MethodHandle autofuzzFunction4 = null;
MethodHandle autofuzzFunction5 = null;
MethodHandle autofuzzConsumer1 = null;
MethodHandle autofuzzConsumer2 = null;
MethodHandle autofuzzConsumer3 = null;
MethodHandle autofuzzConsumer4 = null;
MethodHandle autofuzzConsumer5 = null;
try {
jazzerInternal = Class.forName("com.code_intelligence.jazzer.runtime.JazzerInternal");
MethodType onFuzzTargetReadyType = MethodType.methodType(void.class, Runnable.class);
onFuzzTargetReady = MethodHandles.publicLookup().findStatic(
jazzerInternal, "registerOnFuzzTargetReadyCallback", onFuzzTargetReadyType);
Class<?> traceDataFlowNativeCallbacks =
Class.forName("com.code_intelligence.jazzer.runtime.TraceDataFlowNativeCallbacks");
// Use method handles for hints as the calls are potentially performance critical.
MethodType traceStrcmpType =
MethodType.methodType(void.class, String.class, String.class, int.class, int.class);
traceStrcmp = MethodHandles.publicLookup().findStatic(
traceDataFlowNativeCallbacks, "traceStrcmp", traceStrcmpType);
MethodType traceStrstrType =
MethodType.methodType(void.class, String.class, String.class, int.class);
traceStrstr = MethodHandles.publicLookup().findStatic(
traceDataFlowNativeCallbacks, "traceStrstr", traceStrstrType);
MethodType traceMemcmpType =
MethodType.methodType(void.class, byte[].class, byte[].class, int.class, int.class);
traceMemcmp = MethodHandles.publicLookup().findStatic(
traceDataFlowNativeCallbacks, "traceMemcmp", traceMemcmpType);
MethodType tracePcIndirType = MethodType.methodType(void.class, int.class, int.class);
tracePcIndir = MethodHandles.publicLookup().findStatic(
traceDataFlowNativeCallbacks, "tracePcIndir", tracePcIndirType);
Class<?> metaClass = Class.forName("com.code_intelligence.jazzer.autofuzz.Meta");
MethodType consumeType =
MethodType.methodType(Object.class, FuzzedDataProvider.class, Class.class);
consume = MethodHandles.publicLookup().findStatic(metaClass, "consume", consumeType);
autofuzzFunction1 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(Object.class, FuzzedDataProvider.class, Function1.class));
autofuzzFunction2 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(Object.class, FuzzedDataProvider.class, Function2.class));
autofuzzFunction3 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(Object.class, FuzzedDataProvider.class, Function3.class));
autofuzzFunction4 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(Object.class, FuzzedDataProvider.class, Function4.class));
autofuzzFunction5 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(Object.class, FuzzedDataProvider.class, Function5.class));
autofuzzConsumer1 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer1.class));
autofuzzConsumer2 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer2.class));
autofuzzConsumer3 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer3.class));
autofuzzConsumer4 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer4.class));
autofuzzConsumer5 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz",
MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer5.class));
} catch (ClassNotFoundException ignore) {
// Not running in the context of the agent. This is fine as long as no methods are called on
// this class.
} catch (NoSuchMethodException | IllegalAccessException e) {
// This should never happen as the Jazzer API is loaded from the agent and thus should always
// match the version of the runtime classes.
System.err.println("ERROR: Incompatible version of the Jazzer API detected, please update.");
e.printStackTrace();
System.exit(1);
}
JAZZER_INTERNAL = jazzerInternal;
ON_FUZZ_TARGET_READY = onFuzzTargetReady;
TRACE_STRCMP = traceStrcmp;
TRACE_STRSTR = traceStrstr;
TRACE_MEMCMP = traceMemcmp;
TRACE_PC_INDIR = tracePcIndir;
CONSUME = consume;
AUTOFUZZ_FUNCTION_1 = autofuzzFunction1;
AUTOFUZZ_FUNCTION_2 = autofuzzFunction2;
AUTOFUZZ_FUNCTION_3 = autofuzzFunction3;
AUTOFUZZ_FUNCTION_4 = autofuzzFunction4;
AUTOFUZZ_FUNCTION_5 = autofuzzFunction5;
AUTOFUZZ_CONSUMER_1 = autofuzzConsumer1;
AUTOFUZZ_CONSUMER_2 = autofuzzConsumer2;
AUTOFUZZ_CONSUMER_3 = autofuzzConsumer3;
AUTOFUZZ_CONSUMER_4 = autofuzzConsumer4;
AUTOFUZZ_CONSUMER_5 = autofuzzConsumer5;
}
private Jazzer() {}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Function1} with (partially) specified
* type variables, e.g. {@code (Function1<String, ?>) String::new}.
* @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke
* the function.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
@SuppressWarnings("unchecked")
public static <T1, R> R autofuzz(FuzzedDataProvider data, Function1<T1, R> func) {
try {
return (R) AUTOFUZZ_FUNCTION_1.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
// Not reached.
return null;
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Function2} with (partially) specified
* type variables.
* @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke
* the function.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
@SuppressWarnings("unchecked")
public static <T1, T2, R> R autofuzz(FuzzedDataProvider data, Function2<T1, T2, R> func) {
try {
return (R) AUTOFUZZ_FUNCTION_2.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
// Not reached.
return null;
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Function3} with (partially) specified
* type variables.
* @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke
* the function.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
@SuppressWarnings("unchecked")
public static <T1, T2, T3, R> R autofuzz(FuzzedDataProvider data, Function3<T1, T2, T3, R> func) {
try {
return (R) AUTOFUZZ_FUNCTION_3.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
// Not reached.
return null;
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Function4} with (partially) specified
* type variables.
* @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke
* the function.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
@SuppressWarnings("unchecked")
public static <T1, T2, T3, T4, R> R autofuzz(
FuzzedDataProvider data, Function4<T1, T2, T3, T4, R> func) {
try {
return (R) AUTOFUZZ_FUNCTION_4.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
// Not reached.
return null;
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Function5} with (partially) specified
* type variables.
* @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke
* the function.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
@SuppressWarnings("unchecked")
public static <T1, T2, T3, T4, T5, R> R autofuzz(
FuzzedDataProvider data, Function5<T1, T2, T3, T4, T5, R> func) {
try {
return (R) AUTOFUZZ_FUNCTION_5.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
// Not reached.
return null;
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Consumer1} with explicitly specified
* type variable.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
public static <T1> void autofuzz(FuzzedDataProvider data, Consumer1<T1> func) {
try {
AUTOFUZZ_CONSUMER_1.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Consumer2} with (partially) specified
* type variables.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
public static <T1, T2> void autofuzz(FuzzedDataProvider data, Consumer2<T1, T2> func) {
try {
AUTOFUZZ_CONSUMER_2.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Consumer3} with (partially) specified
* type variables.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
public static <T1, T2, T3> void autofuzz(FuzzedDataProvider data, Consumer3<T1, T2, T3> func) {
try {
AUTOFUZZ_CONSUMER_3.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Consumer4} with (partially) specified
* type variables.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
public static <T1, T2, T3, T4> void autofuzz(
FuzzedDataProvider data, Consumer4<T1, T2, T3, T4> func) {
try {
AUTOFUZZ_CONSUMER_4.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
}
/**
* Attempts to invoke {@code func} with arguments created automatically from the fuzzer input
* using only public methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to execute {@code func} in
* meaningful ways for a number of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param func a method reference for the function to autofuzz. If there are multiple overloads,
* resolve ambiguities by explicitly casting to {@link Consumer5} with (partially) specified
* type variables.
* @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link
* AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call.
* The {@link Throwable} is thrown unchecked.
*/
public static <T1, T2, T3, T4, T5> void autofuzz(
FuzzedDataProvider data, Consumer5<T1, T2, T3, T4, T5> func) {
try {
AUTOFUZZ_CONSUMER_5.invoke(data, func);
} catch (AutofuzzInvocationException e) {
rethrowUnchecked(e.getCause());
} catch (Throwable t) {
rethrowUnchecked(t);
}
}
/**
* Attempts to construct an instance of {@code type} from the fuzzer input using only public
* methods available on the classpath.
* <p>
* <b>Note:</b> This function is inherently heuristic and may fail to return meaningful values for
* a variety of reasons.
*
* @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}.
* @param type the {@link Class} to construct an instance of.
* @return an instance of {@code type} constructed from the fuzzer input, or {@code null} if
* autofuzz failed to create an instance.
*/
@SuppressWarnings("unchecked")
public static <T> T consume(FuzzedDataProvider data, Class<T> type) {
try {
return (T) CONSUME.invokeExact(data, type);
} catch (AutofuzzConstructionException ignored) {
return null;
} catch (Throwable t) {
rethrowUnchecked(t);
// Not reached.
return null;
}
}
/**
* Instructs the fuzzer to guide its mutations towards making {@code current} equal to {@code
* target}.
* <p>
* If the relation between the raw fuzzer input and the value of {@code current} is relatively
* complex, running the fuzzer with the argument {@code -use_value_profile=1} may be necessary to
* achieve equality.
*
* @param current a non-constant string observed during fuzz target execution
* @param target a string that {@code current} should become equal to, but currently isn't
* @param id a (probabilistically) unique identifier for this particular compare hint
*/
public static void guideTowardsEquality(String current, String target, int id) {
if (TRACE_STRCMP == null) {
return;
}
try {
TRACE_STRCMP.invokeExact(current, target, 1, id);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Instructs the fuzzer to guide its mutations towards making {@code current} equal to {@code
* target}.
* <p>
* If the relation between the raw fuzzer input and the value of {@code current} is relatively
* complex, running the fuzzer with the argument {@code -use_value_profile=1} may be necessary to
* achieve equality.
*
* @param current a non-constant byte array observed during fuzz target execution
* @param target a byte array that {@code current} should become equal to, but currently isn't
* @param id a (probabilistically) unique identifier for this particular compare hint
*/
public static void guideTowardsEquality(byte[] current, byte[] target, int id) {
if (TRACE_MEMCMP == null) {
return;
}
try {
TRACE_MEMCMP.invokeExact(current, target, 1, id);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Instructs the fuzzer to guide its mutations towards making {@code haystack} contain {@code
* needle} as a substring.
* <p>
* If the relation between the raw fuzzer input and the value of {@code haystack} is relatively
* complex, running the fuzzer with the argument {@code -use_value_profile=1} may be necessary to
* satisfy the substring check.
*
* @param haystack a non-constant string observed during fuzz target execution
* @param needle a string that should be contained in {@code haystack} as a substring, but
* currently isn't
* @param id a (probabilistically) unique identifier for this particular compare hint
*/
public static void guideTowardsContainment(String haystack, String needle, int id) {
if (TRACE_STRSTR == null) {
return;
}
try {
TRACE_STRSTR.invokeExact(haystack, needle, id);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Instructs the fuzzer to attain as many possible values for the absolute value of {@code state}
* as possible.
* <p>
* Call this function from a fuzz target or a hook to help the fuzzer track partial progress
* (e.g. by passing the length of a common prefix of two lists that should become equal) or
* explore different values of state that is not directly related to code coverage (see the
* MazeFuzzer example).
* <p>
* <b>Note:</b> This hint only takes effect if the fuzzer is run with the argument
* {@code -use_value_profile=1}.
*
* @param state a numeric encoding of a state that should be varied by the fuzzer
* @param id a (probabilistically) unique identifier for this particular state hint
*/
public static void exploreState(byte state, int id) {
if (TRACE_PC_INDIR == null) {
return;
}
// We only use the lower 7 bits of state, which allows for 128 different state values tracked
// per id. The particular amount of 7 bits of state is also used in libFuzzer's
// TracePC::HandleCmp:
// https://github.com/llvm/llvm-project/blob/c12d49c4e286fa108d4d69f1c6d2b8d691993ffd/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp#L390
// This value should be large enough for most use cases (e.g. tracking the length of a prefix in
// a comparison) while being small enough that the bitmap isn't filled up too quickly
// (65536 bits/ 128 bits per id = 512 ids).
// We use tracePcIndir as a way to set a bit in libFuzzer's value profile bitmap. In
// TracePC::HandleCallerCallee, which is what this function ultimately calls through to, the
// lower 12 bits of each argument are combined into a 24-bit index into the bitmap, which is
// then reduced modulo a 16-bit prime. To keep the modulo bias small, we should fill as many
// of the relevant bits as possible. However, there are the following restrictions:
// 1. Since we use the return address trampoline to set the caller address indirectly, its
// upper 3 bits are fixed, which leaves a total of 21 variable bits on x86_64.
// 2. On arm64 macOS, where every instruction is aligned to 4 bytes, the lower 2 bits of the
// caller address will always be zero, further reducing the number of variable bits in the
// caller parameter to 7.
// https://github.com/llvm/llvm-project/blob/c12d49c4e286fa108d4d69f1c6d2b8d691993ffd/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp#L121
// Even taking these restrictions into consideration, we pass state in the lowest bits of the
// caller address, which is used to form the lowest bits of the bitmap index. This should result
// in the best caching behavior as state is expected to change quickly in consecutive runs and
// in this way all its bitmap entries would be located close to each other in memory.
int lowerBits = (state & 0x7f) | (id << 7);
int upperBits = id >>> 5;
try {
TRACE_PC_INDIR.invokeExact(upperBits, lowerBits);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* Make Jazzer report the provided {@link Throwable} as a finding.
* <p>
* <b>Note:</b> This method must only be called from a method hook. In a
* fuzz target, simply throw an exception to trigger a finding.
* @param finding the finding that Jazzer should report
*/
public static void reportFindingFromHook(Throwable finding) {
try {
JAZZER_INTERNAL.getMethod("reportFindingFromHook", Throwable.class).invoke(null, finding);
} catch (NullPointerException | IllegalAccessException | NoSuchMethodException e) {
// We can only reach this point if the runtime is not on the classpath, e.g. in case of a
// reproducer. Just throw the finding.
rethrowUnchecked(finding);
} catch (InvocationTargetException e) {
// reportFindingFromHook throws a HardToCatchThrowable, which will bubble up wrapped in an
// InvocationTargetException that should not be stopped here.
if (e.getCause().getClass().getName().endsWith(".HardToCatchError")) {
throw(Error) e.getCause();
} else {
e.printStackTrace();
}
}
}
/**
* Register a callback to be executed right before the fuzz target is executed for the first time.
* <p>
* This can be used to disable hooks until after Jazzer has been fully initializing, e.g. to
* prevent Jazzer internals from triggering hooks on Java standard library classes.
*
* @param callback the callback to execute
*/
public static void onFuzzTargetReady(Runnable callback) {
try {
ON_FUZZ_TARGET_READY.invokeExact(callback);
} catch (Throwable e) {
e.printStackTrace();
}
}
private static int getLibFuzzerSeed() {
// The Jazzer driver sets this property based on the value of libFuzzer's -seed command-line
// option, which allows for fully reproducible fuzzing runs if set. If not running in the
// context of the driver, fall back to a random number instead.
String rawSeed = System.getProperty("jazzer.seed");
if (rawSeed == null) {
return new SecureRandom().nextInt();
}
// If jazzer.seed is set, we expect it to be a valid integer.
return Integer.parseUnsignedInt(rawSeed);
}
// Rethrows a (possibly checked) exception while avoiding a throws declaration.
@SuppressWarnings("unchecked")
private static <T extends Throwable> void rethrowUnchecked(Throwable t) throws T {
throw(T) t;
}
}