Skip to content

Commit cda5c22

Browse files
authored
Merge pull request github#5590 from github/sauyon/java-spring-errors
Add models for Spring validation.Errors
2 parents 37f8794 + 52d1901 commit cda5c22

File tree

14 files changed

+654
-45
lines changed

14 files changed

+654
-45
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Added additional taint steps modeling the Spring `validation.Errors` class (`org.springframework.validation.Errors`).

java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ private module Frameworks {
8686
private import semmle.code.java.frameworks.Optional
8787
private import semmle.code.java.frameworks.spring.SpringHttp
8888
private import semmle.code.java.frameworks.spring.SpringUtil
89+
private import semmle.code.java.frameworks.spring.SpringValidation
8990
private import semmle.code.java.frameworks.spring.SpringWebClient
9091
private import semmle.code.java.frameworks.spring.SpringBeans
9192
private import semmle.code.java.security.ResponseSplitting

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import semmle.code.java.frameworks.spring.SpringRef
3434
import semmle.code.java.frameworks.spring.SpringReplacedMethod
3535
import semmle.code.java.frameworks.spring.SpringSet
3636
import semmle.code.java.frameworks.spring.SpringUtil
37+
import semmle.code.java.frameworks.spring.SpringValidation
3738
import semmle.code.java.frameworks.spring.SpringValue
3839
import semmle.code.java.frameworks.spring.SpringXMLElement
3940
import semmle.code.java.frameworks.spring.metrics.MetricSpringBean
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/** Definitions of flow steps through utility methods of `org.springframework.validation.Errors`. */
2+
3+
import java
4+
private import semmle.code.java.dataflow.ExternalFlow
5+
6+
private class SpringValidationErrorModel extends SummaryModelCsv {
7+
override predicate row(string row) {
8+
row =
9+
[
10+
"org.springframework.validation;Errors;true;addAllErrors;;;Argument[0];Argument[-1];taint",
11+
"org.springframework.validation;Errors;true;getAllErrors;;;Argument[-1];ReturnValue;taint",
12+
"org.springframework.validation;Errors;true;getFieldError;;;Argument[-1];ReturnValue;taint",
13+
"org.springframework.validation;Errors;true;getFieldErrors;;;Argument[-1];ReturnValue;taint",
14+
"org.springframework.validation;Errors;true;getGlobalError;;;Argument[-1];ReturnValue;taint",
15+
"org.springframework.validation;Errors;true;getGlobalErrors;;;Argument[-1];ReturnValue;taint",
16+
"org.springframework.validation;Errors;true;reject;;;Argument[0];Argument[-1];taint",
17+
"org.springframework.validation;Errors;true;reject;;;ArrayElement of Argument[1];Argument[-1];taint",
18+
"org.springframework.validation;Errors;true;reject;;;Argument[2];Argument[-1];taint",
19+
"org.springframework.validation;Errors;true;rejectValue;;;Argument[1];Argument[-1];taint",
20+
"org.springframework.validation;Errors;true;rejectValue;;;Argument[3];Argument[-1];taint",
21+
"org.springframework.validation;Errors;true;rejectValue;(java.lang.String,java.lang.String,java.lang.Object[],java.lang.String);;ArrayElement of Argument[2];Argument[-1];taint",
22+
"org.springframework.validation;Errors;true;rejectValue;(java.lang.String,java.lang.String,java.lang.String);;Argument[2];Argument[-1];taint"
23+
]
24+
}
25+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import org.springframework.validation.Errors;
2+
3+
class ValidationErrorsTest {
4+
Object source() { return null; }
5+
6+
Errors sourceErrs() { return (Errors)source(); }
7+
Errors errors() { return null; }
8+
9+
void sink(Object o) {}
10+
11+
void test() {
12+
Errors es0 = errors();
13+
es0.addAllErrors(sourceErrs());
14+
sink(es0); // $hasTaintFlow
15+
16+
sink(sourceErrs().getAllErrors()); // $hasTaintFlow
17+
18+
sink(sourceErrs().getFieldError()); // $hasTaintFlow
19+
sink(sourceErrs().getFieldError("field")); // $hasTaintFlow
20+
21+
sink(sourceErrs().getGlobalError()); // $hasTaintFlow
22+
sink(sourceErrs().getGlobalErrors()); // $hasTaintFlow
23+
24+
Errors es1 = errors();
25+
es1.reject((String)source());
26+
sink(es1); // $hasTaintFlow
27+
28+
Errors es2 = errors();
29+
es2.reject((String)source(), null, "");
30+
sink(es2); // $hasTaintFlow
31+
32+
Errors es3 = errors();
33+
es3.reject((String)source(), null, "");
34+
sink(es3); // $hasTaintFlow
35+
36+
{
37+
Errors es4 = errors();
38+
Object[] in = { (String)source() };
39+
es4.reject("", in, "");
40+
sink(in); // $hasTaintFlow
41+
}
42+
43+
{
44+
Errors es5 = errors();
45+
es5.reject("", null, (String)source());
46+
sink(es5); // $hasTaintFlow
47+
}
48+
49+
Errors es6 = errors();
50+
es6.reject((String)source(), "");
51+
sink(es6); // $hasTaintFlow
52+
53+
Errors es7 = errors();
54+
es7.reject("", (String)source());
55+
sink(es7); // $hasTaintFlow
56+
57+
Errors es8 = errors();
58+
es8.rejectValue("", (String)source(), null, "");
59+
sink(es8); // $hasTaintFlow
60+
61+
Errors es9 = errors();
62+
Object[] in = {source()};
63+
es9.rejectValue("", "", in, "");
64+
sink(es9); // $hasTaintFlow
65+
66+
Errors es10 = errors();
67+
es10.rejectValue("", "", null, (String)source());
68+
sink(es10); // $hasTaintFlow
69+
70+
Errors es11 = errors();
71+
es11.rejectValue("", (String)source(), "");
72+
sink(es11); // $hasTaintFlow
73+
74+
Errors es12 = errors();
75+
es12.rejectValue("", "", (String)source());
76+
sink(es12); // $hasTaintFlow
77+
}
78+
}
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.3.8

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

Whitespace-only changes.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import java
2+
import semmle.code.java.dataflow.DataFlow
3+
import semmle.code.java.dataflow.TaintTracking
4+
import TestUtilities.InlineExpectationsTest
5+
6+
class ValueFlowConf extends DataFlow::Configuration {
7+
ValueFlowConf() { this = "qltest:valueFlowConf" }
8+
9+
override predicate isSource(DataFlow::Node n) {
10+
n.asExpr().(MethodAccess).getMethod().hasName("source")
11+
}
12+
13+
override predicate isSink(DataFlow::Node n) {
14+
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
15+
}
16+
}
17+
18+
class TaintFlowConf extends TaintTracking::Configuration {
19+
TaintFlowConf() { this = "qltest:taintFlowConf" }
20+
21+
override predicate isSource(DataFlow::Node n) {
22+
n.asExpr().(MethodAccess).getMethod().hasName("source")
23+
}
24+
25+
override predicate isSink(DataFlow::Node n) {
26+
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
27+
}
28+
}
29+
30+
class HasFlowTest extends InlineExpectationsTest {
31+
HasFlowTest() { this = "HasFlowTest" }
32+
33+
override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
34+
35+
override predicate hasActualResult(Location location, string element, string tag, string value) {
36+
tag = "hasValueFlow" and
37+
exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
38+
sink.getLocation() = location and
39+
element = sink.toString() and
40+
value = ""
41+
)
42+
or
43+
tag = "hasTaintFlow" and
44+
exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf |
45+
conf.hasFlow(src, sink) and not any(ValueFlowConf c).hasFlow(src, sink)
46+
|
47+
sink.getLocation() = location and
48+
element = sink.toString() and
49+
value = ""
50+
)
51+
}
52+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2002-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context;
18+
19+
public interface MessageSourceResolvable {
20+
String[] getCodes();
21+
22+
default Object[] getArguments() {
23+
return null;
24+
}
25+
26+
default String getDefaultMessage() {
27+
return null;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2002-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.support;
18+
19+
import java.io.Serializable;
20+
import org.springframework.context.MessageSourceResolvable;
21+
import org.springframework.lang.Nullable;
22+
23+
public class DefaultMessageSourceResolvable implements MessageSourceResolvable, Serializable {
24+
public DefaultMessageSourceResolvable(String code) {}
25+
26+
public DefaultMessageSourceResolvable(String[] codes) {}
27+
28+
public DefaultMessageSourceResolvable(String[] codes, String defaultMessage) {}
29+
30+
public DefaultMessageSourceResolvable(String[] codes, Object[] arguments) {}
31+
32+
public DefaultMessageSourceResolvable(
33+
@Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage) {}
34+
35+
public DefaultMessageSourceResolvable(MessageSourceResolvable resolvable) {}
36+
37+
public String getCode() {
38+
return null;
39+
}
40+
41+
@Override
42+
public String[] getCodes() {
43+
return null;
44+
}
45+
46+
@Override
47+
public Object[] getArguments() {
48+
return null;
49+
}
50+
51+
@Override
52+
public String getDefaultMessage() {
53+
return null;
54+
}
55+
56+
public boolean shouldRenderDefaultMessage() {
57+
return false;
58+
}
59+
60+
@Override
61+
public String toString() {
62+
return null;
63+
}
64+
65+
@Override
66+
public boolean equals(@Nullable Object other) {
67+
return false;
68+
}
69+
70+
@Override
71+
public int hashCode() {
72+
return 0;
73+
}
74+
75+
protected final String resolvableToString() {
76+
return null;
77+
}
78+
}

0 commit comments

Comments
 (0)