diff options
author | Fabian Meumertzheim <meumertzheim@code-intelligence.com> | 2023-06-02 16:36:52 +0200 |
---|---|---|
committer | Fabian Meumertzheim <fabian@meumertzhe.im> | 2023-06-06 08:45:25 +0200 |
commit | 0615190974864714ee2318654035d09f449145a3 (patch) | |
tree | 8103a53205783397b96b16a04ff51f5fdf087bf8 | |
parent | b12d1ea863b336b120e192700ac11c9744af6cfd (diff) | |
download | jazzer-api-0615190974864714ee2318654035d09f449145a3.tar.gz |
all: Only load Opt in the system class loader
We can detect whether we are running on Android via system properties
and thus don't need to have this bit passed in via a flag.
As a result, the runtime no longer depends on Opt, which is thus no
longer loaded in the bootstrap class loader in addition to the system
class loader.
15 files changed, 82 insertions, 54 deletions
diff --git a/src/main/java/com/code_intelligence/jazzer/BUILD.bazel b/src/main/java/com/code_intelligence/jazzer/BUILD.bazel index 779fab66..ea3eaa6b 100644 --- a/src/main/java/com/code_intelligence/jazzer/BUILD.bazel +++ b/src/main/java/com/code_intelligence/jazzer/BUILD.bazel @@ -117,6 +117,7 @@ java_library( ], deps = [ "//src/main/java/com/code_intelligence/jazzer/driver", + "//src/main/java/com/code_intelligence/jazzer/runtime:constants", "//src/main/java/com/code_intelligence/jazzer/utils:log", "@fmeum_rules_jni//jni/tools/native_loader", ], diff --git a/src/main/java/com/code_intelligence/jazzer/Jazzer.java b/src/main/java/com/code_intelligence/jazzer/Jazzer.java index 54664d76..e0f7bad6 100644 --- a/src/main/java/com/code_intelligence/jazzer/Jazzer.java +++ b/src/main/java/com/code_intelligence/jazzer/Jazzer.java @@ -16,6 +16,7 @@ package com.code_intelligence.jazzer; +import static com.code_intelligence.jazzer.runtime.Constants.IS_ANDROID; import static java.lang.System.exit; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -208,7 +209,7 @@ public class Jazzer { } char shellQuote = isPosixOrAndroid() ? '\'' : '"'; String launcherTemplate; - if (isAndroid()) { + if (IS_ANDROID) { launcherTemplate = "#!/system/bin/env sh\n%s $@\n"; } else if (isPosix()) { launcherTemplate = "#!/usr/bin/env sh\n%s $@\n"; @@ -237,7 +238,7 @@ public class Jazzer { // argv0 is printed by libFuzzer during reproduction, so have the launcher basename contain // "jazzer". Path launcher; - if (isAndroid()) { + if (IS_ANDROID) { launcher = Files.createTempFile( Paths.get("/data/local/tmp/"), "jazzer-", launcherExtension, launcherScriptAttributes); } else { @@ -251,7 +252,7 @@ public class Jazzer { private static Path javaBinary() { String javaBinaryName; - if (isAndroid()) { + if (IS_ANDROID) { javaBinaryName = "dalvikvm"; } else if (isPosix()) { javaBinaryName = "java"; @@ -274,7 +275,7 @@ public class Jazzer { // entitlements required for library insertion. "-Djdk.attach.allowAttachSelf=true", Jazzer.class.getName()); - if (isAndroid()) { + if (IS_ANDROID) { // ManagementFactory wont work with Android return stream; } @@ -300,7 +301,7 @@ public class Jazzer { } private static Path findLibrary(List<String> candidateNames) { - if (!isAndroid()) { + if (!IS_ANDROID) { return findHostClangLibrary(candidateNames); } @@ -387,7 +388,7 @@ public class Jazzer { } private static List<String> hwasanLibNames() { - if (!isAndroid()) { + if (!IS_ANDROID) { Log.error("HWAsan is only supported for Android. Please try --asan"); exit(1); } @@ -397,7 +398,7 @@ public class Jazzer { private static List<String> asanLibNames() { if (isLinux()) { - if (isAndroid()) { + if (IS_ANDROID) { Log.error("ASan is not supported for Android at this time. Use --hwasan for Address " + "Sanitization on Android"); exit(1); @@ -412,7 +413,7 @@ public class Jazzer { private static List<String> ubsanLibNames() { if (isLinux()) { - if (isAndroid()) { + if (IS_ANDROID) { // return asList("libclang_rt.ubsan_standalone-aarch64-android.so"); Log.error("ERROR: UBSan is not supported for Android at this time."); exit(1); @@ -437,15 +438,14 @@ public class Jazzer { } private static boolean isPosix() { - return !isAndroid() && FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); - } - - private static boolean isAndroid() { - return Boolean.parseBoolean(System.getProperty("jazzer.android", "false")); + return !IS_ANDROID && FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); } private static boolean isPosixOrAndroid() { - return isPosix() || isAndroid(); + if (isPosix()) { + return true; + } + return IS_ANDROID; } private static byte[] readAllBytes(InputStream in) throws IOException { diff --git a/src/main/java/com/code_intelligence/jazzer/agent/AgentInstaller.java b/src/main/java/com/code_intelligence/jazzer/agent/AgentInstaller.java index 5006c243..5dd041ac 100644 --- a/src/main/java/com/code_intelligence/jazzer/agent/AgentInstaller.java +++ b/src/main/java/com/code_intelligence/jazzer/agent/AgentInstaller.java @@ -15,8 +15,8 @@ package com.code_intelligence.jazzer.agent; import static com.code_intelligence.jazzer.agent.AgentUtils.extractBootstrapJar; +import static com.code_intelligence.jazzer.runtime.Constants.IS_ANDROID; -import com.code_intelligence.jazzer.driver.Opt; import java.lang.instrument.Instrumentation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -37,7 +37,7 @@ public class AgentInstaller { return; } - if (Opt.isAndroid) { + if (IS_ANDROID) { return; } diff --git a/src/main/java/com/code_intelligence/jazzer/agent/BUILD.bazel b/src/main/java/com/code_intelligence/jazzer/agent/BUILD.bazel index 89dc0bc9..3106acb7 100644 --- a/src/main/java/com/code_intelligence/jazzer/agent/BUILD.bazel +++ b/src/main/java/com/code_intelligence/jazzer/agent/BUILD.bazel @@ -11,6 +11,7 @@ java_library( deps = [ ":agent_lib", "//src/main/java/com/code_intelligence/jazzer/driver:opt", + "//src/main/java/com/code_intelligence/jazzer/runtime:constants", "@net_bytebuddy_byte_buddy_agent//jar", ], ) diff --git a/src/main/java/com/code_intelligence/jazzer/driver/BUILD.bazel b/src/main/java/com/code_intelligence/jazzer/driver/BUILD.bazel index 468d4d79..48e4af44 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/BUILD.bazel +++ b/src/main/java/com/code_intelligence/jazzer/driver/BUILD.bazel @@ -22,6 +22,7 @@ java_library( ":opt", "//src/main/java/com/code_intelligence/jazzer/agent:agent_installer", "//src/main/java/com/code_intelligence/jazzer/driver/junit:junit_runner", + "//src/main/java/com/code_intelligence/jazzer/runtime:constants", "//src/main/java/com/code_intelligence/jazzer/utils:log", ], ) @@ -47,6 +48,7 @@ kt_jvm_library( deps = [ ":opt", "//src/main/java/com/code_intelligence/jazzer/api:hooks", + "//src/main/java/com/code_intelligence/jazzer/runtime:constants", "//src/main/java/com/code_intelligence/jazzer/utils:log", ], ) @@ -59,6 +61,7 @@ java_library( ":fuzz_target_holder", ":opt", "//src/main/java/com/code_intelligence/jazzer/api", + "//src/main/java/com/code_intelligence/jazzer/runtime:constants", "//src/main/java/com/code_intelligence/jazzer/utils:log", "//src/main/java/com/code_intelligence/jazzer/utils:manifest_utils", ], @@ -106,6 +109,7 @@ java_jni_library( "//src/main/java/com/code_intelligence/jazzer/autofuzz", "//src/main/java/com/code_intelligence/jazzer/instrumentor", "//src/main/java/com/code_intelligence/jazzer/mutation", + "//src/main/java/com/code_intelligence/jazzer/runtime:constants", "//src/main/java/com/code_intelligence/jazzer/runtime:jazzer_bootstrap_compile_only", "//src/main/java/com/code_intelligence/jazzer/utils:log", "//src/main/java/com/code_intelligence/jazzer/utils:manifest_utils", @@ -143,9 +147,10 @@ java_library( "OptParser.java", ], visibility = [ - "//src/main/java/com/code_intelligence/jazzer:__subpackages__", + "//src/main/java/com/code_intelligence/jazzer/agent:__pkg__", + "//src/main/java/com/code_intelligence/jazzer/driver:__subpackages__", "//src/main/java/com/code_intelligence/jazzer/junit:__pkg__", - "//src/test/java/com/code_intelligence/jazzer/driver:__pkg__", + "//src/test/java/com/code_intelligence/jazzer/driver:__subpackages__", ], deps = [ "//src/main/java/com/code_intelligence/jazzer:constants", diff --git a/src/main/java/com/code_intelligence/jazzer/driver/Driver.java b/src/main/java/com/code_intelligence/jazzer/driver/Driver.java index a99a155d..8640e6c3 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/Driver.java +++ b/src/main/java/com/code_intelligence/jazzer/driver/Driver.java @@ -16,6 +16,7 @@ package com.code_intelligence.jazzer.driver; +import static com.code_intelligence.jazzer.runtime.Constants.IS_ANDROID; import static java.lang.System.exit; import com.code_intelligence.jazzer.agent.AgentInstaller; @@ -32,8 +33,7 @@ import java.util.Optional; public class Driver { public static int start(List<String> args, boolean spawnsSubprocesses) throws IOException { - boolean isAndroid = Boolean.parseBoolean(System.getProperty("jazzer.android", "false")); - if (isAndroid) { + if (IS_ANDROID) { if (!System.getProperty("jazzer.autofuzz", "").isEmpty()) { Log.error("--autofuzz is not supported for Android"); return 1; @@ -65,7 +65,7 @@ public class Driver { // pass its path to the agent in every child process. This requires adding // the argument to argv for it to be picked up by libFuzzer, which then // forwards it to child processes. - if (!isAndroid) { + if (!IS_ANDROID) { idSyncFile = Files.createTempFile("jazzer-", ""); } else { File f = File.createTempFile("jazzer-", "", new File("/data/local/tmp/")); diff --git a/src/main/java/com/code_intelligence/jazzer/driver/ExceptionUtils.kt b/src/main/java/com/code_intelligence/jazzer/driver/ExceptionUtils.kt index 3bec53da..ed4b0569 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/ExceptionUtils.kt +++ b/src/main/java/com/code_intelligence/jazzer/driver/ExceptionUtils.kt @@ -17,6 +17,7 @@ package com.code_intelligence.jazzer.driver import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow +import com.code_intelligence.jazzer.runtime.Constants.IS_ANDROID import com.code_intelligence.jazzer.utils.Log import java.lang.management.ManagementFactory import java.nio.ByteBuffer @@ -97,7 +98,7 @@ fun preprocessThrowable(throwable: Throwable): Throwable = when (throwable) { (frame !in observedFrames).also { observedFrames.add(frame) } } var securityIssueMessage = "Stack overflow" - if (!Opt.isAndroid) { + if (!IS_ANDROID) { securityIssueMessage = "$securityIssueMessage (use '${getReproducingXssArg()}' to reproduce)" } FuzzerSecurityIssueLow(securityIssueMessage, throwable).apply { @@ -106,7 +107,7 @@ fun preprocessThrowable(throwable: Throwable): Throwable = when (throwable) { } is OutOfMemoryError -> { var securityIssueMessage = "Out of memory" - if (!Opt.isAndroid) { + if (!IS_ANDROID) { securityIssueMessage = "$securityIssueMessage (use '${getReproducingXmxArg()}' to reproduce)" } stripOwnStackTrace(FuzzerSecurityIssueLow(securityIssueMessage, throwable)) @@ -200,7 +201,7 @@ fun dumpAllStackTraces() { Log.println("") } - if (Opt.isAndroid) { + if (IS_ANDROID) { // ManagementFactory is not supported on Android return } diff --git a/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetFinder.java b/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetFinder.java index ef3c0bcd..c2c41774 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetFinder.java +++ b/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetFinder.java @@ -16,6 +16,7 @@ package com.code_intelligence.jazzer.driver; +import static com.code_intelligence.jazzer.runtime.Constants.IS_ANDROID; import static java.lang.System.exit; import com.code_intelligence.jazzer.api.FuzzedDataProvider; @@ -40,7 +41,7 @@ class FuzzTargetFinder { if (!Opt.targetClass.isEmpty()) { return Opt.targetClass; } - if (Opt.isAndroid) { + if (IS_ANDROID) { // Fuzz target detection tools aren't supported on android return null; } @@ -55,12 +56,8 @@ class FuzzTargetFinder { static FuzzTarget findFuzzTarget(String targetClassName) { Class<?> fuzzTargetClass; try { - if (Opt.isAndroid) { - fuzzTargetClass = - Class.forName(targetClassName, false, FuzzTargetFinder.class.getClassLoader()); - } else { - fuzzTargetClass = Class.forName(targetClassName); - } + fuzzTargetClass = + Class.forName(targetClassName, false, FuzzTargetFinder.class.getClassLoader()); } catch (ClassNotFoundException e) { Log.error(String.format( "'%s' not found on classpath:%n%n%s%n%nAll required classes must be on the classpath specified via --cp.", diff --git a/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java b/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java index 7a4992bd..a5e189e9 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java +++ b/src/main/java/com/code_intelligence/jazzer/driver/FuzzTargetRunner.java @@ -17,6 +17,7 @@ package com.code_intelligence.jazzer.driver; import static com.code_intelligence.jazzer.driver.Constants.JAZZER_FINDING_EXIT_CODE; +import static com.code_intelligence.jazzer.runtime.Constants.IS_ANDROID; import static java.lang.System.exit; import static java.util.stream.Collectors.joining; @@ -95,7 +96,7 @@ public final class FuzzTargetRunner { throw new IllegalStateException(e); } useFuzzedDataProvider = fuzzTarget.usesFuzzedDataProvider(); - if (!useFuzzedDataProvider && Opt.isAndroid) { + if (!useFuzzedDataProvider && IS_ANDROID) { Log.error("Android fuzz targets must use " + FuzzedDataProvider.class.getName()); exit(1); throw new IllegalStateException("Not reached"); @@ -367,7 +368,9 @@ public final class FuzzTargetRunner { // https://github.com/llvm/llvm-project/blob/da3623de2411dd931913eb510e94fe846c929c24/compiler-rt/lib/fuzzer/FuzzerFlags.def#L19 args.add("-len_control=100"); } - SignalHandler.initialize(); + if (!IS_ANDROID) { + SignalHandler.initialize(); + } return startLibFuzzer( args.stream().map(str -> str.getBytes(StandardCharsets.UTF_8)).toArray(byte[][] ::new)); } diff --git a/src/main/java/com/code_intelligence/jazzer/driver/Opt.java b/src/main/java/com/code_intelligence/jazzer/driver/Opt.java index f06f81eb..78accfd6 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/Opt.java +++ b/src/main/java/com/code_intelligence/jazzer/driver/Opt.java @@ -42,15 +42,15 @@ import java.util.stream.Stream; * <p>Each option corresponds to a command-line argument of the driver of the same name. * * <p>Every public field should be deeply immutable. - * - * <p>This class is loaded twice: As it is used in {@link FuzzTargetRunner}, it is loaded in the - * class loader that loads {@link Driver}. It is also used in - * {@link com.code_intelligence.jazzer.agent.Agent} after the agent JAR has been added to the - * bootstrap classpath and thus is loaded again in the bootstrap loader. This is not a problem since - * it only provides immutable fields and has no non-fatal side effects. */ public final class Opt { static { + if (Opt.class.getClassLoader() == null) { + throw new IllegalStateException("Opt should not be loaded in the bootstrap class loader"); + } + } + + static { // We additionally list system properties supported by the Jazzer JUnit engine that do not // directly map to arguments. These are not shown in help texts. ignoreSetting("instrument"); @@ -153,10 +153,6 @@ public final class Opt { public static final boolean dedup = boolSetting("dedup", hooks, "Compute and print a deduplication token for every finding"); - // Default to false. Sets if fuzzing is taking place on Android device (virtual or physical) - public static final boolean isAndroid = - boolSetting("android", false, "Jazzer is running on Android"); - // Whether hook instrumentation should add a check for JazzerInternal#hooksEnabled before // executing hooks. Used to disable hooks during non-fuzz JUnit tests. public static final boolean conditionalHooks = diff --git a/src/main/java/com/code_intelligence/jazzer/driver/SignalHandler.java b/src/main/java/com/code_intelligence/jazzer/driver/SignalHandler.java index 0ad913c9..215a0479 100644 --- a/src/main/java/com/code_intelligence/jazzer/driver/SignalHandler.java +++ b/src/main/java/com/code_intelligence/jazzer/driver/SignalHandler.java @@ -19,10 +19,8 @@ import sun.misc.Signal; public final class SignalHandler { static { - if (!Opt.isAndroid) { - RulesJni.loadLibrary("jazzer_signal_handler", SignalHandler.class); - Signal.handle(new Signal("INT"), sig -> handleInterrupt()); - } + RulesJni.loadLibrary("jazzer_signal_handler", SignalHandler.class); + Signal.handle(new Signal("INT"), sig -> handleInterrupt()); } public static void initialize() { diff --git a/src/main/java/com/code_intelligence/jazzer/runtime/BUILD.bazel b/src/main/java/com/code_intelligence/jazzer/runtime/BUILD.bazel index 59064a85..6198f085 100644 --- a/src/main/java/com/code_intelligence/jazzer/runtime/BUILD.bazel +++ b/src/main/java/com/code_intelligence/jazzer/runtime/BUILD.bazel @@ -104,7 +104,6 @@ java_jni_library( "//src/test:__subpackages__", ], deps = [ - "//src/main/java/com/code_intelligence/jazzer/driver:opt", "//src/main/java/com/code_intelligence/jazzer/utils:unsafe_provider", ], ) @@ -123,7 +122,7 @@ java_jni_library( srcs = ["FuzzTargetRunnerNatives.java"], visibility = ["//src/main/native/com/code_intelligence/jazzer/driver:__pkg__"], deps = [ - "//src/main/java/com/code_intelligence/jazzer/driver:opt", + ":constants", ], ) @@ -159,9 +158,17 @@ java_library( "//src/main/java/com/code_intelligence/jazzer/utils:unsafe_provider", ], deps = [ + ":constants", ":coverage_map", ":trace_data_flow_native_callbacks", "//src/main/java/com/code_intelligence/jazzer/api:hooks", - "//src/main/java/com/code_intelligence/jazzer/driver:opt", ], ) + +# This target exposes a class that can safely be loaded in both the system and the bootstrap class +# loader as it provides true constants that do not change over the lifetime of the JVM. +java_library( + name = "constants", + srcs = ["Constants.java"], + visibility = ["//visibility:public"], +) diff --git a/src/main/java/com/code_intelligence/jazzer/runtime/Constants.java b/src/main/java/com/code_intelligence/jazzer/runtime/Constants.java new file mode 100644 index 00000000..92f4a3ca --- /dev/null +++ b/src/main/java/com/code_intelligence/jazzer/runtime/Constants.java @@ -0,0 +1,21 @@ +/* + * Copyright 2023 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.runtime; + +public final class Constants { + public static final boolean IS_ANDROID = System.getProperty("java.vm.vendor").contains("Android"); +} diff --git a/src/main/java/com/code_intelligence/jazzer/runtime/FuzzTargetRunnerNatives.java b/src/main/java/com/code_intelligence/jazzer/runtime/FuzzTargetRunnerNatives.java index 2db68adf..bbf74fdb 100644 --- a/src/main/java/com/code_intelligence/jazzer/runtime/FuzzTargetRunnerNatives.java +++ b/src/main/java/com/code_intelligence/jazzer/runtime/FuzzTargetRunnerNatives.java @@ -14,7 +14,6 @@ package com.code_intelligence.jazzer.runtime; -import com.code_intelligence.jazzer.driver.Opt; import com.github.fmeum.rules_jni.RulesJni; /** @@ -26,7 +25,7 @@ import com.github.fmeum.rules_jni.RulesJni; */ public class FuzzTargetRunnerNatives { static { - if (!Opt.isAndroid && FuzzTargetRunnerNatives.class.getClassLoader() != null) { + if (!Constants.IS_ANDROID && FuzzTargetRunnerNatives.class.getClassLoader() != null) { throw new IllegalStateException( "FuzzTargetRunnerNatives must be loaded in the bootstrap loader"); } diff --git a/src/main/java/com/code_intelligence/jazzer/runtime/NativeLibHooks.java b/src/main/java/com/code_intelligence/jazzer/runtime/NativeLibHooks.java index 01573f45..8572f05a 100644 --- a/src/main/java/com/code_intelligence/jazzer/runtime/NativeLibHooks.java +++ b/src/main/java/com/code_intelligence/jazzer/runtime/NativeLibHooks.java @@ -16,7 +16,6 @@ package com.code_intelligence.jazzer.runtime; import com.code_intelligence.jazzer.api.HookType; import com.code_intelligence.jazzer.api.MethodHook; -import com.code_intelligence.jazzer.driver.Opt; import java.lang.invoke.MethodHandle; @SuppressWarnings("unused") @@ -31,7 +30,7 @@ final public class NativeLibHooks { targetMethodDescriptor = "(Ljava/lang/String;)V") public static void loadLibraryHook(MethodHandle method, Object thisObject, Object[] arguments, int hookId) { - if (Opt.isAndroid) { + if (Constants.IS_ANDROID) { return; } |