Skip to content

Commit d0638db

Browse files
committed
[Java] Add data flow through Iterator deserializers for Jackson
1 parent 56b1f15 commit d0638db

File tree

4 files changed

+104
-7
lines changed

4 files changed

+104
-7
lines changed

java/ql/src/semmle/code/java/frameworks/jackson/JacksonSerializability.qll

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ abstract class JacksonSerializableType extends Type { }
2828
* A method used for serializing objects using Jackson. The final parameter is the object to be
2929
* serialized.
3030
*/
31-
library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
31+
private class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
3232
JacksonWriteValueMethod() {
3333
(
3434
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectWriter") or
@@ -50,17 +50,17 @@ library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
5050
}
5151
}
5252

53-
library class JacksonReadValueMethod extends Method, TaintPreservingCallable {
53+
private class JacksonReadValueMethod extends Method, TaintPreservingCallable {
5454
JacksonReadValueMethod() {
5555
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectReader") and
56-
hasName("readValue")
56+
hasName(["readValue", "readValues"])
5757
}
5858

5959
override predicate returnsTaintFrom(int arg) { arg = 0 }
6060
}
6161

6262
/** A type whose values are explicitly serialized in a call to a Jackson method. */
63-
library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
63+
private class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
6464
ExplicitlyWrittenJacksonSerializableType() {
6565
exists(MethodAccess ma |
6666
// A call to a Jackson write method...
@@ -71,8 +71,20 @@ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializab
7171
}
7272
}
7373

74+
/** A type whose values are explicitly deserialized in a call to a Jackson method. */
75+
private class ExplicitlyReadJacksonSerializableType extends JacksonDeserializableType {
76+
ExplicitlyReadJacksonSerializableType() {
77+
exists(MethodAccess ma |
78+
// A call to a Jackson write method...
79+
ma.getMethod() instanceof JacksonReadValueMethod and
80+
// ...where `this` is used in the final argument, indicating that this type will be deserialized.
81+
usesType(ma.getArgument(ma.getNumArgument() - 1).getType(), this)
82+
)
83+
}
84+
}
85+
7486
/** A type used in a `JacksonSerializableField` declaration. */
75-
library class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
87+
private class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
7688
FieldReferencedJacksonSerializableType() {
7789
exists(JacksonSerializableField f | usesType(f.getType(), this))
7890
}
@@ -105,7 +117,7 @@ private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::C
105117
}
106118

107119
/** A type whose values are explicitly deserialized in a call to a Jackson method. */
108-
library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
120+
private class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
109121
ExplicitlyReadJacksonDeserializableType() {
110122
exists(TypeLiteralToJacksonDatabindFlowConfiguration conf |
111123
usesType(conf.getSourceWithFlowToJacksonDatabind().getTypeName().getType(), this)
@@ -114,7 +126,7 @@ library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializa
114126
}
115127

116128
/** A type used in a `JacksonDeserializableField` declaration. */
117-
library class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType {
129+
private class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType {
118130
FieldReferencedJacksonDeSerializableType() {
119131
exists(JacksonDeserializableField f | usesType(f.getType(), this))
120132
}
@@ -144,10 +156,15 @@ class JacksonDeserializableField extends DeserializableField {
144156
}
145157
}
146158

159+
/** A call to a field that may be deserialized using the Jackson JSON framework. */
147160
class JacksonDeserializableFieldAccess extends FieldAccess {
148161
JacksonDeserializableFieldAccess() { getField() instanceof JacksonDeserializableField }
149162
}
150163

164+
/**
165+
* When an object is deserialized by the Jackson JSON framework using a tainted input source,
166+
* the fields that the framework deserialized are themselves tainted input data.
167+
*/
151168
class JacksonDeseializedTaintStep extends AdditionalTaintStep {
152169
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
153170
node2.asExpr().(JacksonDeserializableFieldAccess).getQualifier() = node1.asExpr()

java/ql/test/library-tests/dataflow/taint-jackson/Test.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.OutputStream;
44
import java.io.StringWriter;
55
import java.io.Writer;
6+
import java.util.Iterator;
67

78
import com.fasterxml.jackson.core.JsonFactory;
89
import com.fasterxml.jackson.core.JsonGenerator;
@@ -79,4 +80,18 @@ public static void jacksonObjectReader() throws java.io.IOException {
7980
sink(reader.readValue(s, Potato.class).name); //$hasTaintFlow
8081
sink(reader.readValue(s, Potato.class).getName()); //$hasTaintFlow
8182
}
83+
84+
public static void jacksonObjectReaderIterable() throws java.io.IOException {
85+
String s = taint();
86+
ObjectMapper om = new ObjectMapper();
87+
ObjectReader reader = om.readerFor(Potato.class);
88+
sink(reader.readValues(s)); //$hasTaintFlow
89+
Iterator<Potato> pIterator = reader.readValues(s, Potato.class);
90+
while(pIterator.hasNext()) {
91+
Potato p = pIterator.next();
92+
sink(p); //$hasTaintFlow
93+
sink(p.name); //$hasTaintFlow
94+
sink(p.getName()); //$hasTaintFlow
95+
}
96+
}
8297
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.fasterxml.jackson.databind;
2+
3+
import java.io.Closeable;
4+
import java.io.IOException;
5+
import java.util.*;
6+
7+
public class MappingIterator<T> implements Iterator<T>, Closeable {
8+
9+
@Override
10+
public boolean hasNext() {
11+
return false;
12+
}
13+
14+
@Override
15+
public T next() {
16+
return null;
17+
}
18+
19+
@Override
20+
public void remove() {
21+
22+
}
23+
24+
@Override
25+
public void close() throws IOException {
26+
27+
}
28+
}

java/ql/test/stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectReader.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,41 @@ public <T> T readValue(Reader src) throws IOException {
4242
public <T> T readValue(Reader src, Class<T> valueType) throws IOException {
4343
return null;
4444
}
45+
46+
public <T> MappingIterator<T> readValues(String src) {
47+
return null;
48+
}
49+
50+
public <T> MappingIterator<T> readValues(String src, Class<T> valueType) throws IOException {
51+
return null;
52+
}
53+
54+
public <T> MappingIterator<T> readValues(byte[] content) throws IOException {
55+
return null;
56+
}
57+
58+
public <T> MappingIterator<T> readValues(byte[] content, Class<T> valueType) throws IOException {
59+
return null;
60+
}
61+
62+
public <T> MappingIterator<T> readValues(File src) throws IOException {
63+
return null;
64+
}
65+
66+
public <T> MappingIterator<T> readValues(InputStream src) throws IOException {
67+
return null;
68+
}
69+
70+
public <T> MappingIterator<T> readValues(InputStream src, Class<T> valueType) throws IOException {
71+
return null;
72+
}
73+
74+
public <T> MappingIterator<T> readValues(Reader src) throws IOException {
75+
return null;
76+
}
77+
78+
public <T> MappingIterator<T> readValues(Reader src, Class<T> valueType) throws IOException {
79+
return null;
80+
}
81+
4582
}

0 commit comments

Comments
 (0)