From 5246e52be3bf4427791000355cbef86626b43eca Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Fri, 29 Jan 2021 16:20:19 +0100 Subject: Initial commit --- .../src/main/java/com/example/ExampleFuzzer.java | 40 ++++++++++++++ .../main/java/com/example/ExampleFuzzerHooks.java | 30 +++++++++++ .../java/com/example/ExampleFuzzerWithNative.java | 35 +++++++++++++ .../com/example/ExampleValueProfileFuzzer.java | 53 +++++++++++++++++++ .../src/main/java/com/example/FastJsonFuzzer.java | 32 ++++++++++++ .../java/com/example/GifImageParserFuzzer.java | 34 ++++++++++++ .../main/java/com/example/JacksonCborFuzzer.java | 36 +++++++++++++ .../java/com/example/JpegImageParserFuzzer.java | 33 ++++++++++++ .../main/java/com/example/JsonSanitizerFuzzer.java | 42 +++++++++++++++ .../java/com/example/TiffImageParserFuzzer.java | 33 ++++++++++++ .../src/main/java/com/example/TurboJpegFuzzer.java | 61 ++++++++++++++++++++++ 11 files changed, 429 insertions(+) create mode 100644 examples/src/main/java/com/example/ExampleFuzzer.java create mode 100644 examples/src/main/java/com/example/ExampleFuzzerHooks.java create mode 100644 examples/src/main/java/com/example/ExampleFuzzerWithNative.java create mode 100644 examples/src/main/java/com/example/ExampleValueProfileFuzzer.java create mode 100644 examples/src/main/java/com/example/FastJsonFuzzer.java create mode 100644 examples/src/main/java/com/example/GifImageParserFuzzer.java create mode 100644 examples/src/main/java/com/example/JacksonCborFuzzer.java create mode 100644 examples/src/main/java/com/example/JpegImageParserFuzzer.java create mode 100644 examples/src/main/java/com/example/JsonSanitizerFuzzer.java create mode 100644 examples/src/main/java/com/example/TiffImageParserFuzzer.java create mode 100644 examples/src/main/java/com/example/TurboJpegFuzzer.java (limited to 'examples/src/main/java/com/example') diff --git a/examples/src/main/java/com/example/ExampleFuzzer.java b/examples/src/main/java/com/example/ExampleFuzzer.java new file mode 100644 index 00000000..40dcb697 --- /dev/null +++ b/examples/src/main/java/com/example/ExampleFuzzer.java @@ -0,0 +1,40 @@ +// 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.FuzzedDataProvider; +import java.security.SecureRandom; + +public class ExampleFuzzer { + public static void fuzzerInitialize() { + // Optional initialization to be run before the first call to fuzzerTestOneInput. + } + + public static boolean fuzzerTestOneInput(FuzzedDataProvider data) { + String input = data.consumeRemainingAsString(); + // Without the hook in ExampleFuzzerHooks.java, the value of random would change on every + // invocation, making it almost impossible to guess for the fuzzer. + long random = new SecureRandom().nextLong(); + if (input.startsWith("magicstring" + random) && input.length() > 30 + && input.charAt(25) == 'C') { + mustNeverBeCalled(); + } + return false; + } + + private static void mustNeverBeCalled() { + throw new IllegalStateException("mustNeverBeCalled has been called"); + } +} diff --git a/examples/src/main/java/com/example/ExampleFuzzerHooks.java b/examples/src/main/java/com/example/ExampleFuzzerHooks.java new file mode 100644 index 00000000..41f16635 --- /dev/null +++ b/examples/src/main/java/com/example/ExampleFuzzerHooks.java @@ -0,0 +1,30 @@ +// 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.HookType; +import com.code_intelligence.jazzer.api.MethodHook; +import java.lang.invoke.MethodHandle; + +public class ExampleFuzzerHooks { + @MethodHook(type = HookType.REPLACE, targetClassName = "java.security.SecureRandom", + targetMethod = "nextLong", targetMethodDescriptor = "()J") + public static long + getRandomNumber(MethodHandle handle, Object thisObject, Object[] args, int hookId) { + return 4; // chosen by fair dice roll. + // guaranteed to be random. + // https://xkcd.com/221/ + } +} diff --git a/examples/src/main/java/com/example/ExampleFuzzerWithNative.java b/examples/src/main/java/com/example/ExampleFuzzerWithNative.java new file mode 100644 index 00000000..801e84ea --- /dev/null +++ b/examples/src/main/java/com/example/ExampleFuzzerWithNative.java @@ -0,0 +1,35 @@ +// 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.FuzzedDataProvider; + +public class ExampleFuzzerWithNative { + static { + System.loadLibrary("native"); + } + + public static boolean fuzzerTestOneInput(FuzzedDataProvider data) { + int val = data.consumeInt(); + String stringData = data.consumeRemainingAsString(); + if (val == 17759716 && stringData.length() > 10 && stringData.contains("jazzer")) { + // call native function which contains a crash + new ExampleFuzzerWithNative().parse(stringData); + } + return false; + } + + private native boolean parse(String bytes); +} \ No newline at end of file diff --git a/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java b/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java new file mode 100644 index 00000000..1eb55df0 --- /dev/null +++ b/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java @@ -0,0 +1,53 @@ +// 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.FuzzedDataProvider; +import java.util.Base64; + +public class ExampleValueProfileFuzzer { + private static String base64(byte[] input) { + return Base64.getEncoder().encodeToString(input); + } + + private static long insecureEncrypt(long input) { + long key = 0xefe4eb93215cb6b0L; + return input ^ key; + } + + public static boolean fuzzerTestOneInput(FuzzedDataProvider data) { + // Without -use_value_profile=1, the fuzzer gets stuck here as there is no direct correspondence + // between the input bytes and the compared string. With value profile, the fuzzer can guess the + // expected input byte by byte, which takes linear rather than exponential time. + if (base64(data.consumeBytes(6)).equals("SmF6emVy")) { + long[] plaintextBlocks = data.consumeLongs(2); + if (plaintextBlocks.length != 2) + return false; + if (insecureEncrypt(plaintextBlocks[0]) == 0x9fc48ee64d3dc090L) { + // Without --fake_pcs (enabled by default with -use_value_profile=1), the fuzzer would get + // stuck here as the value profile information for long comparisons would not be able to + // distinguish between this comparison and the one above. + if (insecureEncrypt(plaintextBlocks[1]) == 0x888a82ff483ad9c2L) { + mustNeverBeCalled(); + } + } + } + return false; + } + + private static void mustNeverBeCalled() { + throw new IllegalStateException("mustNeverBeCalled has been called"); + } +} diff --git a/examples/src/main/java/com/example/FastJsonFuzzer.java b/examples/src/main/java/com/example/FastJsonFuzzer.java new file mode 100644 index 00000000..5c203ffb --- /dev/null +++ b/examples/src/main/java/com/example/FastJsonFuzzer.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.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONException; +import com.code_intelligence.jazzer.api.FuzzedDataProvider; + +// Found the issues described in +// https://github.com/alibaba/fastjson/issues/3631 +public class FastJsonFuzzer { + public static boolean fuzzerTestOneInput(FuzzedDataProvider data) { + try { + JSON.parse(data.consumeRemainingAsString()); + } catch (JSONException e) { + return false; + } + return false; + } +} diff --git a/examples/src/main/java/com/example/GifImageParserFuzzer.java b/examples/src/main/java/com/example/GifImageParserFuzzer.java new file mode 100644 index 00000000..276bdb84 --- /dev/null +++ b/examples/src/main/java/com/example/GifImageParserFuzzer.java @@ -0,0 +1,34 @@ +// 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 java.io.IOException; +import java.util.HashMap; +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.common.bytesource.ByteSourceArray; +import org.apache.commons.imaging.formats.gif.GifImageParser; + +// Found https://issues.apache.org/jira/browse/IMAGING-277 and +// https://issues.apache.org/jira/browse/IMAGING-278. +public class GifImageParserFuzzer { + public static boolean fuzzerTestOneInput(byte[] input) { + try { + new GifImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>()); + } catch (IOException | ImageReadException e) { + return false; + } + return false; + } +} diff --git a/examples/src/main/java/com/example/JacksonCborFuzzer.java b/examples/src/main/java/com/example/JacksonCborFuzzer.java new file mode 100644 index 00000000..3d847751 --- /dev/null +++ b/examples/src/main/java/com/example/JacksonCborFuzzer.java @@ -0,0 +1,36 @@ +// 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.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.cbor.CBORFactory; +import java.io.IOException; + +// Reproduces https://github.com/FasterXML/jackson-dataformats-binary/issues/236 and +// https://github.com/FasterXML/jackson-databind/pull/3032 if executed with +// `--keep_going=3 -seed=2735196724`. +public class JacksonCborFuzzer { + public static boolean fuzzerTestOneInput(byte[] input) { + CBORFactory factory = new CBORFactory(); + ObjectMapper mapper = new ObjectMapper(factory); + mapper.enableDefaultTyping(); + try { + mapper.readTree(input); + } catch (IOException e) { + return false; + } + return false; + } +} diff --git a/examples/src/main/java/com/example/JpegImageParserFuzzer.java b/examples/src/main/java/com/example/JpegImageParserFuzzer.java new file mode 100644 index 00000000..4040daee --- /dev/null +++ b/examples/src/main/java/com/example/JpegImageParserFuzzer.java @@ -0,0 +1,33 @@ +// 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 java.io.IOException; +import java.util.HashMap; +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.common.bytesource.ByteSourceArray; +import org.apache.commons.imaging.formats.jpeg.JpegImageParser; + +// Found https://issues.apache.org/jira/browse/IMAGING-275. +public class JpegImageParserFuzzer { + public static boolean fuzzerTestOneInput(byte[] input) { + try { + new JpegImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>()); + } catch (IOException | ImageReadException e) { + return false; + } + return false; + } +} diff --git a/examples/src/main/java/com/example/JsonSanitizerFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerFuzzer.java new file mode 100644 index 00000000..ef13f369 --- /dev/null +++ b/examples/src/main/java/com/example/JsonSanitizerFuzzer.java @@ -0,0 +1,42 @@ +// 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.FuzzedDataProvider; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.json.JsonSanitizer; + +public class JsonSanitizerFuzzer { + public static boolean fuzzerTestOneInput(FuzzedDataProvider data) { + String input = data.consumeRemainingAsString(); + String validJson; + try { + validJson = JsonSanitizer.sanitize(input, 60); + } catch (ArrayIndexOutOfBoundsException e) { + // ArrayIndexOutOfBoundsException is expected if nesting depth is + // exceeded. + return false; + } + Gson gson = new Gson(); + gson.fromJson(validJson, JsonElement.class); + if (validJson.contains("") || validJson.contains("")) { + System.out.println(validJson); + return true; + } + return false; + } +} diff --git a/examples/src/main/java/com/example/TiffImageParserFuzzer.java b/examples/src/main/java/com/example/TiffImageParserFuzzer.java new file mode 100644 index 00000000..6dd127c2 --- /dev/null +++ b/examples/src/main/java/com/example/TiffImageParserFuzzer.java @@ -0,0 +1,33 @@ +// 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 java.io.IOException; +import java.util.HashMap; +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.common.bytesource.ByteSourceArray; +import org.apache.commons.imaging.formats.tiff.TiffImageParser; + +// Found https://issues.apache.org/jira/browse/IMAGING-276. +public class TiffImageParserFuzzer { + public static boolean fuzzerTestOneInput(byte[] input) { + try { + new TiffImageParser().getBufferedImage(new ByteSourceArray(input), new HashMap<>()); + } catch (IOException | ImageReadException e) { + return false; + } + return false; + } +} diff --git a/examples/src/main/java/com/example/TurboJpegFuzzer.java b/examples/src/main/java/com/example/TurboJpegFuzzer.java new file mode 100644 index 00000000..0a0059e4 --- /dev/null +++ b/examples/src/main/java/com/example/TurboJpegFuzzer.java @@ -0,0 +1,61 @@ +// 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.FuzzedDataProvider; +import org.libjpegturbo.turbojpeg.TJ; +import org.libjpegturbo.turbojpeg.TJDecompressor; +import org.libjpegturbo.turbojpeg.TJException; +import org.libjpegturbo.turbojpeg.TJTransform; +import org.libjpegturbo.turbojpeg.TJTransformer; + +public class TurboJpegFuzzer { + static byte[] buffer = new byte[128 * 128 * 4]; + + public static void fuzzerInitialize() throws TJException { + // Trigger an early load of the native library to show the coverage counters stats in libFuzzer. + new TJDecompressor(); + } + + public static boolean fuzzerTestOneInput(FuzzedDataProvider data) { + try { + int flagsDecompress = data.consumeInt(); + int flagsTransform = data.consumeInt(); + int pixelFormat = data.consumeInt(TJ.PF_RGB, TJ.PF_CMYK); + // Specify explicit small target width/height so that we can reuse a + // fixed-size buffer. + int desiredWidth = data.consumeInt(1, 128); + int desiredHeight = data.consumeInt(1, 128); + int transformOp = data.consumeInt(TJTransform.OP_NONE, TJTransform.OP_ROT270); + int transformOptions = data.consumeInt(); + int transformWidth = data.consumeBoolean() ? 128 : 64; + int transformHeight = data.consumeBoolean() ? 128 : 64; + TJDecompressor tjd; + if (data.consumeBoolean()) { + TJTransformer tjt = new TJTransformer(data.consumeRemainingAsBytes()); + TJTransform tjf = new TJTransform( + 0, 0, transformWidth, transformHeight, transformOp, transformOptions, null); + tjd = tjt.transform(new TJTransform[] {tjf}, flagsTransform)[0]; + } else { + tjd = new TJDecompressor(data.consumeRemainingAsBytes()); + } + tjd.decompress(buffer, 0, 0, desiredWidth, 0, desiredHeight, pixelFormat, flagsDecompress); + } catch (Exception e) { + // We are not looking for Java exceptions, but segfaults and ASan reports. + return false; + } + return false; + } +} -- cgit v1.2.3