Skip to content

Commit 8f89d74

Browse files
Add spring tests
1 parent 4be7e94 commit 8f89d74

File tree

5 files changed

+118
-16
lines changed

5 files changed

+118
-16
lines changed

java/ql/src/semmle/code/java/frameworks/spring/SpringHttp.qll

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,22 +78,22 @@ private class SpringHttpFlowStep extends SinkModelCsv {
7878
"org.springframework.http;ResponseEntity;true;of;(Optional<T>);;Argument[0];ReturnValue;taint",
7979
"org.springframework.http;ResponseEntity;true;ok;(T);;Argument[0];ReturnValue;taint",
8080
"org.springframework.http;ResponseEntity;true;created;(URI);;Argument[0];ReturnValue;taint",
81-
"org.springframework.http;ResponseEntity$BodyBuilder;true;contentLength;(long);;Argument[-1];ReturnValue;value",
82-
"org.springframework.http;ResponseEntity$BodyBuilder;true;contentType;(MediaType);;Argument[-1];ReturnValue;value",
83-
"org.springframework.http;ResponseEntity$BodyBuilder;true;body;(T);;Argument[-1..0];ReturnValue;taint",
84-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;allow;(HttpMethod[]);;Argument[-1];ReturnValue;value",
85-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;eTag;(String);;Argument[-1];ReturnValue;value",
86-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;eTag;(String);;Argument[0];Argument[-1];taint",
87-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;header;(String,String[]);;Argument[-1];ReturnValue;value",
88-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;header;(String,String[]);;Argument[0..1];Argument[-1];taint",
89-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;headers;(Consumer<HttpHeader>);;Argument[-1];ReturnValue;value",
90-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;headers;(HttpHeaders);;Argument[-1];ReturnValue;value",
91-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;headers;(HttpHeaders);;Argument[0];Argument[-1];taint",
92-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;lastModified;;;Argument[-1];ReturnValue;value",
93-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;location;(URI);;Argument[-1];ReturnValue;value",
94-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;location;(URI);;Argument[0];Argument[-1];taint",
95-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;varyBy;(String[]);;Argument[-1];ReturnValue;value",
96-
"org.springframework.http;ResponseEntity$HeadersBuilder;true;build;();;Argument[-1];ReturnValue;taint",
81+
"org.springframework.http;ResponseEntity<>$BodyBuilder;true;contentLength;(long);;Argument[-1];ReturnValue;value",
82+
"org.springframework.http;ResponseEntity<>$BodyBuilder;true;contentType;(MediaType);;Argument[-1];ReturnValue;value",
83+
"org.springframework.http;ResponseEntity<>$BodyBuilder;true;body;(T);;Argument[-1..0];ReturnValue;taint",
84+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;allow;(HttpMethod[]);;Argument[-1];ReturnValue;value",
85+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;eTag;(String);;Argument[-1];ReturnValue;value",
86+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;eTag;(String);;Argument[0];Argument[-1];taint",
87+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;header;(String,String[]);;Argument[-1];ReturnValue;value",
88+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;header;(String,String[]);;Argument[0..1];Argument[-1];taint",
89+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;headers;(Consumer<HttpHeader>);;Argument[-1];ReturnValue;value",
90+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;headers;(HttpHeaders);;Argument[-1];ReturnValue;value",
91+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;headers;(HttpHeaders);;Argument[0];Argument[-1];taint",
92+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;lastModified;;;Argument[-1];ReturnValue;value",
93+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;location;(URI);;Argument[-1];ReturnValue;value",
94+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;location;(URI);;Argument[0];Argument[-1];taint",
95+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;varyBy;(String[]);;Argument[-1];ReturnValue;value",
96+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;build;();;Argument[-1];ReturnValue;taint",
9797
"org.springframework.http;RequestEntity;true;getUrl;();;Argument[-1];ReturnValue;taint",
9898
"org.springframework.http;HttpHeaders;true;get;(Object);;Argument[-1];ReturnValue;taint", // Returns List<String>
9999
"org.springframework.http;HttpHeaders;true;getAccessControlAllowHeaders;();;Argument[-1];ReturnValue;taint", // Returns List<String>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import org.springframework.http.HttpEntity;
2+
import org.springframework.http.ResponseEntity;
3+
import org.springframework.http.RequestEntity;
4+
import org.springframework.http.HttpHeaders;
5+
import org.springframework.util.MultiValueMap;
6+
import org.springframework.util.LinkedMultiValueMap;
7+
import java.util.Optional;
8+
9+
class TestHttp {
10+
static <T> T taint() { return null; }
11+
static void sink(Object o) {}
12+
13+
void test1() {
14+
String x = taint();
15+
sink(new HttpEntity(x)); // $hasTaintFlow
16+
17+
MultiValueMap<String,String> m = new LinkedMultiValueMap();
18+
sink(new HttpEntity(x, m)); // $hasTaintFlow
19+
20+
m.add("a", taint());
21+
sink(new HttpEntity("a", m)); // $ MISSING:hasTaintFlow
22+
sink(new HttpEntity<String>(m)); // $ MISSING:hasTaintFlow
23+
24+
HttpEntity<String> ent = taint();
25+
sink(ent.getBody()); // $hasTaintFlow
26+
sink(ent.getHeaders()); // $hasTaintFlow
27+
28+
RequestEntity<String> req = taint();
29+
sink(req.getUrl()); // $hasTaintFlow
30+
}
31+
32+
void test2() {
33+
String x = taint();
34+
sink(ResponseEntity.ok(x)); // $hasTaintFlow
35+
sink(ResponseEntity.of(Optional.of(x))); // $ MISSING:hasTaintFlow
36+
37+
sink(ResponseEntity.status(200).contentLength(2048).body(x)); // $hasTaintFlow
38+
sink(ResponseEntity.created(taint()).contentType(null).body("a")); // $hasTaintFlow
39+
sink(ResponseEntity.status(200).header(x, "a", "b", "c").build()); // $hasTaintFlow
40+
sink(ResponseEntity.status(200).header("h", "a", "b", x).build()); // $hasTaintFlow
41+
HttpHeaders h = new HttpHeaders();
42+
h.add("h", taint());
43+
sink(ResponseEntity.status(200).headers(h).allow().build()); // $hasTaintFlow
44+
sink(ResponseEntity.status(200).eTag(x).allow().build()); // $hasTaintFlow
45+
sink(ResponseEntity.status(200).location(taint()).lastModified(10000000).build()); // $hasTaintFlow
46+
sink(ResponseEntity.status(200).varyBy(x).build());
47+
}
48+
}

java/ql/test/library-tests/frameworks/spring/flow.expected

Whitespace-only changes.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import java
2+
import semmle.code.java.frameworks.spring.Spring
3+
import semmle.code.java.dataflow.TaintTracking
4+
import TestUtilities.InlineExpectationsTest
5+
6+
class TaintFlowConf extends TaintTracking::Configuration {
7+
TaintFlowConf() { this = "qltest:frameworks:spring-taint-flow" }
8+
9+
override predicate isSource(DataFlow::Node n) {
10+
exists(string name | name.matches("taint%") |
11+
n.asExpr().(MethodAccess).getMethod().hasName(name)
12+
)
13+
}
14+
15+
override predicate isSink(DataFlow::Node n) {
16+
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
17+
}
18+
}
19+
20+
class ValueFlowConf extends DataFlow::Configuration {
21+
ValueFlowConf() { this = "qltest:frameworks:spring-value-flow" }
22+
23+
override predicate isSource(DataFlow::Node n) {
24+
n.asExpr().(MethodAccess).getMethod().hasName("taint")
25+
}
26+
27+
override predicate isSink(DataFlow::Node n) {
28+
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
29+
}
30+
}
31+
32+
class HasFlowTest extends InlineExpectationsTest {
33+
HasFlowTest() { this = "HasFlowTest" }
34+
35+
override string getARelevantTag() { result = ["hasTaintFlow", "hasValueFlow"] }
36+
37+
override predicate hasActualResult(Location location, string element, string tag, string value) {
38+
tag = "hasTaintFlow" and
39+
exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf | conf.hasFlow(src, sink) |
40+
not any(ValueFlowConf vconf).hasFlow(src, sink) and
41+
sink.getLocation() = location and
42+
element = sink.toString() and
43+
value = ""
44+
)
45+
or
46+
tag = "hasValueFlow" and
47+
exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
48+
sink.getLocation() = location and
49+
element = sink.toString() and
50+
value = ""
51+
)
52+
}
53+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3

0 commit comments

Comments
 (0)