diff options
Diffstat (limited to 'tests/src/test')
16 files changed, 692 insertions, 0 deletions
diff --git a/tests/src/test/java/com/example/AutofuzzInnerClassTarget.java b/tests/src/test/java/com/example/AutofuzzInnerClassTarget.java new file mode 100644 index 00000000..16240eff --- /dev/null +++ b/tests/src/test/java/com/example/AutofuzzInnerClassTarget.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; + +@SuppressWarnings("unused") +public class AutofuzzInnerClassTarget { + public static class Middle { + public static class Inner { + public void test(int a, int b) { + if (a == b) { + throw new FuzzerSecurityIssueLow("Finished Autofuzz Target"); + } + } + } + } +} diff --git a/tests/src/test/java/com/example/BytesMemoryLeakFuzzer.java b/tests/src/test/java/com/example/BytesMemoryLeakFuzzer.java new file mode 100644 index 00000000..95406316 --- /dev/null +++ b/tests/src/test/java/com/example/BytesMemoryLeakFuzzer.java @@ -0,0 +1,21 @@ +/* + * Copyright 2022 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.example; + +public class BytesMemoryLeakFuzzer { + public static void fuzzerTestOneInput(byte[] data) {} +} diff --git a/tests/src/test/java/com/example/CoverageFuzzer.java b/tests/src/test/java/com/example/CoverageFuzzer.java new file mode 100644 index 00000000..8f63639d --- /dev/null +++ b/tests/src/test/java/com/example/CoverageFuzzer.java @@ -0,0 +1,198 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; +import com.code_intelligence.jazzer.third_party.org.jacoco.core.data.ExecutionData; +import com.code_intelligence.jazzer.third_party.org.jacoco.core.data.ExecutionDataReader; +import com.code_intelligence.jazzer.third_party.org.jacoco.core.data.ExecutionDataStore; +import com.code_intelligence.jazzer.third_party.org.jacoco.core.data.SessionInfoStore; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * Test of coverage report and dump. + * + * Internally, JaCoCo is used to gather coverage information to guide the fuzzer to cover new + * branches. This information can be dumped in the JaCoCo format and used to generate reports later + * on. The dump only contains classes with at least one coverage data point. A JaCoCo report will + * also include completely uncovered files based on the available classes in the stated jar files + * in the report command. + * + * A human-readable coverage report can be generated directly by Jazzer. It contains information + * on file level about all classes that should have been instrumented according to the + * instrumentation_includes and instrumentation_exclude filters. + */ +@SuppressWarnings({"unused", "UnusedReturnValue"}) +public final class CoverageFuzzer { + // Not used during fuzz run, so not included in the dump + public static class ClassNotToCover { + private final int i; + public ClassNotToCover(int i) { + this.i = i; + } + public int getI() { + return i; + } + } + + // Used in the fuzz run and included in the dump + public static class ClassToCover { + private final int i; + + public ClassToCover(int i) { + if (i < 0 || i > 1000) { + throw new IllegalArgumentException(String.format("Invalid repeat number \"%d\"", i)); + } + this.i = i; + } + + public String repeat(String str) { + if (str != null && str.length() >= 3 && str.length() <= 10) { + return IntStream.range(0, i).mapToObj(i -> str).collect(Collectors.joining()); + } + throw new IllegalArgumentException(String.format("Invalid str \"%s\"", str)); + } + } + + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + try { + ClassToCover classToCover = new ClassToCover(data.consumeInt()); + String repeated = classToCover.repeat(data.consumeRemainingAsAsciiString()); + if (repeated.equals("foofoofoo")) { + throw new FuzzerSecurityIssueLow("Finished coverage fuzzer test"); + } + } catch (IllegalArgumentException ignored) { + } + } + + public static void fuzzerTearDown() throws IOException { + assertCoverageReport(); + assertCoverageDump(); + } + + private static void assertCoverageReport() throws IOException { + List<String> coverage = Files.readAllLines(Paths.get(System.getenv("COVERAGE_REPORT_FILE"))); + List<List<String>> sections = new ArrayList<>(4); + sections.add(new ArrayList<>()); + coverage.forEach(l -> { + if (l.isEmpty()) { + sections.add(new ArrayList<>()); + } else { + sections.get(sections.size() - 1).add(l); + } + }); + + List<String> branchCoverage = sections.get(0); + assertEquals(2, branchCoverage.size()); + List<String> lineCoverage = sections.get(1); + assertEquals(2, lineCoverage.size()); + List<String> incompleteCoverage = sections.get(2); + assertEquals(2, incompleteCoverage.size()); + List<String> missedCoverage = sections.get(3); + assertEquals(2, missedCoverage.size()); + + assertNotNull( + branchCoverage.stream() + .filter(l -> l.startsWith(CoverageFuzzer.class.getSimpleName())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Could not find branch coverage"))); + + assertNotNull( + lineCoverage.stream() + .filter(l -> l.startsWith(CoverageFuzzer.class.getSimpleName())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Could not find line coverage"))); + + assertNotNull( + incompleteCoverage.stream() + .filter(l -> l.startsWith(CoverageFuzzer.class.getSimpleName())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Could not find incomplete coverage"))); + + String missed = + missedCoverage.stream() + .filter(l -> l.startsWith(CoverageFuzzer.class.getSimpleName())) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Could not find missed coverage")); + List<String> missingLines = IntStream.rangeClosed(63, 79) + .mapToObj(i -> " " + i) + .filter(missed::contains) + .collect(Collectors.toList()); + if (!missingLines.isEmpty()) { + throw new IllegalStateException(String.format( + "Missing coverage for ClassToCover on lines %s", String.join(", ", missingLines))); + } + } + + private static void assertCoverageDump() throws IOException { + ExecutionDataStore executionDataStore = new ExecutionDataStore(); + SessionInfoStore sessionInfoStore = new SessionInfoStore(); + try (FileInputStream bais = new FileInputStream(System.getenv("COVERAGE_DUMP_FILE"))) { + ExecutionDataReader reader = new ExecutionDataReader(bais); + reader.setExecutionDataVisitor(executionDataStore); + reader.setSessionInfoVisitor(sessionInfoStore); + reader.read(); + } + assertEquals(2, executionDataStore.getContents().size()); + + ExecutionData coverageFuzzerCoverage = new ExecutionData(0, "", 0); + ExecutionData classToCoverCoverage = new ExecutionData(0, "", 0); + for (ExecutionData content : executionDataStore.getContents()) { + if (content.getName().endsWith("ClassToCover")) { + classToCoverCoverage = content; + } else { + coverageFuzzerCoverage = content; + } + } + + assertEquals("com/example/CoverageFuzzer", coverageFuzzerCoverage.getName()); + assertEquals(7, countHits(coverageFuzzerCoverage.getProbes())); + + assertEquals("com/example/CoverageFuzzer$ClassToCover", classToCoverCoverage.getName()); + assertEquals(11, countHits(classToCoverCoverage.getProbes())); + } + + private static int countHits(boolean[] probes) { + int count = 0; + for (boolean probe : probes) { + if (probe) + count++; + } + return count; + } + + private static <T> void assertEquals(T expected, T actual) { + if (!expected.equals(actual)) { + throw new IllegalStateException( + String.format("Expected \"%s\", got \"%s\"", expected, actual)); + } + } + + private static <T> void assertNotNull(T actual) { + if (actual == null) { + throw new IllegalStateException("Expected none null value, got null"); + } + } +} diff --git a/tests/src/test/java/com/example/DisabledHooksFuzzer.java b/tests/src/test/java/com/example/DisabledHooksFuzzer.java new file mode 100644 index 00000000..430bfa40 --- /dev/null +++ b/tests/src/test/java/com/example/DisabledHooksFuzzer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.HookType; +import com.code_intelligence.jazzer.api.Jazzer; +import com.code_intelligence.jazzer.api.MethodHook; +import java.lang.invoke.MethodHandle; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class DisabledHooksFuzzer { + public static void fuzzerTestOneInput(byte[] data) { + triggerCustomHook(); + triggerBuiltinHook(); + } + + private static void triggerCustomHook() {} + + private static void triggerBuiltinHook() { + // Trigger the built-in regex injection detector if it is enabled, but catch the exception + // thrown if it isn't. + try { + Pattern.compile("["); + } catch (PatternSyntaxException ignored) { + } + } +} + +class DisabledHook { + @MethodHook(type = HookType.BEFORE, targetClassName = "com.example.DisabledHooksFuzzer", + targetMethod = "triggerCustomHook", targetMethodDescriptor = "()V") + public static void + triggerCustomHookHook(MethodHandle method, Object thisObject, Object[] arguments, int hookId) { + Jazzer.reportFindingFromHook( + new IllegalStateException("hook on triggerCustomHook should have been disabled")); + } +} diff --git a/tests/src/test/java/com/example/ForkModeFuzzer.java b/tests/src/test/java/com/example/ForkModeFuzzer.java new file mode 100644 index 00000000..9f005124 --- /dev/null +++ b/tests/src/test/java/com/example/ForkModeFuzzer.java @@ -0,0 +1,48 @@ +// Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; + +public final class ForkModeFuzzer { + public static void fuzzerInitialize() { + // When running through a Java reproducer, do not check the Java opts. + if (System.getProperty("jazzer.is_reproducer") != null) + return; + String foo = System.getProperty("foo"); + String bar = System.getProperty("bar"); + String baz = System.getProperty("baz"); + // Only used to verify that arguments are correctly passed down to child processes. + if (foo == null || bar == null || baz == null || !foo.equals("foo") + || !(bar.equals("b;ar") || bar.equals("b:ar")) || !baz.equals("baz")) { + // Exit the process with an exit code different from that for a finding. + System.err.println("ERROR: Did not correctly pass all jvm_args to child process."); + System.err.printf("foo: %s%nbar: %s%nbaz: %s%n", foo, bar, baz); + System.exit(3); + } + // Only used to verify that Jazzer honors the JAVA_OPTS env var. + String javaOpts = System.getProperty("java_opts"); + if (javaOpts == null || !javaOpts.equals("1")) { + // Exit the process with an exit code different from that for a finding. + System.err.println("ERROR: Did not honor JAVA_OPTS."); + System.err.printf("java_opts: %s%n", javaOpts); + System.exit(4); + } + } + + public static void fuzzerTestOneInput(byte[] data) { + throw new FuzzerSecurityIssueLow("Passed fuzzerInitialize"); + } +} diff --git a/tests/src/test/java/com/example/HookDependenciesFuzzer.java b/tests/src/test/java/com/example/HookDependenciesFuzzer.java new file mode 100644 index 00000000..88627f4c --- /dev/null +++ b/tests/src/test/java/com/example/HookDependenciesFuzzer.java @@ -0,0 +1,68 @@ +// Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; +import com.code_intelligence.jazzer.api.HookType; +import com.code_intelligence.jazzer.api.MethodHook; +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.regex.Pattern; + +// This fuzzer verifies that: +// 1. a class referenced in a static initializer of a hook is still instrumented with the hook; +// 2. hooks that are not shipped in the Jazzer agent JAR can still instrument Java standard library +// classes. +public class HookDependenciesFuzzer { + private static final Field PATTERN_ROOT; + + static { + Field root; + try { + root = Pattern.class.getDeclaredField("root"); + } catch (NoSuchFieldException e) { + root = null; + } + PATTERN_ROOT = root; + } + + @MethodHook(type = HookType.AFTER, targetClassName = "java.util.regex.Matcher", + targetMethod = "matches", targetMethodDescriptor = "()Z", + additionalClassesToHook = {"java.util.regex.Pattern"}) + public static void + matcherMatchesHook(MethodHandle method, Object alwaysNull, Object[] alwaysEmpty, int hookId, + Boolean returnValue) { + if (PATTERN_ROOT != null) { + throw new FuzzerSecurityIssueLow("Hook applied even though it depends on the class to hook"); + } + } + + public static void fuzzerTestOneInput(byte[] data) { + try { + Pattern.matches("foobar", "foobar"); + } catch (Throwable t) { + if (t instanceof FuzzerSecurityIssueLow) { + throw t; + } else { + // Unexpected exception, exit without producing a finding to let the test fail due to the + // missing Java reproducer. + // FIXME(fabian): This is hacky and will result in false positives as soon as we implement + // Java reproducers for fuzz target exits. Replace this with a more reliable signal. + t.printStackTrace(); + System.exit(1); + } + } + } +} diff --git a/tests/src/test/java/com/example/JazzerApiFuzzer.java b/tests/src/test/java/com/example/JazzerApiFuzzer.java new file mode 100644 index 00000000..2428d21f --- /dev/null +++ b/tests/src/test/java/com/example/JazzerApiFuzzer.java @@ -0,0 +1,31 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; +import com.code_intelligence.jazzer.api.Jazzer; + +public class JazzerApiFuzzer { + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + Jazzer.exploreState(data.consumeByte(), 1); + Jazzer.guideTowardsEquality(data.consumeString(10), data.pickValue(new String[] {"foo"}), 1); + Jazzer.guideTowardsEquality(data.consumeBytes(10), new byte[] {}, 2); + Jazzer.guideTowardsContainment(data.consumeAsciiString(10), "bar", 2); + throw new FuzzerSecurityIssueLow("Jazzer API calls succeed"); + } +} diff --git a/tests/src/test/java/com/example/LongStringFuzzer.java b/tests/src/test/java/com/example/LongStringFuzzer.java new file mode 100644 index 00000000..324764d4 --- /dev/null +++ b/tests/src/test/java/com/example/LongStringFuzzer.java @@ -0,0 +1,32 @@ +// 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.example; + +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; + +/** + * Provoke a finding with huge captured data to verify that the generated crash reproducer is still + * compilable. This test uses a huge, predefined corpus to speed up finding the issue. + * <p> + * Reproduces issue #269 (<a + * href="https://github.com/CodeIntelligenceTesting/jazzer/issues/269">...</a>) + */ +public class LongStringFuzzer { + public static void fuzzerTestOneInput(byte[] data) { + if (data.length > 1024 * 64) { + throw new FuzzerSecurityIssueLow("String too long exception"); + } + } +} diff --git a/tests/src/test/java/com/example/LongStringFuzzerInput b/tests/src/test/java/com/example/LongStringFuzzerInput Binary files differnew file mode 100644 index 00000000..f18c9a67 --- /dev/null +++ b/tests/src/test/java/com/example/LongStringFuzzerInput diff --git a/tests/src/test/java/com/example/MemoryLeakFuzzer.java b/tests/src/test/java/com/example/MemoryLeakFuzzer.java new file mode 100644 index 00000000..9f38a1e2 --- /dev/null +++ b/tests/src/test/java/com/example/MemoryLeakFuzzer.java @@ -0,0 +1,26 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; + +public class MemoryLeakFuzzer { + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + throw new FuzzerSecurityIssueLow(); + } +} diff --git a/tests/src/test/java/com/example/NativeValueProfileFuzzer.java b/tests/src/test/java/com/example/NativeValueProfileFuzzer.java new file mode 100644 index 00000000..1085a953 --- /dev/null +++ b/tests/src/test/java/com/example/NativeValueProfileFuzzer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; +import com.github.fmeum.rules_jni.RulesJni; + +public class NativeValueProfileFuzzer { + public static void fuzzerInitialize() { + RulesJni.loadLibrary("native_value_profile_fuzzer", NativeValueProfileFuzzer.class); + } + + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + long[] blocks = data.consumeLongs(2); + if (blocks.length != 2) + return; + if (checkAccess(blocks[0], blocks[1])) { + throw new FuzzerSecurityIssueLow("Security breached"); + } + } + + private static native boolean checkAccess(long block1, long block2); +} diff --git a/tests/src/test/java/com/example/NoCoverageFuzzer.java b/tests/src/test/java/com/example/NoCoverageFuzzer.java new file mode 100644 index 00000000..a1f8b4ea --- /dev/null +++ b/tests/src/test/java/com/example/NoCoverageFuzzer.java @@ -0,0 +1,19 @@ +// Copyright 2022 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.example; + +public class NoCoverageFuzzer { + public static void fuzzerTestOneInput(byte[] data) {} +} diff --git a/tests/src/test/java/com/example/NoSeedFuzzer.java b/tests/src/test/java/com/example/NoSeedFuzzer.java new file mode 100644 index 00000000..bf1c1103 --- /dev/null +++ b/tests/src/test/java/com/example/NoSeedFuzzer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.Jazzer; + +public class NoSeedFuzzer { + public static void fuzzerInitialize() { + // Verify that the seed was randomly generated and not taken to be the fixed + // one set in FuzzTargetTestWrapper. This has a 1 / INT_MAX chance to be + // flaky, which is acceptable. + if (Jazzer.SEED == (int) 2735196724L) { + System.err.println( + "Jazzer.SEED should not equal the fixed seed set in FuzzTargetTestWrapper"); + System.exit(1); + } + } + + public static void fuzzerTestOneInput(byte[] data) {} +} diff --git a/tests/src/test/java/com/example/SeedFuzzer.java b/tests/src/test/java/com/example/SeedFuzzer.java new file mode 100644 index 00000000..4d1e4e8b --- /dev/null +++ b/tests/src/test/java/com/example/SeedFuzzer.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 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.example; + +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; +import com.code_intelligence.jazzer.api.Jazzer; + +public class SeedFuzzer { + public static void fuzzerInitialize() { + if (Jazzer.SEED != 1234567) { + throw new FuzzerSecurityIssueLow("Expected Jazzer.SEED to be 1234567, got " + Jazzer.SEED); + } + } + + public static void fuzzerTestOneInput(byte[] data) {} +} diff --git a/tests/src/test/native/com/example/BUILD.bazel b/tests/src/test/native/com/example/BUILD.bazel new file mode 100644 index 00000000..93b886a8 --- /dev/null +++ b/tests/src/test/native/com/example/BUILD.bazel @@ -0,0 +1,28 @@ +load("@fmeum_rules_jni//jni:defs.bzl", "cc_jni_library") + +cc_jni_library( + name = "native_value_profile_fuzzer", + srcs = ["native_value_profile_fuzzer.cpp"], + copts = [ + "-fsanitize=fuzzer-no-link,address", + "-fno-sanitize-blacklist", + ], + defines = [ + # Workaround for Windows build failures with VS 2022: + # "lld-link: error: /INFERASANLIBS is not allowed in .drectve" + # https://github.com/llvm/llvm-project/issues/56300#issuecomment-1214313292 + "_DISABLE_STRING_ANNOTATION=1", + "_DISABLE_VECTOR_ANNOTATION=1", + ], + linkopts = select({ + "//:clang_on_linux": ["-fuse-ld=lld"], + "@platforms//os:windows": [ + # Windows requires all symbols that should be imported from the main + # executable to be defined by an import lib. + "/wholearchive:clang_rt.asan_dll_thunk-x86_64.lib", + ], + "//conditions:default": [], + }), + visibility = ["//tests:__pkg__"], + deps = ["//tests:native_value_profile_fuzzer.hdrs"], +) diff --git a/tests/src/test/native/com/example/native_value_profile_fuzzer.cpp b/tests/src/test/native/com/example/native_value_profile_fuzzer.cpp new file mode 100644 index 00000000..2edcc269 --- /dev/null +++ b/tests/src/test/native/com/example/native_value_profile_fuzzer.cpp @@ -0,0 +1,35 @@ +// Copyright 2022 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. + +#include <cstdint> +#include <cstring> + +#include "com_example_NativeValueProfileFuzzer.h" + +// Prevent the compiler from inlining the secret all the way into checkAccess, +// which would make it trivial for the fuzzer to pass the checks. +volatile uint64_t secret = 0xefe4eb93215cb6b0L; + +static uint64_t insecureEncrypt(uint64_t input) { return input ^ secret; } + +jboolean Java_com_example_NativeValueProfileFuzzer_checkAccess(JNIEnv *, jclass, + jlong block1, + jlong block2) { + if (insecureEncrypt(block1) == 0x9fc48ee64d3dc090L) { + if (insecureEncrypt(block2) == 0x888a82ff483ad9c2L) { + return true; + } + } + return false; +} |