Skip to content

Commit 0b27508

Browse files
committed
Add models for org.springframework.jdbc.object
Also add tests for the existing Spring JDBC SQL injection sinks in the process
1 parent a0481bd commit 0b27508

38 files changed

+913
-2
lines changed

java/ql/src/semmle/code/java/frameworks/SpringJdbc.qll

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,16 @@ private class SqlSinkCsv extends SinkModelCsv {
2424
"org.springframework.jdbc.core;JdbcTemplate;false;queryForMap;;;Argument[0];sql",
2525
"org.springframework.jdbc.core;JdbcTemplate;false;queryForObject;;;Argument[0];sql",
2626
"org.springframework.jdbc.core;JdbcTemplate;false;queryForRowSet;;;Argument[0];sql",
27-
"org.springframework.jdbc.core;JdbcTemplate;false;queryForStream;;;Argument[0];sql"
27+
"org.springframework.jdbc.core;JdbcTemplate;false;queryForStream;;;Argument[0];sql",
28+
"org.springframework.jdbc.object;BatchSqlUpdate;false;BatchSqlUpdate;;;Argument[1];sql",
29+
"org.springframework.jdbc.object;MappingSqlQuery;false;BatchSqlUpdate;;;Argument[1];sql",
30+
"org.springframework.jdbc.object;MappingSqlQueryWithParameters;false;BatchSqlUpdate;;;Argument[1];sql",
31+
"org.springframework.jdbc.object;RdbmsOperation;true;setSql;;;Argument[0];sql",
32+
"org.springframework.jdbc.object;SqlCall;false;SqlCall;;;Argument[1];sql",
33+
"org.springframework.jdbc.object;SqlFunction;false;SqlFunction;;;Argument[1];sql",
34+
"org.springframework.jdbc.object;SqlQuery;false;SqlQuery;;;Argument[1];sql",
35+
"org.springframework.jdbc.object;SqlUpdate;false;SqlUpdate;;;Argument[1];sql",
36+
"org.springframework.jdbc.object;UpdatableSqlQuery;false;UpdatableSqlQuery;;;Argument[1];sql"
2837
]
2938
}
3039
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import java.sql.ResultSet;
2+
import java.util.Map;
3+
import org.springframework.jdbc.core.JdbcTemplate;
4+
import org.springframework.jdbc.core.RowMapper;
5+
import org.springframework.jdbc.object.BatchSqlUpdate;
6+
import org.springframework.jdbc.object.MappingSqlQueryWithParameters;
7+
import org.springframework.jdbc.object.SqlFunction;
8+
import org.springframework.jdbc.object.SqlUpdate;
9+
import org.springframework.jdbc.object.UpdatableSqlQuery;
10+
11+
public class SpringJdbc {
12+
13+
public static String source() { return null; }
14+
15+
private static class MyUpdatableSqlQuery extends UpdatableSqlQuery<String> {
16+
public MyUpdatableSqlQuery() {
17+
super(null, source()); // $ sqlInjection
18+
}
19+
20+
protected String updateRow(ResultSet rs, int rowNum, Map<?,?> context) {
21+
return null;
22+
}
23+
}
24+
25+
public static void test(JdbcTemplate template) {
26+
new BatchSqlUpdate(null, source()); // $ sqlInjection
27+
new SqlFunction(null, source()); // $ sqlInjection
28+
new SqlUpdate(null, source()); // $ sqlInjection
29+
30+
(new BatchSqlUpdate()).setSql(source()); // $ sqlInjection
31+
32+
template.batchUpdate(source()); // $ sqlInjection
33+
template.batchUpdate(source(), null, 0, null); // $ sqlInjection
34+
template.execute(source()); // $ sqlInjection
35+
template.update(source()); // $ sqlInjection
36+
template.query(source(), (RowMapper)null); // $ sqlInjection
37+
template.queryForList(source()); // $ sqlInjection
38+
template.queryForMap(source()); // $ sqlInjection
39+
template.queryForObject(source(), (Class)null); // $ sqlInjection
40+
template.queryForRowSet(source()); // $ sqlInjection
41+
template.queryForStream(source(), (RowMapper)null); // $ sqlInjection
42+
}
43+
44+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/springframework-5.3.8

java/ql/test/query-tests/security/CWE-089/semmle/examples/springjdbc.expected

Whitespace-only changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import java
2+
import semmle.code.java.dataflow.TaintTracking
3+
import semmle.code.java.security.QueryInjection
4+
import TestUtilities.InlineExpectationsTest
5+
6+
private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
7+
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
8+
9+
override predicate isSource(DataFlow::Node src) {
10+
src.asExpr() = any(MethodAccess ma | ma.getMethod().hasName("source"))
11+
}
12+
13+
override predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
14+
15+
override predicate isSanitizer(DataFlow::Node node) {
16+
node.getType() instanceof PrimitiveType or
17+
node.getType() instanceof BoxedType or
18+
node.getType() instanceof NumberType
19+
}
20+
21+
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
22+
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)
23+
}
24+
}
25+
26+
class HasFlowTest extends InlineExpectationsTest {
27+
HasFlowTest() { this = "HasFlowTest" }
28+
29+
override string getARelevantTag() { result = "sqlInjection" }
30+
31+
override predicate hasActualResult(Location location, string element, string tag, string value) {
32+
tag = "sqlInjection" and
33+
exists(DataFlow::Node src, DataFlow::Node sink, QueryInjectionFlowConfig conf |
34+
conf.hasFlow(src, sink)
35+
|
36+
sink.getLocation() = location and
37+
element = sink.toString() and
38+
value = ""
39+
)
40+
}
41+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Generated automatically from org.springframework.core.NestedRuntimeException for testing purposes
2+
3+
package org.springframework.core;
4+
5+
6+
abstract public class NestedRuntimeException extends RuntimeException
7+
{
8+
protected NestedRuntimeException() {}
9+
public NestedRuntimeException(String p0){}
10+
public NestedRuntimeException(String p0, Throwable p1){}
11+
public String getMessage(){ return null; }
12+
public Throwable getMostSpecificCause(){ return null; }
13+
public Throwable getRootCause(){ return null; }
14+
public boolean contains(Class<? extends Object> p0){ return false; }
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Generated automatically from org.springframework.dao.DataAccessException for testing purposes
2+
3+
package org.springframework.dao;
4+
5+
import org.springframework.core.NestedRuntimeException;
6+
7+
abstract public class DataAccessException extends NestedRuntimeException
8+
{
9+
protected DataAccessException() {}
10+
public DataAccessException(String p0){}
11+
public DataAccessException(String p0, Throwable p1){}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Generated automatically from org.springframework.jdbc.core.BatchPreparedStatementSetter for testing purposes
2+
3+
package org.springframework.jdbc.core;
4+
5+
import java.sql.PreparedStatement;
6+
7+
public interface BatchPreparedStatementSetter
8+
{
9+
int getBatchSize();
10+
void setValues(PreparedStatement p0, int p1);
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Generated automatically from org.springframework.jdbc.core.CallableStatementCallback for testing purposes
2+
3+
package org.springframework.jdbc.core;
4+
5+
import java.sql.CallableStatement;
6+
7+
public interface CallableStatementCallback<T>
8+
{
9+
T doInCallableStatement(CallableStatement p0);
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Generated automatically from org.springframework.jdbc.core.CallableStatementCreator for testing purposes
2+
3+
package org.springframework.jdbc.core;
4+
5+
import java.sql.CallableStatement;
6+
import java.sql.Connection;
7+
8+
public interface CallableStatementCreator
9+
{
10+
CallableStatement createCallableStatement(Connection p0);
11+
}

0 commit comments

Comments
 (0)