Skip to content

Commit f2ff2aa

Browse files
committed
Add flow tests for JAX-RS
1 parent 155d63d commit f2ff2aa

File tree

3 files changed

+351
-0
lines changed

3 files changed

+351
-0
lines changed

java/ql/test/library-tests/frameworks/JaxWs/JaxRsFlow.expected

Whitespace-only changes.
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
import java.lang.reflect.Method;
2+
import java.net.URI;
3+
import java.util.ArrayList;
4+
import java.util.Date;
5+
import java.util.HashMap;
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Set;
10+
import javax.ws.rs.core.CacheControl;
11+
import javax.ws.rs.core.Cookie;
12+
import javax.ws.rs.core.EntityTag;
13+
import javax.ws.rs.core.Form;
14+
import javax.ws.rs.core.GenericEntity;
15+
import javax.ws.rs.core.HttpHeaders;
16+
import javax.ws.rs.core.Link;
17+
import javax.ws.rs.core.MediaType;
18+
import javax.ws.rs.core.MultivaluedMap;
19+
import javax.ws.rs.core.PathSegment;
20+
import javax.ws.rs.core.Response;
21+
import javax.ws.rs.core.UriBuilder;
22+
import javax.ws.rs.core.UriInfo;
23+
import javax.ws.rs.core.Variant;
24+
25+
public class JaxRsFlow {
26+
String taint() { return "tainted"; }
27+
28+
private static class ResponseSource {
29+
static Response taint() { return null; }
30+
}
31+
32+
private static class ResponseBuilderSource {
33+
static Response.ResponseBuilder taint() { return Response.noContent(); }
34+
}
35+
36+
private static class IntSource {
37+
static int taint() { return 0; }
38+
}
39+
40+
private static class SetStringSource {
41+
static Set<String> taint() { return new HashSet<String>(); }
42+
}
43+
44+
static HttpHeaders taint(HttpHeaders h) { return h; }
45+
46+
static PathSegment taint(PathSegment ps) { return ps; }
47+
48+
static UriInfo taint(UriInfo ui) { return ui; }
49+
50+
static Map taint(Map m) { return m; }
51+
52+
static Link taint(Link l) { return l; }
53+
54+
static Class taint(Class c) { return c; }
55+
56+
private static class UriSource {
57+
static URI taint() throws Exception { return new URI(""); }
58+
}
59+
60+
void sink(Object o) {}
61+
62+
void testResponse() {
63+
sink(Response.accepted(taint())); // $hasTaintFlow
64+
sink(Response.fromResponse(ResponseSource.taint())); // $hasTaintFlow
65+
sink(Response.ok(taint())); // $hasTaintFlow
66+
sink(Response.ok(taint(), new MediaType())); // $hasTaintFlow
67+
sink(Response.ok(taint(), "type")); // $hasTaintFlow
68+
sink(Response.ok(taint(), new Variant(new MediaType(), "", ""))); // $hasTaintFlow
69+
}
70+
71+
void testResponseBuilder(MultivaluedMap<String,Object> multivaluedMap, List<Variant> list) throws Exception {
72+
sink(ResponseBuilderSource.taint().build()); // $hasTaintFlow
73+
sink(Response.noContent().entity(taint())); // $hasTaintFlow
74+
sink(ResponseBuilderSource.taint().allow(new HashSet<String>())); // $hasValueFlow
75+
sink(ResponseBuilderSource.taint().cacheControl(new CacheControl())); // $hasValueFlow
76+
sink(ResponseBuilderSource.taint().clone()); // $hasTaintFlow
77+
sink(ResponseBuilderSource.taint().contentLocation(new URI(""))); // $hasValueFlow
78+
sink(ResponseBuilderSource.taint().cookie()); // $hasValueFlow
79+
sink(ResponseBuilderSource.taint().encoding("")); // $hasValueFlow
80+
sink(ResponseBuilderSource.taint().entity("")); // $hasValueFlow
81+
sink(ResponseBuilderSource.taint().expires(new Date())); // $hasValueFlow
82+
sink(ResponseBuilderSource.taint().header("", "")); // $hasValueFlow
83+
sink(ResponseBuilderSource.taint().language("")); // $hasValueFlow
84+
sink(ResponseBuilderSource.taint().lastModified(new Date())); // $hasValueFlow
85+
sink(ResponseBuilderSource.taint().link("", "")); // $hasValueFlow
86+
sink(ResponseBuilderSource.taint().link(new URI(""), "")); // $hasValueFlow
87+
sink(ResponseBuilderSource.taint().links()); // $hasValueFlow
88+
sink(ResponseBuilderSource.taint().location(new URI(""))); // $hasValueFlow
89+
sink(ResponseBuilderSource.taint().replaceAll(multivaluedMap)); // $hasValueFlow
90+
sink(ResponseBuilderSource.taint().status(400)); // $hasValueFlow
91+
sink(ResponseBuilderSource.taint().tag(new EntityTag(""))); // $hasValueFlow
92+
sink(ResponseBuilderSource.taint().tag("")); // $hasValueFlow
93+
sink(ResponseBuilderSource.taint().type("")); // $hasValueFlow
94+
sink(ResponseBuilderSource.taint().variant(new Variant(new MediaType(), "", ""))); // $hasValueFlow
95+
sink(ResponseBuilderSource.taint().variants(list)); // $hasValueFlow
96+
sink(ResponseBuilderSource.taint().variants()); // $hasValueFlow
97+
}
98+
99+
void testHttpHeaders(HttpHeaders h) {
100+
sink(taint(h).getAcceptableLanguages()); // $hasTaintFlow
101+
sink(taint(h).getAcceptableMediaTypes()); // $hasTaintFlow
102+
sink(taint(h).getCookies()); // $hasTaintFlow
103+
sink(taint(h).getHeaderString("")); // $hasTaintFlow
104+
sink(taint(h).getLanguage()); // $hasTaintFlow
105+
sink(taint(h).getMediaType()); // $hasTaintFlow
106+
sink(taint(h).getRequestHeader("")); // $hasTaintFlow
107+
sink(taint(h).getRequestHeaders()); // $hasTaintFlow
108+
}
109+
110+
void testMultivaluedMapAdd(MultivaluedMap<String, String> mm1, MultivaluedMap<String, String> mm2) {
111+
mm1.add(taint(), "value");
112+
sink(mm1.keySet().iterator().next()); // $hasValueFlow
113+
mm2.add("key", taint());
114+
sink(mm2.get("key").get(0)); // $hasValueFlow
115+
}
116+
117+
void testMultivaluedMapAddAll(MultivaluedMap<String, String> mm1, MultivaluedMap<String, String> mm2, MultivaluedMap<String, String> mm3) {
118+
mm1.addAll(taint(), "a", "b");
119+
sink(mm1.keySet().iterator().next()); // $hasValueFlow
120+
List<String> l = new ArrayList<String>();
121+
l.add(taint());
122+
mm2.addAll("key", l);
123+
sink(mm2.get("key").get(0)); // $hasValueFlow
124+
mm3.addAll("key", "a", taint());
125+
sink(mm3.get("key").get(0)); // $hasValueFlow
126+
}
127+
128+
void testMultivaluedMapAddFirst(MultivaluedMap<String, String> mm1, MultivaluedMap<String, String> mm2) {
129+
mm1.addFirst(taint(), "value");
130+
sink(mm1.keySet().iterator().next()); // $hasValueFlow
131+
mm2.addFirst("key", taint());
132+
sink(mm2.get("key").get(0)); // $hasValueFlow
133+
sink(mm2.getFirst("key")); // $hasValueFlow
134+
}
135+
136+
void testMultivaluedMapputSingle(MultivaluedMap<String, String> mm1, MultivaluedMap<String, String> mm2) {
137+
mm1.putSingle(taint(), "value");
138+
sink(mm1.keySet().iterator().next()); // $hasValueFlow
139+
mm2.putSingle("key", taint());
140+
sink(mm2.get("key").get(0)); // $hasValueFlow
141+
}
142+
143+
void testPathSegment(PathSegment ps1, PathSegment ps2) {
144+
sink(taint(ps1).getMatrixParameters()); // $hasTaintFlow
145+
sink(taint(ps2).getPath()); // $hasTaintFlow
146+
}
147+
148+
void testUriInfo(UriInfo ui1, UriInfo ui2, UriInfo ui3, UriInfo ui4, UriInfo ui5) {
149+
sink(taint(ui1).getPathParameters()); // $hasTaintFlow
150+
sink(taint(ui2).getPathSegments()); // $hasTaintFlow
151+
sink(taint(ui2).getQueryParameters()); // $hasTaintFlow
152+
sink(taint(ui2).getRequestUri()); // $hasTaintFlow
153+
sink(taint(ui2).getRequestUriBuilder()); // $hasTaintFlow
154+
}
155+
156+
void testCookie() {
157+
sink(new Cookie(taint(), "", "", "", 0)); // $hasTaintFlow
158+
sink(new Cookie("", taint(), "", "", 0)); // $hasTaintFlow
159+
sink(new Cookie("", "", taint(), "", 0)); // $hasTaintFlow
160+
sink(new Cookie("", "", "", taint(), 0)); // $hasTaintFlow
161+
sink(new Cookie("", "", "", "", IntSource.taint())); // $hasTaintFlow
162+
sink(new Cookie(taint(), "", "", "")); // $hasTaintFlow
163+
sink(new Cookie("", taint(), "", "")); // $hasTaintFlow
164+
sink(new Cookie("", "", taint(), "")); // $hasTaintFlow
165+
sink(new Cookie("", "", "", taint())); // $hasTaintFlow
166+
sink(new Cookie(taint(), "")); // $hasTaintFlow
167+
sink(new Cookie("", taint())); // $hasTaintFlow
168+
sink(Cookie.valueOf(taint())); // $hasTaintFlow
169+
sink(Cookie.valueOf(taint()).getDomain()); // $hasTaintFlow
170+
sink(Cookie.valueOf(taint()).getName()); // $hasTaintFlow
171+
sink(Cookie.valueOf(taint()).getPath()); // $hasTaintFlow
172+
sink(Cookie.valueOf(taint()).getValue()); // $hasTaintFlow
173+
sink(Cookie.valueOf(taint()).getVersion()); // $hasTaintFlow
174+
sink(Cookie.valueOf(taint()).toString()); // $hasTaintFlow
175+
}
176+
177+
void testForm(MultivaluedMap<String, String> mm1, MultivaluedMap<String, String> mm2) {
178+
sink(new Form(taint(), "")); // $hasTaintFlow
179+
sink(new Form("", taint())); // $hasTaintFlow
180+
mm1.add(taint(), "value");
181+
sink(new Form(mm1)); // $hasTaintFlow
182+
mm2.add("key", taint());
183+
sink(new Form(mm2)); // $hasTaintFlow
184+
Form f1 = new Form(taint(), "");
185+
sink(f1.asMap()); // $hasTaintFlow
186+
Form f2 = new Form();
187+
sink(f2.param(taint(), "b")); // $hasTaintFlow
188+
Form f3 = new Form();
189+
sink(f3.param("a", taint())); // $hasTaintFlow
190+
Form f4 = new Form(taint(), "");
191+
sink(f4.param("a", "b")); // $hasTaintFlow
192+
}
193+
194+
void testGenericEntity() {
195+
Method m = Dummy.class.getMethods()[0];
196+
GenericEntity<Set<String>> ge = new GenericEntity<Set<String>>(SetStringSource.taint(), m.getGenericReturnType());
197+
sink(ge); // $hasTaintFlow
198+
sink(ge.getEntity()); // $hasTaintFlow
199+
}
200+
201+
void testMediaType(Map<String, String> m) {
202+
sink(new MediaType(taint(), "")); // $hasTaintFlow
203+
sink(new MediaType("", taint())); // $hasTaintFlow
204+
sink(new MediaType(taint(), "", m)); // $hasTaintFlow
205+
sink(new MediaType("", taint(), m)); // $hasTaintFlow
206+
sink(new MediaType("", "", taint(m))); // $hasTaintFlow
207+
sink(new MediaType(taint(), "", "")); // $hasTaintFlow
208+
sink(new MediaType("", taint(), "")); // $hasTaintFlow
209+
sink(new MediaType("", "", taint())); // $hasTaintFlow
210+
sink(MediaType.valueOf(taint()).getParameters()); // $hasTaintFlow
211+
sink(MediaType.valueOf(taint()).getSubtype()); // $hasTaintFlow
212+
sink(MediaType.valueOf(taint()).getType()); // $hasTaintFlow
213+
sink(MediaType.valueOf(taint())); // $hasTaintFlow
214+
}
215+
216+
void testUriBuilder() throws Exception {
217+
sink(UriBuilder.fromPath("").build(taint())); // $hasTaintFlow
218+
sink(UriBuilder.fromPath("").build("", taint())); // $hasTaintFlow
219+
sink(UriBuilder.fromPath("").build(taint(), false)); // $hasTaintFlow
220+
sink(UriBuilder.fromPath("").build("", taint(), true)); // $hasTaintFlow
221+
sink(UriBuilder.fromPath(taint()).build("")); // $hasTaintFlow
222+
sink(UriBuilder.fromPath(taint()).build("", false)); // $hasTaintFlow
223+
224+
sink(UriBuilder.fromPath("").buildFromEncoded(taint())); // $hasTaintFlow
225+
sink(UriBuilder.fromPath("").buildFromEncoded("", taint())); // $hasTaintFlow
226+
sink(UriBuilder.fromPath(taint()).buildFromEncoded("")); // $hasTaintFlow
227+
sink(UriBuilder.fromPath("").buildFromEncodedMap(taint(new HashMap<String, String>()))); // $hasTaintFlow
228+
sink(UriBuilder.fromPath(taint()).buildFromEncodedMap(new HashMap<String, String>())); // $hasTaintFlow
229+
sink(UriBuilder.fromPath("").buildFromMap(taint(new HashMap<String, String>()), false)); // $hasTaintFlow
230+
sink(UriBuilder.fromPath(taint()).buildFromMap(new HashMap<String, String>(), true)); // $hasTaintFlow
231+
232+
sink(UriBuilder.fromPath(taint()).clone()); // $hasTaintFlow
233+
sink(UriBuilder.fromPath("").fragment(taint())); // $hasTaintFlow
234+
sink(UriBuilder.fromPath(taint()).fragment("")); // $hasTaintFlow
235+
sink(UriBuilder.fromLink(taint(Link.valueOf("")))); // $hasTaintFlow
236+
sink(UriBuilder.fromPath(taint())); // $hasTaintFlow
237+
sink(UriBuilder.fromUri(taint())); // $hasTaintFlow
238+
sink(UriBuilder.fromPath("").host(taint())); // $hasTaintFlow
239+
sink(UriBuilder.fromPath(taint()).host("")); // $hasTaintFlow
240+
241+
sink(UriBuilder.fromPath("").matrixParam(taint(), "")); // $hasTaintFlow
242+
sink(UriBuilder.fromPath("").matrixParam("", "", taint())); // $hasTaintFlow
243+
sink(UriBuilder.fromPath(taint()).matrixParam("", "")); // $hasTaintFlow
244+
sink(UriBuilder.fromPath("").path(taint(Dummy.class))); // $hasTaintFlow
245+
sink(UriBuilder.fromPath("").path(Dummy.class, taint())); // $hasTaintFlow
246+
sink(UriBuilder.fromPath(taint()).path(Dummy.class)); // $hasTaintFlow
247+
sink(UriBuilder.fromPath("").queryParam(taint(), "")); // $hasTaintFlow
248+
sink(UriBuilder.fromPath("").queryParam("", "", taint())); // $hasTaintFlow
249+
sink(UriBuilder.fromPath(taint()).queryParam("", "")); // $hasTaintFlow
250+
251+
sink(UriBuilder.fromPath("").replaceMatrix(taint())); // $hasTaintFlow
252+
sink(UriBuilder.fromPath(taint()).replaceMatrix("")); // $hasTaintFlow
253+
sink(UriBuilder.fromPath("").replaceMatrixParam(taint(), "")); // $hasTaintFlow
254+
sink(UriBuilder.fromPath("").replaceMatrixParam("", "", taint())); // $hasTaintFlow
255+
sink(UriBuilder.fromPath(taint()).replaceMatrixParam("", "")); // $hasTaintFlow
256+
sink(UriBuilder.fromPath("").replacePath(taint())); // $hasTaintFlow
257+
sink(UriBuilder.fromPath(taint()).replacePath("")); // $hasTaintFlow
258+
sink(UriBuilder.fromPath("").replaceQuery(taint())); // $hasTaintFlow
259+
sink(UriBuilder.fromPath(taint()).replaceQuery("")); // $hasTaintFlow
260+
sink(UriBuilder.fromPath("").replaceQueryParam(taint(), "")); // $hasTaintFlow
261+
sink(UriBuilder.fromPath("").replaceQueryParam("", "", taint())); // $hasTaintFlow
262+
sink(UriBuilder.fromPath(taint()).replaceQueryParam("", "")); // $hasTaintFlow
263+
264+
sink(UriBuilder.fromPath("").resolveTemplate(taint(), "")); // $hasTaintFlow
265+
sink(UriBuilder.fromPath("").resolveTemplate(taint(), "", false)); // $hasTaintFlow
266+
sink(UriBuilder.fromPath("").resolveTemplate("", taint())); // $hasTaintFlow
267+
sink(UriBuilder.fromPath("").resolveTemplate("", taint(), true)); // $hasTaintFlow
268+
sink(UriBuilder.fromPath(taint()).resolveTemplate("", "")); // $hasTaintFlow
269+
sink(UriBuilder.fromPath(taint()).resolveTemplate("", "", false)); // $hasTaintFlow
270+
sink(UriBuilder.fromPath("").resolveTemplateFromEncoded(taint(), "")); // $hasTaintFlow
271+
sink(UriBuilder.fromPath("").resolveTemplateFromEncoded("", taint())); // $hasTaintFlow
272+
sink(UriBuilder.fromPath(taint()).resolveTemplateFromEncoded("", "")); // $hasTaintFlow
273+
274+
sink(UriBuilder.fromPath("").resolveTemplates(taint(new HashMap<String, Object>()))); // $hasTaintFlow
275+
sink(UriBuilder.fromPath("").resolveTemplates(taint(new HashMap<String, Object>()), true)); // $hasTaintFlow
276+
sink(UriBuilder.fromPath(taint()).resolveTemplates(new HashMap<String, Object>())); // $hasTaintFlow
277+
sink(UriBuilder.fromPath(taint()).resolveTemplates(new HashMap<String, Object>(), false)); // $hasTaintFlow
278+
sink(UriBuilder.fromPath("").resolveTemplatesFromEncoded(taint(new HashMap<String, Object>()))); // $hasTaintFlow
279+
sink(UriBuilder.fromPath(taint()).resolveTemplatesFromEncoded(new HashMap<String, Object>())); // $hasTaintFlow
280+
281+
sink(UriBuilder.fromPath("").scheme(taint())); // $hasTaintFlow
282+
sink(UriBuilder.fromPath(taint()).scheme("")); // $hasTaintFlow
283+
sink(UriBuilder.fromPath("").schemeSpecificPart(taint())); // $hasTaintFlow
284+
sink(UriBuilder.fromPath(taint()).schemeSpecificPart("")); // $hasTaintFlow
285+
sink(UriBuilder.fromPath("").segment(taint(), "")); // $hasTaintFlow
286+
sink(UriBuilder.fromPath("").segment("", "", taint())); // $hasTaintFlow
287+
sink(UriBuilder.fromPath(taint()).segment("", "")); // $hasTaintFlow
288+
sink(UriBuilder.fromPath(taint()).toTemplate()); // $hasTaintFlow
289+
290+
sink(UriBuilder.fromPath("").uri(taint())); // $hasTaintFlow
291+
sink(UriBuilder.fromPath(taint()).uri("")); // $hasTaintFlow
292+
sink(UriBuilder.fromPath("").uri(UriSource.taint())); // $hasTaintFlow
293+
sink(UriBuilder.fromPath(taint()).uri(new URI(""))); // $hasTaintFlow
294+
sink(UriBuilder.fromPath("").userInfo(taint())); // $hasTaintFlow
295+
sink(UriBuilder.fromPath(taint()).userInfo("")); // $hasTaintFlow
296+
}
297+
}
298+
299+
class Dummy {
300+
private static Set<String> foo() { return null; }
301+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import java
2+
import semmle.code.java.dataflow.TaintTracking
3+
import TestUtilities.InlineExpectationsTest
4+
5+
class TaintFlowConf extends TaintTracking::Configuration {
6+
TaintFlowConf() { this = "qltest:frameworks:jax-rs-taint" }
7+
8+
override predicate isSource(DataFlow::Node n) {
9+
n.asExpr().(MethodAccess).getMethod().hasName("taint")
10+
}
11+
12+
override predicate isSink(DataFlow::Node n) {
13+
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
14+
}
15+
}
16+
17+
class ValueFlowConf extends DataFlow::Configuration {
18+
ValueFlowConf() { this = "qltest:frameworks:jax-rs-value" }
19+
20+
override predicate isSource(DataFlow::Node n) {
21+
n.asExpr().(MethodAccess).getMethod().hasName("taint")
22+
}
23+
24+
override predicate isSink(DataFlow::Node n) {
25+
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
26+
}
27+
}
28+
29+
class HasFlowTest extends InlineExpectationsTest {
30+
HasFlowTest() { this = "HasFlowTest" }
31+
32+
override string getARelevantTag() { result = ["hasTaintFlow", "hasValueFlow"] }
33+
34+
override predicate hasActualResult(Location location, string element, string tag, string value) {
35+
tag = "hasTaintFlow" and
36+
exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf | conf.hasFlow(src, sink) |
37+
not any(ValueFlowConf vconf).hasFlow(src, sink) and
38+
sink.getLocation() = location and
39+
element = sink.toString() and
40+
value = ""
41+
)
42+
or
43+
tag = "hasValueFlow" and
44+
exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
45+
sink.getLocation() = location and
46+
element = sink.toString() and
47+
value = ""
48+
)
49+
}
50+
}

0 commit comments

Comments
 (0)