From f7cd9410c9025b2caf459ec38557eb562fe68536 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:08:25 +0100 Subject: [PATCH] jackson-databind: Improve fuzzers (#8807) 1. Add more target APIs 2. Group target types together 3. Add more settings Signed-off-by: AdamKorcz Signed-off-by: AdamKorcz --- .../AdaLObjectReader3Fuzzer.java | 479 +++++++++++++++--- .../jackson-databind/ObjectReader2Fuzzer.java | 76 ++- .../ObjectReaderRandomClassFuzzer.java | 67 +++ projects/jackson-databind/build.sh | 4 + 4 files changed, 549 insertions(+), 77 deletions(-) diff --git a/projects/jackson-databind/AdaLObjectReader3Fuzzer.java b/projects/jackson-databind/AdaLObjectReader3Fuzzer.java index 03d0f308d..a31062dce 100644 --- a/projects/jackson-databind/AdaLObjectReader3Fuzzer.java +++ b/projects/jackson-databind/AdaLObjectReader3Fuzzer.java @@ -20,20 +20,37 @@ import java.util.*; import java.util.regex.Pattern; import java.io.Reader; import java.io.StringReader; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.FileOutputStream; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.io.File; +import java.io.InputStream; +import java.io.DataInput; +import java.io.EOFException; import java.lang.IllegalArgumentException; import java.net.URI; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.core.filter.TokenFilter; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.JsonNode; +import java.lang.ClassCastException; + +// For NoCheckSubTypeValidator +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.cfg.MapperConfig; +import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; public class AdaLObjectReader3Fuzzer { public static void fuzzerTestOneInput(FuzzedDataProvider data) { @@ -47,6 +64,55 @@ public class AdaLObjectReader3Fuzzer { ObjectReader r, r2, r3; JsonParser jp; + MapperFeature[] mapperfeatures = new MapperFeature[]{MapperFeature.AUTO_DETECT_CREATORS, + MapperFeature.AUTO_DETECT_FIELDS, + MapperFeature.AUTO_DETECT_GETTERS, + MapperFeature.AUTO_DETECT_IS_GETTERS, + MapperFeature.AUTO_DETECT_SETTERS, + MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, + MapperFeature.USE_GETTERS_AS_SETTERS, + MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES, + MapperFeature.INFER_PROPERTY_MUTATORS, + MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, + MapperFeature.ALLOW_VOID_VALUED_PROPERTIES, + MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS, + MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS, + MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, + MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME, + MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, + MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, + MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, + MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES, + MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING, + MapperFeature.USE_STD_BEAN_NAMING, + MapperFeature.ALLOW_COERCION_OF_SCALARS, + MapperFeature.DEFAULT_VIEW_INCLUSION, + MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS, + MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE, + MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL, + MapperFeature.USE_STATIC_TYPING, + MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES}; + + SerializationFeature[] serializationfeatures = new SerializationFeature[]{SerializationFeature.INDENT_OUTPUT, + SerializationFeature.CLOSE_CLOSEABLE, + SerializationFeature.WRAP_ROOT_VALUE, + SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, + SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS, + SerializationFeature.WRITE_ENUMS_USING_TO_STRING, + SerializationFeature.WRITE_ENUMS_USING_INDEX, + SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, + SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN, + SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, + SerializationFeature.USE_EQUALITY_FOR_OBJECT_ID, + SerializationFeature.FAIL_ON_EMPTY_BEANS, + SerializationFeature.WRAP_EXCEPTIONS, + SerializationFeature.FLUSH_AFTER_WRITE_VALUE, + SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, + SerializationFeature.WRITE_NULL_MAP_VALUES, + SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, + SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, + SerializationFeature.EAGER_SERIALIZER_FETCH}; + DeserializationFeature[] deserializationfeatures = new DeserializationFeature[]{DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, @@ -73,9 +139,59 @@ public class AdaLObjectReader3Fuzzer { DeserializationFeature.FAIL_ON_TRAILING_TOKENS, DeserializationFeature.EAGER_DESERIALIZER_FETCH}; + ObjectMapper.DefaultTyping[] typings = new ObjectMapper.DefaultTyping[]{ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT, + ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, + ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS, + ObjectMapper.DefaultTyping.NON_FINAL, + ObjectMapper.DefaultTyping.EVERYTHING}; + ObjectMapper mapper = new ObjectMapper(); + + // Maybe create a mapper with different typing settings. Let the fuzzer decide + doThis = data.consumeBoolean(); + if (doThis) { + JsonMapper.Builder b = JsonMapper.builder(); + + for (int i = 0; i < typings.length; i++) { + if (data.consumeBoolean()) { + b.activateDefaultTyping(NoCheckSubTypeValidator.instance, typings[i]); + } + } + mapper = b.build(); + } + + for (int i = 0; i < mapperfeatures.length; i++) { + if (data.consumeBoolean()) { + mapper.enable(mapperfeatures[i]); + } else { + mapper.disable(mapperfeatures[i]); + } + } + + for (int i = 0; i < serializationfeatures.length; i++) { + if (data.consumeBoolean()) { + mapper.enable(serializationfeatures[i]); + } else { + mapper.disable(serializationfeatures[i]); + } + } + + int idx = data.consumeInt(0, classes.length - 1); - r = mapper.readerFor(classes[idx]); + r = mapper.readerFor(classes[idx]); // To initialize- + switch (data.consumeInt(0, 4)) { + case 0: + r = mapper.readerFor(classes[idx]); + case 1: + r = mapper.readerForMapOf(classes[idx]); + case 2: + r = mapper.readerForListOf(classes[idx]); + case 3: + r = mapper.readerForArrayOf(classes[idx]); + case 4: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + r = r.forType(mapper.constructType(classes[fuzzInt1])); + } // set reader settings for (int i = 0; i < deserializationfeatures.length; i++) { @@ -87,102 +203,214 @@ public class AdaLObjectReader3Fuzzer { } try { - for (int i = 0; i < data.consumeInt(); i++) { - // Select a method and call it - int callType = data.consumeInt(); - switch (callType%19) { + // Select a method and call it + int callType = data.consumeInt(); + switch (callType%7) { + case 0: + // readValue + switch (data.consumeInt(0, 12)){ case 0: r.readValue(data.consumeString(100000)); case 1: - r.readValue(data.consumeBytes(100000)); + r.readValue(new MockFuzzDataInput(data.consumeString(100000))); case 2: - r.readTree(data.consumeString(100000)); + r.readValue(data.consumeBytes(100000)); case 3: - r.readTree(data.consumeBytes(100000)); - case 4: - doThis = data.consumeBoolean(); - jp = r.createParser(data.consumeBytes(100000)); + jp = _createParser(data, mapper, r); o = r.readValue(jp); + doThis = data.consumeBoolean(); if (doThis) { r3 = r.withValueToUpdate(o); } + case 4: + jp = _createParser(data, mapper, r); + fuzzInt1 = data.consumeInt(0, classes.length - 1); + r.readValue(jp, mapper.constructType(classes[fuzzInt1])); case 5: - stringR = new StringReader(new String(data.consumeBytes(100000))); - r.readValue(stringR); + jp = _createParser(data, mapper, r); + fuzzInt1 = data.consumeInt(0, classes.length - 1); + r.readValue(jp, classes[fuzzInt1]); case 6: stringR = new StringReader(new String(data.consumeBytes(100000))); - r.readValues(stringR); + r.readValue(stringR); case 7: - r.readValues(data.consumeRemainingAsString()); - case 8: - r.readValue(data.consumeBytes(100000)); - case 9: - doThis = data.consumeBoolean(); - jp = r.createParser(data.consumeBytes(100000)); - o = r.readValues(jp); - if (doThis) { - r3 = r.withValueToUpdate(o); - } - case 10: - doThis = data.consumeBoolean(); - jp = r.createParser(data.consumeBytes(100000)); - o = r.readTree(jp); - if (doThis) { - r3 = r.withValueToUpdate(o); - } - case 11: - stringR = new StringReader(new String(data.consumeBytes(100000))); - r.readTree(stringR); - case 12: - fileData = data.consumeBytes(100000); + fileData = data.consumeRemainingAsBytes(); out = new FileOutputStream("fuzzFile"); out.write(fileData); out.close(); r.readValue(new File("fuzzFile")); + case 8: + fuzzInt1 = data.consumeInt(); + fuzzInt2 = data.consumeInt(); + r.readValue(data.consumeBytes(100000), fuzzInt1, fuzzInt2); + case 9: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + r.readValue(data.consumeBytes(100000), classes[idx]); + case 10: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + r.readValue(data.consumeString(100000), classes[idx]); + case 11: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.readValue(data.consumeBytes(1000000), data.consumeInt(), data.consumeInt(), classes[fuzzInt1]); + case 12: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.readValue(data.consumeBytes(1000000), mapper.constructType(classes[fuzzInt1])); case 13: - fileData = data.consumeBytes(100000); + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.readValue(data.consumeString(1000000), mapper.constructType(classes[fuzzInt1])); + } + case 1: + // readTree + switch (data.consumeInt(0, 6)){ + case 0: + jp = _createParser(data, mapper, r); + o = r.readTree(jp); + if (data.consumeBoolean()) { + r3 = r.withValueToUpdate(o); + } + case 1: + r.readTree(data.consumeString(100000)); + case 2: + r.readTree(data.consumeBytes(100000)); + case 3: + stringR = new StringReader(new String(data.consumeRemainingAsBytes())); + r.readTree(stringR); + case 4: + fuzzInt1 = data.consumeInt(); + fuzzInt2 = data.consumeInt(); + r.readTree(data.consumeRemainingAsBytes(), fuzzInt1, fuzzInt2); + case 5: + mapper.readTree(data.consumeBytes(1000000)); + case 6: + mapper.readTree(data.consumeString(1000000)); + case 7: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + switch (data.consumeInt(0,1)) { + case 0: + r.readValue(data.consumeRemainingAsBytes(), classes[fuzzInt1]); + case 1: + r.readValue(data.consumeRemainingAsString(), classes[fuzzInt1]); + } + } + case 2: + // readValues + switch (data.consumeInt(0, 7)){ + case 0: + stringR = new StringReader(new String(data.consumeRemainingAsBytes())); + r.readValues(stringR); + case 1: + r.readValues(data.consumeRemainingAsString()); + case 2: + doThis = data.consumeBoolean(); + jp = _createParser(data, mapper, r); + o = r.readValues(jp); + if (doThis) { + r3 = r.withValueToUpdate(o); + } + case 3: + fileData = data.consumeRemainingAsBytes(); out = new FileOutputStream("fuzzFile"); out.write(fileData); out.close(); r.readValues(new File("fuzzFile")); - case 14: - fileData = data.consumeBytes(100000); - out = new FileOutputStream("fuzzFile"); - out.write(fileData); - out.close(); - jp = r.createParser(new File("fuzzFile")); - o = r.readTree(jp); - case 15: + case 4: fuzzInt1 = data.consumeInt(); fuzzInt2 = data.consumeInt(); - r.readValue(data.consumeBytes(100000), fuzzInt1, fuzzInt2); - case 16: - fuzzInt1 = data.consumeInt(); - fuzzInt2 = data.consumeInt(); - r.readValues(data.consumeBytes(100000), fuzzInt1, fuzzInt2); - case 17: - fuzzInt1 = data.consumeInt(); - fuzzInt2 = data.consumeInt(); - r.readTree(data.consumeBytes(100000), fuzzInt1, fuzzInt2); - case 18: - fuzzInt1 = data.consumeInt(); - fuzzInt2 = data.consumeInt(); - jp = r.createParser(data.consumeBytes(100000), fuzzInt1, fuzzInt2); + r.readValues(data.consumeBytes(1000000), fuzzInt1, fuzzInt2); + case 5: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + jp = _createParser(data, mapper, r); + mapper.readValues(jp, mapper.constructType(classes[fuzzInt1])); + case 6: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + jp = _createParser(data, mapper, r); + mapper.readValues(jp, classes[fuzzInt1]); + case 7: + r.readValues(new MockFuzzDataInput(data.consumeString(1000000))); } - - // target with(); - if (data.consumeBoolean()) { - JsonFactory jf = new JsonFactory(); - r2 = r.with(jf); + case 3: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + fuzzInt2 = data.consumeInt(0, classes.length - 1); + mapper.addMixIn(classes[fuzzInt1], classes[fuzzInt2]); + case 4: + JsonNode tree = mapper.readTree(data.consumeString(1000000)); + JsonNode node = tree.at(data.consumeString(1000000)); + doThis = data.consumeBoolean(); + if (doThis) { + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.treeToValue(node, classes[fuzzInt1]); } + doThis = data.consumeBoolean(); + if (doThis) { + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.treeToValue(node, mapper.constructType(classes[fuzzInt1])); + } + doThis = data.consumeBoolean(); + if (doThis) { + r.readValue(node); + } + doThis = data.consumeBoolean(); + fuzzInt1 = data.consumeInt(0, classes.length - 1); + if (doThis) { + r.readValue(node, classes[fuzzInt1]); + } + case 5: + switch (data.consumeInt(0, 1)){ + case 0: + mapper.readTree(new ByteArrayInputStream(data.consumeBytes(100000))); + case 1: + ObjectNode src = (ObjectNode) mapper.readTree(data.consumeString(100000)); + TreeNode tn = src; + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.treeToValue(tn, classes[fuzzInt1]); + case 2: + r.readTree(new MockFuzzDataInput(data.consumeString(100000))); + } + case 6: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.canSerialize(classes[fuzzInt1]); } - } catch (IOException | IllegalArgumentException e) { } + + // target with(); + if (data.consumeBoolean()) { + JsonFactory jf = new JsonFactory(); + r2 = r.with(jf); + } + } catch (IOException | IllegalArgumentException | ClassCastException e) { } try { Files.delete(Paths.get("fuzzFile")); } catch (IOException e) { } } + public static JsonParser _createParser(FuzzedDataProvider data, ObjectMapper mapper, ObjectReader r) throws IOException { + int fuzzInt1, fuzzInt2; + byte[] fileData; + switch (data.consumeInt(0, 6)) { + case 0: + return r.createParser(data.consumeBytes(100000)); + case 1: + fileData = data.consumeBytes(100000); + FileOutputStream out = new FileOutputStream("fuzzFile"); + out.write(fileData); + out.close(); + return r.createParser(new File("fuzzFile")); + case 2: + fuzzInt1 = data.consumeInt(); + fuzzInt2 = data.consumeInt(); + return r.createParser(data.consumeBytes(100000), fuzzInt1, fuzzInt2); + case 3: + mapper.createParser(data.consumeBytes(100000)); + case 4: + return mapper.createParser(data.consumeString(1000000)); + case 5: + fuzzInt1 = data.consumeInt(); + fuzzInt2 = data.consumeInt(); + return mapper.createParser(data.consumeBytes(100000), fuzzInt1, fuzzInt2); + } + return r.createParser(data.consumeBytes(100000)); + } + public static Class[] classes = { DummyClass.class, Integer.class, String.class, Byte.class, List.class, Map.class, TreeMap.class, BitSet.class, TimeZone.class, Date.class, Calendar.class, Locale.class, Long.class }; @@ -215,4 +443,127 @@ public class AdaLObjectReader3Fuzzer { public Long _long; public Double _double; } + + + // Test util classes + public static final class NoCheckSubTypeValidator + extends PolymorphicTypeValidator.Base + { + private static final long serialVersionUID = 1L; + + public static final NoCheckSubTypeValidator instance = new NoCheckSubTypeValidator(); + + @Override + public Validity validateBaseType(MapperConfig config, JavaType baseType) { + return Validity.INDETERMINATE; + } + + @Override + public Validity validateSubClassName(MapperConfig config, + JavaType baseType, String subClassName) { + return Validity.ALLOWED; + } + + @Override + public Validity validateSubType(MapperConfig config, JavaType baseType, + JavaType subType) { + return Validity.ALLOWED; + } + } + + public static class MockFuzzDataInput implements DataInput + { + private final InputStream _input; + + public MockFuzzDataInput(byte[] data) { + _input = new ByteArrayInputStream(data); + } + + public MockFuzzDataInput(String utf8Data) throws IOException { + _input = new ByteArrayInputStream(utf8Data.getBytes("UTF-8")); + } + + public MockFuzzDataInput(InputStream in) { + _input = in; + } + + @Override + public void readFully(byte[] b) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void readFully(byte[] b, int off, int len) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public int skipBytes(int n) throws IOException { + return (int) _input.skip(n); + } + + @Override + public boolean readBoolean() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public byte readByte() throws IOException { + int ch = _input.read(); + if (ch < 0) { + throw new EOFException("End-of-input for readByte()"); + } + return (byte) ch; + } + + @Override + public int readUnsignedByte() throws IOException { + return readByte() & 0xFF; + } + + @Override + public short readShort() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public int readUnsignedShort() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public char readChar() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public int readInt() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public long readLong() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public float readFloat() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public double readDouble() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public String readLine() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public String readUTF() throws IOException { + throw new UnsupportedOperationException(); + } + } } diff --git a/projects/jackson-databind/ObjectReader2Fuzzer.java b/projects/jackson-databind/ObjectReader2Fuzzer.java index b96a80b97..db5338efe 100644 --- a/projects/jackson-databind/ObjectReader2Fuzzer.java +++ b/projects/jackson-databind/ObjectReader2Fuzzer.java @@ -74,7 +74,18 @@ public class ObjectReader2Fuzzer { ObjectMapper mapper = new ObjectMapper(); int idx = data.consumeInt(0, classes.length - 1); - r = mapper.readerFor(classes[idx]); + r = mapper.readerFor(classes[idx]); // To initialize + switch (data.consumeInt(0, 3)) { + case 0: + r = mapper.readerFor(classes[idx]); + case 1: + r = mapper.readerForMapOf(classes[idx]); + case 2: + r = mapper.readerForListOf(classes[idx]); + case 3: + r = mapper.readerForArrayOf(classes[idx]); + + } // set reader settings for (int i = 0; i < deserializationfeatures.length; i++) { @@ -88,7 +99,7 @@ public class ObjectReader2Fuzzer { try { // Select a method and call it int callType = data.consumeInt(); - switch (callType%19) { + switch (callType%23) { case 0: r.readValue(data.consumeRemainingAsString()); case 1: @@ -99,7 +110,7 @@ public class ObjectReader2Fuzzer { r.readTree(data.consumeRemainingAsBytes()); case 4: doThis = data.consumeBoolean(); - jp = r.createParser(data.consumeRemainingAsBytes()); + jp = _createParser(data, mapper, r); o = r.readValue(jp); if (doThis) { r3 = r.withValueToUpdate(o); @@ -116,14 +127,14 @@ public class ObjectReader2Fuzzer { r.readValue(data.consumeRemainingAsBytes()); case 9: doThis = data.consumeBoolean(); - jp = r.createParser(data.consumeRemainingAsBytes()); + jp = _createParser(data, mapper, r); o = r.readValues(jp); if (doThis) { r3 = r.withValueToUpdate(o); } case 10: doThis = data.consumeBoolean(); - jp = r.createParser(data.consumeRemainingAsBytes()); + jp = _createParser(data, mapper, r); o = r.readTree(jp); if (doThis) { r3 = r.withValueToUpdate(o); @@ -144,11 +155,7 @@ public class ObjectReader2Fuzzer { out.close(); r.readValues(new File("fuzzFile")); case 14: - fileData = data.consumeRemainingAsBytes(); - out = new FileOutputStream("fuzzFile"); - out.write(fileData); - out.close(); - jp = r.createParser(new File("fuzzFile")); + jp = _createParser(data, mapper, r); o = r.readTree(jp); case 15: fuzzInt1 = data.consumeInt(); @@ -163,9 +170,24 @@ public class ObjectReader2Fuzzer { fuzzInt2 = data.consumeInt(); r.readTree(data.consumeRemainingAsBytes(), fuzzInt1, fuzzInt2); case 18: - fuzzInt1 = data.consumeInt(); - fuzzInt2 = data.consumeInt(); - jp = r.createParser(data.consumeRemainingAsBytes(), fuzzInt1, fuzzInt2); + jp = _createParser(data, mapper, r); + case 19: + int idx2 = data.consumeInt(0, classes.length - 1); + switch (data.consumeInt()%4) { + case 0: + r.readValue(data.consumeRemainingAsBytes(), classes[idx]); + case 1: + r.readValue(data.consumeRemainingAsString(), classes[idx]); + } + case 20: + fuzzInt1 = data.consumeInt(0, classes.length - 1); + mapper.readValue(data.consumeBytes(1000000), data.consumeInt(), data.consumeInt(), classes[fuzzInt1]); + case 21: + int idx3 = data.consumeInt(0, classes.length - 1); + mapper.readValue(data.consumeBytes(1000000), mapper.constructType(classes[idx])); + case 22: + int idx4 = data.consumeInt(0, classes.length - 1); + mapper.readValue(data.consumeString(1000000), mapper.constructType(classes[idx])); } // target with(); @@ -180,6 +202,34 @@ public class ObjectReader2Fuzzer { } catch (IOException e) { } } + public static JsonParser _createParser(FuzzedDataProvider data, ObjectMapper mapper, ObjectReader r) throws IOException { + int fuzzInt1, fuzzInt2; + byte[] fileData; + switch (data.consumeInt(0, 5)) { + case 0: + return r.createParser(data.consumeBytes(100000)); + case 1: + fileData = data.consumeBytes(100000); + FileOutputStream out = new FileOutputStream("fuzzFile"); + out.write(fileData); + out.close(); + return r.createParser(new File("fuzzFile")); + case 2: + fuzzInt1 = data.consumeInt(); + fuzzInt2 = data.consumeInt(); + return r.createParser(data.consumeBytes(100000), fuzzInt1, fuzzInt2); + case 3: + mapper.createParser(data.consumeBytes(100000)); + case 4: + return mapper.createParser(data.consumeString(1000000)); + case 5: + fuzzInt1 = data.consumeInt(); + fuzzInt2 = data.consumeInt(); + return mapper.createParser(data.consumeBytes(100000), fuzzInt1, fuzzInt2); + } + return r.createParser(data.consumeBytes(100000)); + } + public static Class[] classes = { DummyClass.class, Integer.class, String.class, Byte.class, List.class, Map.class, TreeMap.class, BitSet.class, TimeZone.class, Date.class, Calendar.class, Locale.class, Long.class, File.class, Charset.class, URI.class }; diff --git a/projects/jackson-databind/ObjectReaderRandomClassFuzzer.java b/projects/jackson-databind/ObjectReaderRandomClassFuzzer.java index 07cab135c..0e78e9616 100644 --- a/projects/jackson-databind/ObjectReaderRandomClassFuzzer.java +++ b/projects/jackson-databind/ObjectReaderRandomClassFuzzer.java @@ -17,6 +17,8 @@ import com.code_intelligence.jazzer.api.FuzzedDataProvider; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.core.JsonFactory; @@ -63,6 +65,55 @@ public class ObjectReaderRandomClassFuzzer { return; } + MapperFeature[] mapperfeatures = new MapperFeature[]{MapperFeature.AUTO_DETECT_CREATORS, + MapperFeature.AUTO_DETECT_FIELDS, + MapperFeature.AUTO_DETECT_GETTERS, + MapperFeature.AUTO_DETECT_IS_GETTERS, + MapperFeature.AUTO_DETECT_SETTERS, + MapperFeature.REQUIRE_SETTERS_FOR_GETTERS, + MapperFeature.USE_GETTERS_AS_SETTERS, + MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES, + MapperFeature.INFER_PROPERTY_MUTATORS, + MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, + MapperFeature.ALLOW_VOID_VALUED_PROPERTIES, + MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS, + MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS, + MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, + MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME, + MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, + MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, + MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, + MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES, + MapperFeature.ALLOW_EXPLICIT_PROPERTY_RENAMING, + MapperFeature.USE_STD_BEAN_NAMING, + MapperFeature.ALLOW_COERCION_OF_SCALARS, + MapperFeature.DEFAULT_VIEW_INCLUSION, + MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS, + MapperFeature.IGNORE_MERGE_FOR_UNMERGEABLE, + MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL, + MapperFeature.USE_STATIC_TYPING, + MapperFeature.BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES}; + + SerializationFeature[] serializationfeatures = new SerializationFeature[]{SerializationFeature.INDENT_OUTPUT, + SerializationFeature.CLOSE_CLOSEABLE, + SerializationFeature.WRAP_ROOT_VALUE, + SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, + SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS, + SerializationFeature.WRITE_ENUMS_USING_TO_STRING, + SerializationFeature.WRITE_ENUMS_USING_INDEX, + SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, + SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN, + SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, + SerializationFeature.USE_EQUALITY_FOR_OBJECT_ID, + SerializationFeature.FAIL_ON_EMPTY_BEANS, + SerializationFeature.WRAP_EXCEPTIONS, + SerializationFeature.FLUSH_AFTER_WRITE_VALUE, + SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, + SerializationFeature.WRITE_NULL_MAP_VALUES, + SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, + SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, + SerializationFeature.EAGER_SERIALIZER_FETCH}; + DeserializationFeature[] deserializationfeatures = new DeserializationFeature[]{DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, @@ -105,6 +156,22 @@ public class ObjectReaderRandomClassFuzzer { ObjectMapper mapper = new ObjectMapper(); + for (int i = 0; i < mapperfeatures.length; i++) { + if (data.consumeBoolean()) { + mapper.enable(mapperfeatures[i]); + } else { + mapper.disable(mapperfeatures[i]); + } + } + + for (int i = 0; i < serializationfeatures.length; i++) { + if (data.consumeBoolean()) { + mapper.enable(serializationfeatures[i]); + } else { + mapper.disable(serializationfeatures[i]); + } + } + try { /////////////////////////// // Create a random class // diff --git a/projects/jackson-databind/build.sh b/projects/jackson-databind/build.sh index 466c477f5..9da50b1c2 100755 --- a/projects/jackson-databind/build.sh +++ b/projects/jackson-databind/build.sh @@ -63,6 +63,10 @@ for fuzzer in $(find $SRC -name '*Fuzzer.java'); do if [ "$fuzzer_basename" != "ObjectReaderRandomClassFuzzer" ]; then cp $SRC/$fuzzer_basename\$DummyClass.class $OUT/ fi + if [ "$fuzzer_basename" == "AdaLObjectReader3Fuzzer" ]; then + cp $SRC/$fuzzer_basename\$NoCheckSubTypeValidator.class $OUT/ + cp $SRC/$fuzzer_basename\$MockFuzzDataInput.class $OUT/ + fi # Create an execution wrapper that executes Jazzer with the correct arguments. echo "#!/bin/sh