aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Meumertzheim <fabian@meumertzhe.im>2022-08-16 14:42:39 +0200
committerFabian Meumertzheim <fabian@meumertzhe.im>2022-08-18 12:54:22 +0200
commitee34e9fb291f03c7a90795a1b5f91a0ec7fba90f (patch)
tree571b798114e5c82ed044cda4d9878470055757ef
parent6ee1c1c39fe00ad36aacff32b526bca8eacd800f (diff)
downloadjazzer-api-ee34e9fb291f03c7a90795a1b5f91a0ec7fba90f.tar.gz
driver: Load fuzz target with Driver's class loader
This ensures that the fuzz target is found even if Driver is loaded by a custom class loader.
-rw-r--r--driver/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java61
1 files changed, 51 insertions, 10 deletions
diff --git a/driver/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java b/driver/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java
index fd7a3255..731cd82a 100644
--- a/driver/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java
+++ b/driver/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java
@@ -39,6 +39,7 @@ import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.HashSet;
@@ -70,18 +71,58 @@ public final class FuzzTargetRunner {
static {
String targetClassName = determineFuzzTargetClassName();
+
+ // FuzzTargetRunner is loaded by the bootstrap class loader since Driver installs the agent
+ // before invoking FuzzTargetRunner.startLibFuzzer. We can't load the fuzz target with that
+ // class loader - we have to use the class loader that loaded Driver. This would be
+ // straightforward to do in Java 9+, but requires the use of reflection to maintain
+ // compatibility with Java 8, which doesn't have StackWalker.
+ //
+ // Note that we can't just move the agent initialization so that FuzzTargetRunner is loaded by
+ // Driver's class loader: The agent and FuzzTargetRunner have to share the native library that
+ // contains libFuzzer and that library needs to be available in the bootstrap class loader
+ // since instrumentation applied to Java standard library classes still needs to be able to call
+ // libFuzzer hooks. A fundamental JNI restriction is that a native library can't be shared
+ // between two different class loaders, so FuzzTargetRunner is thus forced to be loaded in the
+ // bootstrap class loader, which makes this ugly code block necessary.
+ // We also can't use the system class loader since Driver may be loaded by a custom class loader
+ // if not invoked from the native driver.
+ Class<?> driverClass;
try {
- // When running with the agent, the JAR containing the agent and the driver has been added to
- // the bootstrap class loader path at the time the native driver can use FindClass to load the
- // Java fuzz target runner. As a result, FuzzTargetRunner's class loader will be the bootstrap
- // class loader, which doesn't have the fuzz target on its classpath. We thus have to
- // explicitly use the system class loader in this case.
- ClassLoader notBootstrapLoader = FuzzTargetRunner.class.getClassLoader();
- if (notBootstrapLoader == null) {
- notBootstrapLoader = ClassLoader.getSystemClassLoader();
+ Class<?> reflectionClass = Class.forName("sun.reflect.Reflection");
+ try {
+ driverClass =
+ (Class<?>) reflectionClass.getMethod("getCallerClass", int.class).invoke(null, 2);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ } catch (ClassNotFoundException e) {
+ // sun.reflect.Reflection is no longer available after Java 8, use StackWalker.
+ try {
+ Class<?> stackWalker = Class.forName("java.lang.StackWalker");
+ Class<? extends Enum<?>> stackWalkerOption =
+ (Class<? extends Enum<?>>) Class.forName("java.lang.StackWalker$Option");
+ Enum<?> retainClassReferences =
+ Arrays.stream(stackWalkerOption.getEnumConstants())
+ .filter(v -> v.name().equals("RETAIN_CLASS_REFERENCE"))
+ .findFirst()
+ .orElseThrow(()
+ -> new IllegalStateException(
+ "No RETAIN_CLASS_REFERENCE in java.lang.StackWalker$Option"));
+ Object stackWalkerInstance = stackWalker.getMethod("getInstance", stackWalkerOption)
+ .invoke(null, retainClassReferences);
+ Method stackWalkerGetCallerClass = stackWalker.getMethod("getCallerClass");
+ driverClass = (Class<?>) stackWalkerGetCallerClass.invoke(stackWalkerInstance);
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
+ | InvocationTargetException ex) {
+ throw new IllegalStateException(ex);
}
- notBootstrapLoader.setDefaultAssertionStatus(true);
- fuzzTargetClass = Class.forName(targetClassName, false, notBootstrapLoader);
+ }
+
+ try {
+ ClassLoader driverClassLoader = driverClass.getClassLoader();
+ driverClassLoader.setDefaultAssertionStatus(true);
+ fuzzTargetClass = Class.forName(targetClassName, false, driverClassLoader);
} catch (ClassNotFoundException e) {
err.print("ERROR: ");
e.printStackTrace(err);