mirror of
https://github.com/github/codeql.git
synced 2026-05-01 19:55:15 +02:00
[Java] Add data flow through Iterator deserializers for Jackson
This commit is contained in:
@@ -28,7 +28,7 @@ abstract class JacksonSerializableType extends Type { }
|
||||
* A method used for serializing objects using Jackson. The final parameter is the object to be
|
||||
* serialized.
|
||||
*/
|
||||
library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
|
||||
private class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
|
||||
JacksonWriteValueMethod() {
|
||||
(
|
||||
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectWriter") or
|
||||
@@ -50,17 +50,17 @@ library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
|
||||
}
|
||||
}
|
||||
|
||||
library class JacksonReadValueMethod extends Method, TaintPreservingCallable {
|
||||
private class JacksonReadValueMethod extends Method, TaintPreservingCallable {
|
||||
JacksonReadValueMethod() {
|
||||
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectReader") and
|
||||
hasName("readValue")
|
||||
hasName(["readValue", "readValues"])
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = 0 }
|
||||
}
|
||||
|
||||
/** A type whose values are explicitly serialized in a call to a Jackson method. */
|
||||
library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
|
||||
private class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
|
||||
ExplicitlyWrittenJacksonSerializableType() {
|
||||
exists(MethodAccess ma |
|
||||
// A call to a Jackson write method...
|
||||
@@ -71,8 +71,20 @@ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializab
|
||||
}
|
||||
}
|
||||
|
||||
/** A type whose values are explicitly deserialized in a call to a Jackson method. */
|
||||
private class ExplicitlyReadJacksonSerializableType extends JacksonDeserializableType {
|
||||
ExplicitlyReadJacksonSerializableType() {
|
||||
exists(MethodAccess ma |
|
||||
// A call to a Jackson write method...
|
||||
ma.getMethod() instanceof JacksonReadValueMethod and
|
||||
// ...where `this` is used in the final argument, indicating that this type will be deserialized.
|
||||
usesType(ma.getArgument(ma.getNumArgument() - 1).getType(), this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A type used in a `JacksonSerializableField` declaration. */
|
||||
library class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
|
||||
private class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
|
||||
FieldReferencedJacksonSerializableType() {
|
||||
exists(JacksonSerializableField f | usesType(f.getType(), this))
|
||||
}
|
||||
@@ -105,7 +117,7 @@ private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::C
|
||||
}
|
||||
|
||||
/** A type whose values are explicitly deserialized in a call to a Jackson method. */
|
||||
library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
|
||||
private class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
|
||||
ExplicitlyReadJacksonDeserializableType() {
|
||||
exists(TypeLiteralToJacksonDatabindFlowConfiguration conf |
|
||||
usesType(conf.getSourceWithFlowToJacksonDatabind().getTypeName().getType(), this)
|
||||
@@ -114,7 +126,7 @@ library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializa
|
||||
}
|
||||
|
||||
/** A type used in a `JacksonDeserializableField` declaration. */
|
||||
library class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType {
|
||||
private class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType {
|
||||
FieldReferencedJacksonDeSerializableType() {
|
||||
exists(JacksonDeserializableField f | usesType(f.getType(), this))
|
||||
}
|
||||
@@ -144,10 +156,15 @@ class JacksonDeserializableField extends DeserializableField {
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to a field that may be deserialized using the Jackson JSON framework. */
|
||||
class JacksonDeserializableFieldAccess extends FieldAccess {
|
||||
JacksonDeserializableFieldAccess() { getField() instanceof JacksonDeserializableField }
|
||||
}
|
||||
|
||||
/**
|
||||
* When an object is deserialized by the Jackson JSON framework using a tainted input source,
|
||||
* the fields that the framework deserialized are themselves tainted input data.
|
||||
*/
|
||||
class JacksonDeseializedTaintStep extends AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node2.asExpr().(JacksonDeserializableFieldAccess).getQualifier() = node1.asExpr()
|
||||
|
||||
@@ -3,6 +3,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
@@ -79,4 +80,18 @@ class Test {
|
||||
sink(reader.readValue(s, Potato.class).name); //$hasTaintFlow
|
||||
sink(reader.readValue(s, Potato.class).getName()); //$hasTaintFlow
|
||||
}
|
||||
|
||||
public static void jacksonObjectReaderIterable() throws java.io.IOException {
|
||||
String s = taint();
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
ObjectReader reader = om.readerFor(Potato.class);
|
||||
sink(reader.readValues(s)); //$hasTaintFlow
|
||||
Iterator<Potato> pIterator = reader.readValues(s, Potato.class);
|
||||
while(pIterator.hasNext()) {
|
||||
Potato p = pIterator.next();
|
||||
sink(p); //$hasTaintFlow
|
||||
sink(p.name); //$hasTaintFlow
|
||||
sink(p.getName()); //$hasTaintFlow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class MappingIterator<T> implements Iterator<T>, Closeable {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -42,4 +42,41 @@ public class ObjectReader {
|
||||
public <T> T readValue(Reader src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(String src) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(String src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(byte[] content) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(byte[] content, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(File src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(InputStream src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(InputStream src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(Reader src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(Reader src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user