Skip to content

Commit 32a20db

Browse files
committed
FindSqlInjection: support of long/double parameters in indirectly called
methods; isSafeValue is called for correct location when SQL query is not the last parameter.
1 parent 370808a commit 32a20db

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

findbugs/src/java/edu/umd/cs/findbugs/detect/FindSqlInjection.java

+29-3
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,24 @@
4747
import edu.umd.cs.findbugs.BugReporter;
4848
import edu.umd.cs.findbugs.Detector;
4949
import edu.umd.cs.findbugs.SourceLineAnnotation;
50+
import edu.umd.cs.findbugs.ba.AnalysisContext;
5051
import edu.umd.cs.findbugs.ba.BasicBlock;
5152
import edu.umd.cs.findbugs.ba.CFG;
5253
import edu.umd.cs.findbugs.ba.CFGBuilderException;
5354
import edu.umd.cs.findbugs.ba.ClassContext;
5455
import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
5556
import edu.umd.cs.findbugs.ba.EdgeTypes;
5657
import edu.umd.cs.findbugs.ba.Location;
58+
import edu.umd.cs.findbugs.ba.SignatureParser;
5759
import edu.umd.cs.findbugs.ba.constant.Constant;
5860
import edu.umd.cs.findbugs.ba.constant.ConstantDataflow;
5961
import edu.umd.cs.findbugs.ba.constant.ConstantFrame;
6062
import edu.umd.cs.findbugs.ba.type.TopType;
6163
import edu.umd.cs.findbugs.ba.type.TypeDataflow;
6264
import edu.umd.cs.findbugs.ba.type.TypeFrame;
65+
import edu.umd.cs.findbugs.ba.vna.ValueNumber;
66+
import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
67+
import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
6368
import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
6469
import edu.umd.cs.findbugs.classfile.Global;
6570
import edu.umd.cs.findbugs.classfile.MethodDescriptor;
@@ -496,6 +501,7 @@ private void analyzeMethod(ClassContext classContext, Method method) throws Data
496501
StringAppendState stringAppendState = getStringAppendState(cfg, cpg);
497502

498503
ConstantDataflow dataflow = classContext.getConstantDataflow(method);
504+
ValueNumberDataflow vnd = classContext.getValueNumberDataflow(method);
499505
for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {
500506
Location location = i.next();
501507
Instruction ins = location.getHandle().getInstruction();
@@ -522,15 +528,16 @@ private void analyzeMethod(ClassContext classContext, Method method) throws Data
522528
}
523529
}
524530
ConstantFrame frame = dataflow.getFactAtLocation(location);
525-
int numArguments = frame.getNumArguments(invoke, cpg);
526-
Constant value = frame.getStackValue(numArguments - 1 - paramNumber);
531+
SignatureParser parser = new SignatureParser(invoke.getSignature(cpg));
532+
Constant value = frame.getArgument(invoke, cpg, paramNumber, parser);
533+
ValueNumber vn = vnd.getFactAtLocation(location).getArgument(invoke, cpg, paramNumber, parser);
527534

528535
if (!value.isConstantString()) {
529536
// TODO: verify it's the same string represented by
530537
// stringAppendState
531538
// FIXME: will false positive on const/static strings
532539
// returns by methods
533-
Location prev = getPreviousLocation(cfg, location, true);
540+
Location prev = getValueNumberCreationLocation(vnd, vn);
534541
if (prev == null || !isSafeValue(prev, cpg)) {
535542
BugInstance bug = generateBugInstance(javaClass, methodGen, location.getHandle(), stringAppendState,
536543
executeMethod);
@@ -544,6 +551,25 @@ private void analyzeMethod(ClassContext classContext, Method method) throws Data
544551
bugAccumulator.reportAccumulatedBugs();
545552
}
546553

554+
private Location getValueNumberCreationLocation(ValueNumberDataflow vnd, ValueNumber vn) {
555+
ConstantPoolGen cpg = vnd.getCFG().getMethodGen().getConstantPool();
556+
for(Iterator<Location> it = vnd.getCFG().locationIterator(); it.hasNext(); ) {
557+
Location loc = it.next();
558+
if(loc.getHandle().getInstruction().produceStack(cpg) != 1) {
559+
continue;
560+
}
561+
try {
562+
ValueNumberFrame vnf = vnd.getFactAfterLocation(loc);
563+
if(vnf.getTopValue().equals(vn)) {
564+
return loc;
565+
}
566+
} catch (DataflowAnalysisException e) {
567+
AnalysisContext.logError("While analyzing "+vnd.getCFG().getMethodGen()+" at "+loc, e);
568+
}
569+
}
570+
return null;
571+
}
572+
547573
@Override
548574
public void report() {
549575
}

findbugsTestCases/src/java/sfBugsNew/Feature314.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package sfBugsNew;
22

3-
import java.io.*;
4-
import java.sql.*;
3+
import java.io.FileNotFoundException;
4+
import java.io.FileOutputStream;
5+
import java.sql.Connection;
6+
import java.sql.ResultSet;
7+
import java.sql.SQLException;
8+
import java.sql.Statement;
59

610
import edu.umd.cs.findbugs.annotations.ExpectWarning;
711
import edu.umd.cs.findbugs.annotations.NoWarning;
@@ -71,11 +75,28 @@ public boolean test(Connection c, String code) throws SQLException {
7175
return Sql.hasResult(c, "SELECT 1 FROM myTable WHERE code='"+code+"'");
7276
}
7377

78+
@ExpectWarning("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
79+
public boolean testSqlLong(Connection c, String code) throws SQLException {
80+
return Sql.hasResult(c, 1L, "SELECT 1 FROM myTable WHERE code='"+code+"'", 2L, "blahblah");
81+
}
82+
83+
@NoWarning("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
84+
public boolean testSqlLongOk(Connection c, String code) throws SQLException {
85+
return Sql.hasResult(c, 1L, "SELECT COUNT(*) FROM myTable", 2L, "Code: "+code);
86+
}
87+
7488
public static class Sql {
7589
public static boolean hasResult(Connection c, String query) throws SQLException {
7690
try (Statement st = c.createStatement(); ResultSet rs = st.executeQuery(query)) {
7791
return rs.next();
7892
}
7993
}
94+
95+
public static boolean hasResult(Connection c, long l1, String query, long l2, String somethingElse) throws SQLException {
96+
System.out.println(somethingElse+": "+l1+":"+l2);
97+
try (Statement st = c.createStatement(); ResultSet rs = st.executeQuery(query)) {
98+
return rs.next();
99+
}
100+
}
80101
}
81102
}

0 commit comments

Comments
 (0)