Skip to content

Commit df74a14

Browse files
Update for collection flow and add more tests
1 parent 8f89d74 commit df74a14

File tree

2 files changed

+161
-28
lines changed

2 files changed

+161
-28
lines changed

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

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,36 @@ private class SpringHttpFlowStep extends SinkModelCsv {
6767
row =
6868
[
6969
//"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
70-
"org.springframework.http;HttpEntity;true;HttpEntity;(T);;Argument[0];Argument[-1];taint",
71-
"org.springframework.http;HttpEntity;true;HttpEntity;(T,MultiValueMap<String,String>);;Argument[0];Argument[-1];taint",
72-
// Constructor with signature (MultiValueMap<String,String>) dependant on collection flow
70+
"org.springframework.http;HttpEntity;true;HttpEntity;(Object);;Argument[0];Argument[-1];taint",
71+
"org.springframework.http;HttpEntity;true;HttpEntity;(Object,MultiValueMap);;Argument[0];Argument[-1];taint",
72+
"org.springframework.http;HttpEntity;true;HttpEntity;(Object,MultiValueMap);;MapKey of Argument[1];Argument[-1];taint",
73+
"org.springframework.http;HttpEntity;true;HttpEntity;(Object,MultiValueMap);;Element of MapValue of Argument[1];Argument[-1];taint",
74+
"org.springframework.http;HttpEntity;true;HttpEntity;(MultiValueMap);;MapKey of Argument[0];Argument[-1];taint",
75+
"org.springframework.http;HttpEntity;true;HttpEntity;(MultiValueMap);;Element of MapValue of Argument[0];Argument[-1];taint",
7376
"org.springframework.http;HttpEntity;true;getBody;;;Argument[-1];ReturnValue;taint",
7477
"org.springframework.http;HttpEntity;true;getHeaders;;;Argument[-1];ReturnValue;taint",
75-
"org.springframework.http;ResponseEntity;true;ResponseEntity;(T,HttpStatus);;Argument[0];Argument[-1];taint",
76-
"org.springframework.http;ResponseEntity;true;ResponseEntity;(T,MultiValueMap<String,String>,HttpStatus);;Argument[0];Argument[-1];taint",
77-
"org.springframework.http;ResponseEntity;true;ResponseEntity;(T,MultiValueMap<String,String>,int);;Argument[0];Argument[-1];taint",
78-
"org.springframework.http;ResponseEntity;true;of;(Optional<T>);;Argument[0];ReturnValue;taint",
79-
"org.springframework.http;ResponseEntity;true;ok;(T);;Argument[0];ReturnValue;taint",
78+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(Object,HttpStatus);;Argument[0];Argument[-1];taint",
79+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(Object,MultiValueMap,HttpStatus);;Argument[0];Argument[-1];taint",
80+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(Object,MultiValueMap,HttpStatus);;MapKey of Argument[1];Argument[-1];taint",
81+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(Object,MultiValueMap,HttpStatus);;Element of MapValue of Argument[1];Argument[-1];taint",
82+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(MultiValueMap,HttpStatus);;MapKey of Argument[0];Argument[-1];taint",
83+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(MultiValueMap,HttpStatus);;Element of MapValue of Argument[0];Argument[-1];taint",
84+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(Object,MultiValueMap,int);;Argument[0];Argument[-1];taint",
85+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(Object,MultiValueMap,int);;MapKey of Argument[1];Argument[-1];taint",
86+
"org.springframework.http;ResponseEntity;true;ResponseEntity;(Object,MultiValueMap,int);;Element of MapValue of Argument[1];Argument[-1];taint",
87+
"org.springframework.http;ResponseEntity;true;of;(Optional);;Argument[0];ReturnValue;taint",
88+
"org.springframework.http;ResponseEntity;true;ok;(Object);;Argument[0];ReturnValue;taint",
8089
"org.springframework.http;ResponseEntity;true;created;(URI);;Argument[0];ReturnValue;taint",
8190
"org.springframework.http;ResponseEntity<>$BodyBuilder;true;contentLength;(long);;Argument[-1];ReturnValue;value",
8291
"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",
92+
"org.springframework.http;ResponseEntity<>$BodyBuilder;true;body;(Object);;Argument[-1..0];ReturnValue;taint",
8493
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;allow;(HttpMethod[]);;Argument[-1];ReturnValue;value",
8594
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;eTag;(String);;Argument[-1];ReturnValue;value",
8695
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;eTag;(String);;Argument[0];Argument[-1];taint",
8796
"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",
97+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;header;(String,String[]);;Argument[0];Argument[-1];taint",
98+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;header;(String,String[]);;ArrayElement of Argument[1];Argument[-1];taint",
99+
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;headers;(Consumer);;Argument[-1];ReturnValue;value",
90100
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;headers;(HttpHeaders);;Argument[-1];ReturnValue;value",
91101
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;headers;(HttpHeaders);;Argument[0];Argument[-1];taint",
92102
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;lastModified;;;Argument[-1];ReturnValue;value",
@@ -95,29 +105,38 @@ private class SpringHttpFlowStep extends SinkModelCsv {
95105
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;varyBy;(String[]);;Argument[-1];ReturnValue;value",
96106
"org.springframework.http;ResponseEntity<>$HeadersBuilder;true;build;();;Argument[-1];ReturnValue;taint",
97107
"org.springframework.http;RequestEntity;true;getUrl;();;Argument[-1];ReturnValue;taint",
98-
"org.springframework.http;HttpHeaders;true;get;(Object);;Argument[-1];ReturnValue;taint", // Returns List<String>
99-
"org.springframework.http;HttpHeaders;true;getAccessControlAllowHeaders;();;Argument[-1];ReturnValue;taint", // Returns List<String>
108+
"org.springframework.http;HttpHeaders;true;HttpHeaders;(MultiValueMap);;MapKey of Argument[0];Argument[-1];taint",
109+
"org.springframework.http;HttpHeaders;true;HttpHeaders;(MultiValueMap);;Element of MapValue of Argument[0];Argument[-1];taint",
110+
"org.springframework.http;HttpHeaders;true;get;(Object);;Argument[-1];Element of ReturnValue;taint",
111+
"org.springframework.http;HttpHeaders;true;getAccessControlAllowHeaders;();;Argument[-1];Element of ReturnValue;taint",
100112
"org.springframework.http;HttpHeaders;true;getAccessControlAllowOrigin;();;Argument[-1];ReturnValue;taint",
101-
"org.springframework.http;HttpHeaders;true;getAccessControlExposeHeaders;();;Argument[-1];ReturnValue;taint", // Returns List<String>
102-
"org.springframework.http;HttpHeaders;true;getAccessControlRequestHeaders;();;Argument[-1];ReturnValue;taint", // Returns List<String>
113+
"org.springframework.http;HttpHeaders;true;getAccessControlExposeHeaders;();;Argument[-1];Element of ReturnValue;taint",
114+
"org.springframework.http;HttpHeaders;true;getAccessControlRequestHeaders;();;Argument[-1];Element of ReturnValue;taint",
103115
"org.springframework.http;HttpHeaders;true;getCacheControl;();;Argument[-1];ReturnValue;taint",
104-
"org.springframework.http;HttpHeaders;true;getConnection;();;Argument[-1];ReturnValue;taint", // Returns List<String>
116+
"org.springframework.http;HttpHeaders;true;getConnection;();;Argument[-1];Element of ReturnValue;taint",
105117
"org.springframework.http;HttpHeaders;true;getETag;();;Argument[-1];ReturnValue;taint",
106-
"org.springframework.http;HttpHeaders;true;getETagValuesAsList;(String);;Argument[-1];ReturnValue;taint", // Returns List<String>
118+
"org.springframework.http;HttpHeaders;true;getETagValuesAsList;(String);;Element of Argument[-1];ReturnValue;taint",
107119
"org.springframework.http;HttpHeaders;true;getFieldValues;(String);;Argument[-1];ReturnValue;taint",
108120
"org.springframework.http;HttpHeaders;true;getFirst;(String);;Argument[-1];ReturnValue;taint",
109-
"org.springframework.http;HttpHeaders;true;getIfMatch;();;Argument[-1];ReturnValue;taint", // Returns List<String>
110-
"org.springframework.http;HttpHeaders;true;getIfNoneMatch;();;Argument[-1];ReturnValue;taint", // Returns List<String>
121+
"org.springframework.http;HttpHeaders;true;getIfMatch;();;Argument[-1];Element of ReturnValue;taint",
122+
"org.springframework.http;HttpHeaders;true;getIfNoneMatch;();;Argument[-1];Element of ReturnValue;taint",
123+
"org.springframework.http;HttpHeaders;true;getHost;();;Argument[-1];ReturnValue;taint",
111124
"org.springframework.http;HttpHeaders;true;getLocation;();;Argument[-1];ReturnValue;taint",
112-
"org.springframework.http;HttpHeaders;true;getOrEmpty;(Object);;Argument[-1];ReturnValue;taint", // Returns List<String>
125+
"org.springframework.http;HttpHeaders;true;getOrEmpty;(Object);;Argument[-1];Element of ReturnValue;taint",
113126
"org.springframework.http;HttpHeaders;true;getOrigin;();;Argument[-1];ReturnValue;taint",
114127
"org.springframework.http;HttpHeaders;true;getPragma;();;Argument[-1];ReturnValue;taint",
115128
"org.springframework.http;HttpHeaders;true;getUpgrade;();;Argument[-1];ReturnValue;taint",
116-
"org.springframework.http;HttpHeaders;true;getValuesAsList;(String);;Argument[-1];ReturnValue;taint", // Returns List<String>
117-
"org.springframework.http;HttpHeaders;true;getVary;();;Argument[-1];ReturnValue;taint", // Returns List<String>
129+
"org.springframework.http;HttpHeaders;true;getValuesAsList;(String);;Argument[-1];Element of ReturnValue;taint",
130+
"org.springframework.http;HttpHeaders;true;getVary;();;Argument[-1];Element of ReturnValue;taint",
118131
"org.springframework.http;HttpHeaders;true;add;(String,String);;Argument[0..1];Argument[-1];taint",
119132
"org.springframework.http;HttpHeaders;true;set;(String,String);;Argument[0..1];Argument[-1];taint",
120-
"org.springframework.http;HttpHeaders;true;addAll;;;Argument[0..1];Argument[-1];taint" // dependant on collection flow
133+
"org.springframework.http;HttpHeaders;true;addAll;(MultiValueMap);;MapKey of Argument[0];Argument[-1];taint",
134+
"org.springframework.http;HttpHeaders;true;addAll;(MultiValueMap);;Element of MapValue of Argument[0];Argument[-1];taint",
135+
"org.springframework.http;HttpHeaders;true;addAll;(String,List);;Argument[0];Argument[-1];taint",
136+
"org.springframework.http;HttpHeaders;true;addAll;(String,List);;Element of Argument[1];Argument[-1];taint",
137+
"org.springframework.http;HttpHeaders;true;formatHeaders;(MultiValueMap);;MapKey of Argument[0];ReturnValue;taint",
138+
"org.springframework.http;HttpHeaders;true;formatHeaders;(MultiValueMap);;Element of MapValue of Argument[0];ReturnValue;taint",
139+
"org.springframework.http;HttpHeaders;true;encodeBasicAuth;(String,String,Charset);;Argument[0..1];ReturnValue;taint"
121140
]
122141
}
123142
}

java/ql/test/library-tests/frameworks/spring/TestHttp.java

Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
import org.springframework.http.ResponseEntity;
33
import org.springframework.http.RequestEntity;
44
import org.springframework.http.HttpHeaders;
5+
import org.springframework.http.HttpStatus;
56
import org.springframework.util.MultiValueMap;
67
import org.springframework.util.LinkedMultiValueMap;
78
import java.util.Optional;
9+
import java.util.List;
810

911
class TestHttp {
1012
static <T> T taint() { return null; }
@@ -14,12 +16,16 @@ void test1() {
1416
String x = taint();
1517
sink(new HttpEntity(x)); // $hasTaintFlow
1618

17-
MultiValueMap<String,String> m = new LinkedMultiValueMap();
18-
sink(new HttpEntity(x, m)); // $hasTaintFlow
19+
MultiValueMap<String,String> m1 = new LinkedMultiValueMap();
20+
sink(new HttpEntity(x, m1)); // $hasTaintFlow
1921

20-
m.add("a", taint());
21-
sink(new HttpEntity("a", m)); // $ MISSING:hasTaintFlow
22-
sink(new HttpEntity<String>(m)); // $ MISSING:hasTaintFlow
22+
m1.add("a", taint());
23+
sink(new HttpEntity("a", m1)); // $ MISSING:hasTaintFlow
24+
sink(new HttpEntity<String>(m1)); // $ MISSING:hasTaintFlow
25+
26+
MultiValueMap<String,String> m2 = new LinkedMultiValueMap();
27+
m2.add(taint(), "a");
28+
sink(new HttpEntity<String>(m2)); // $ MISSING:hasTaintFlow
2329

2430
HttpEntity<String> ent = taint();
2531
sink(ent.getBody()); // $hasTaintFlow
@@ -45,4 +51,112 @@ void test2() {
4551
sink(ResponseEntity.status(200).location(taint()).lastModified(10000000).build()); // $hasTaintFlow
4652
sink(ResponseEntity.status(200).varyBy(x).build());
4753
}
54+
55+
void test3() {
56+
String x = taint();
57+
58+
MultiValueMap<String,String> m1 = new LinkedMultiValueMap();
59+
sink(new ResponseEntity(x, HttpStatus.ACCEPTED)); // $hasTaintFlow
60+
sink(new ResponseEntity(x, m1, HttpStatus.ACCEPTED)); // $hasTaintFlow
61+
sink(new ResponseEntity(x, m1, 200)); // $hasTaintFlow
62+
63+
m1.add("a", taint());
64+
sink(new ResponseEntity("a", m1, HttpStatus.ACCEPTED)); // $ MISSING:hasTaintFlow
65+
sink(new ResponseEntity<String>(m1, HttpStatus.ACCEPTED)); // $ MISSING:hasTaintFlow
66+
sink(new ResponseEntity("a", m1, 200)); // $ MISSING:hasTaintFlow
67+
68+
MultiValueMap<String,String> m2 = new LinkedMultiValueMap();
69+
m2.add(taint(), "a");
70+
sink(new ResponseEntity("a", m2, HttpStatus.ACCEPTED)); // $ MISSING:hasTaintFlow
71+
sink(new ResponseEntity<String>(m2, HttpStatus.ACCEPTED)); // $ MISSING:hasTaintFlow
72+
sink(new ResponseEntity("a", m2, 200)); // $ MISSING:hasTaintFlow
73+
74+
ResponseEntity<String> ent = taint();
75+
sink(ent.getBody()); // $hasTaintFlow
76+
sink(ent.getHeaders()); // $hasTaintFlow
77+
}
78+
79+
void test4() {
80+
MultiValueMap<String,String> m1 = new LinkedMultiValueMap();
81+
m1.add("a", taint());
82+
sink(new HttpHeaders(m1)); // $ MISSING:hasTaintFlow
83+
84+
MultiValueMap<String,String> m2 = new LinkedMultiValueMap();
85+
m2.add(taint(), "a");
86+
sink(new HttpHeaders(m2)); // $ MISSING:hasTaintFlow
87+
88+
HttpHeaders h1 = new HttpHeaders();
89+
h1.add(taint(), "a");
90+
sink(h1); // $hasTaintFlow
91+
92+
HttpHeaders h2 = new HttpHeaders();
93+
h2.add("a", taint());
94+
sink(h2); // $hasTaintFlow
95+
96+
HttpHeaders h3 = new HttpHeaders();
97+
h3.addAll(m1);
98+
sink(h3); // $ MISSING:hasTaintFlow
99+
100+
HttpHeaders h4 = new HttpHeaders();
101+
h4.addAll(m2);
102+
sink(h4); // $ MISSING:hasTaintFlow
103+
104+
HttpHeaders h5 = new HttpHeaders();
105+
h5.addAll(taint(), List.of());
106+
sink(h5); // $hasTaintFlow
107+
108+
HttpHeaders h6 = new HttpHeaders();
109+
h6.addAll("a", List.of(taint()));
110+
sink(h6); // $hasTaintFlow
111+
112+
sink(HttpHeaders.formatHeaders(m1)); // $ MISSING:hasTaintFlow
113+
sink(HttpHeaders.formatHeaders(m2)); // $ MISSING:hasTaintFlow
114+
115+
sink(HttpHeaders.encodeBasicAuth(taint(), "a", null)); // $hasTaintFlow
116+
sink(HttpHeaders.encodeBasicAuth("a", taint(), null)); // $hasTaintFlow
117+
}
118+
119+
void test5() {
120+
HttpHeaders h = taint();
121+
122+
sink(h.get(null).get(0)); // $hasTaintFlow
123+
sink(h.getAccept().get(0));
124+
sink(h.getAcceptCharset().get(0));
125+
sink(h.getAcceptLanguage().get(0));
126+
sink(h.getAcceptLanguageAsLocales().get(0));
127+
sink(h.getAccessControlAllowCredentials());
128+
sink(h.getAccessControlAllowHeaders().get(0)); // $hasTaintFlow
129+
sink(h.getAccessControlAllowMethods().get(0));
130+
sink(h.getAccessControlAllowOrigin()); // $hasTaintFlow
131+
sink(h.getAccessControlExposeHeaders().get(0)); // $hasTaintFlow
132+
sink(h.getAccessControlMaxAge());
133+
sink(h.getAccessControlRequestHeaders().get(0)); // $hasTaintFlow
134+
sink(h.getAccessControlRequestMethod());
135+
sink(h.getAllow().toArray()[0]);
136+
sink(h.getCacheControl()); // $hasTaintFlow
137+
sink(h.getConnection().get(0)); // $hasTaintFlow
138+
sink(h.getContentDisposition());
139+
sink(h.getContentLanguage());
140+
sink(h.getContentLength());
141+
sink(h.getContentType());
142+
sink(h.getDate());
143+
sink(h.getETag()); // $hasTaintFlow
144+
sink(h.getExpires());
145+
sink(h.getFirst("a")); // $hasTaintFlow
146+
sink(h.getFirstDate("a"));
147+
sink(h.getFirstZonedDateTime("a"));
148+
sink(h.getHost()); // $hasTaintFlow
149+
sink(h.getIfMatch().get(0)); // $hasTaintFlow
150+
sink(h.getIfModifiedSince());
151+
sink(h.getIfNoneMatch().get(0)); // $hasTaintFlow
152+
sink(h.getIfUnmodifiedSince());
153+
sink(h.getLastModified());
154+
sink(h.getLocation()); // $hasTaintFlow
155+
sink(h.getOrEmpty("a").get(0)); // $hasTaintFlow
156+
sink(h.getOrigin()); // $hasTaintFlow
157+
sink(h.getPragma()); // $hasTaintFlow
158+
sink(h.getUpgrade()); // $hasTaintFlow
159+
sink(h.getValuesAsList("a").get(0)); // $hasTaintFlow
160+
sink(h.getVary().get(0)); // $hasTaintFlow
161+
}
48162
}

0 commit comments

Comments
 (0)