diff --git a/de.fraunhofer.iem.secucheck.analysis.releng/.attach_pid66076 b/de.fraunhofer.iem.secucheck.analysis.releng/.attach_pid66076 new file mode 100644 index 0000000..e69de29 diff --git a/de.fraunhofer.iem.secucheck.analysis.sample/src/main/java/de/fraunhofer/iem/secucheck/analysis/sample/Main.java b/de.fraunhofer.iem.secucheck.analysis.sample/src/main/java/de/fraunhofer/iem/secucheck/analysis/sample/Main.java index f38a07f..da42884 100644 --- a/de.fraunhofer.iem.secucheck.analysis.sample/src/main/java/de/fraunhofer/iem/secucheck/analysis/sample/Main.java +++ b/de.fraunhofer.iem.secucheck.analysis.sample/src/main/java/de/fraunhofer/iem/secucheck/analysis/sample/Main.java @@ -143,9 +143,9 @@ private static void runDemoSet3(SecucheckAnalysis secucheckAnalysis, getTaintFlowQuery4())); runAnalysisQuery(secucheckAnalysis, compositeOfFirst, 1, null); - runAnalysisQuery(secucheckAnalysis, compositeOfFirstTwo, 2, null); - runAnalysisQuery(secucheckAnalysis, compositeOfFirstThree, 3, null); - runAnalysisQuery(secucheckAnalysis, compositeOfAll, 4, null); + runAnalysisQuery(secucheckAnalysis, compositeOfFirstTwo, 12, null); + runAnalysisQuery(secucheckAnalysis, compositeOfFirstThree, 13, null); + runAnalysisQuery(secucheckAnalysis, compositeOfAll, 14, null); } private static void runAnalysisQuery(SecucheckAnalysis secucheckAnalysis, diff --git a/de.fraunhofer.iem.secucheck.analysis/pom.xml b/de.fraunhofer.iem.secucheck.analysis/pom.xml index bd14f22..401d3da 100644 --- a/de.fraunhofer.iem.secucheck.analysis/pom.xml +++ b/de.fraunhofer.iem.secucheck.analysis/pom.xml @@ -21,31 +21,47 @@ + + + ca.mcgill.sable soot 3.2.0 + + + org.apache.logging.log4j 2.11.0 log4j-api + org.apache.logging.log4j 2.11.0 log4j-core + + + + + + + de.fraunhofer.iem + boomerangScope + 3.1.1 + + + + de.fraunhofer.iem + boomerangPDS + 3.1.1 + + @@ -85,10 +118,18 @@ false + + + + github + CodeShield-Security + https://maven.pkg.github.com/CodeShield-Security/SPDS/ + + - ../de.fraunhofer.iem.secucheck.analysis/src + maven-compiler-plugin diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/SecucheckTaintAnalysisBase.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/SecucheckTaintAnalysisBase.java index 6327662..5492f2f 100644 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/SecucheckTaintAnalysisBase.java +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/SecucheckTaintAnalysisBase.java @@ -1,6 +1,8 @@ package de.fraunhofer.iem.secucheck.analysis; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -8,7 +10,17 @@ import java.util.Map; import java.util.concurrent.locks.ReentrantLock; -import boomerang.preanalysis.BoomerangPretransformer; +import boomerang.BackwardQuery; +import boomerang.Boomerang; +import boomerang.DefaultBoomerangOptions; +import boomerang.Query; +import boomerang.results.BackwardBoomerangResults; +import boomerang.scene.AnalysisScope; +import boomerang.scene.SootDataFlowScope; +import boomerang.scene.Statement; +import boomerang.scene.Val; +import boomerang.scene.jimple.BoomerangPretransformer; +import boomerang.scene.jimple.SootCallGraph; import de.fraunhofer.iem.secucheck.analysis.internal.CompositeTaintFlowAnalysis; import de.fraunhofer.iem.secucheck.analysis.query.CompositeTaintFlowQueryImpl; import de.fraunhofer.iem.secucheck.analysis.query.EntryPoint; @@ -32,13 +44,13 @@ import soot.util.cfgcmd.CFGToDotGraph; import soot.util.dot.DotGraph; import test.core.selfrunning.ImprecisionException; +import wpds.impl.Weight; public abstract class SecucheckTaintAnalysisBase implements SecucheckAnalysis { protected final ReentrantLock lock; protected long analysisTime; - protected BiDiInterproceduralCFG icfg; private OS os; private String appClassPath; @@ -180,6 +192,8 @@ private SecucheckTaintAnalysisResult analyze() { Transform transform = new Transform("wjtp.ifds", createAnalysisTransformer()); PackManager.v().getPack("wjtp").add(transform); PackManager.v().getPack("cg").apply(); + + BoomerangPretransformer.v().apply(); PackManager.v().getPack("wjtp").apply(); if (resultListener != null) { resultListener.reportCompleteResult(this.result); @@ -189,9 +203,9 @@ private SecucheckTaintAnalysisResult analyze() { private SceneTransformer createAnalysisTransformer() throws ImprecisionException { return new SceneTransformer() { - protected void internalTransform(String phaseName, Map options) { - BoomerangPretransformer.v().apply(); - icfg = new JimpleBasedInterproceduralCFG(true); + protected void internalTransform(String phaseName, + @SuppressWarnings("rawtypes") Map options) { + try { executeAnalysis(); } catch (Exception ex) { @@ -199,8 +213,7 @@ protected void internalTransform(String phaseName, Map options) { } } }; - } - + } private static void drawCallGraph(CallGraph callGraph){ DotGraph dot = new DotGraph("callgraph"); @@ -218,16 +231,24 @@ private static void drawCallGraph(CallGraph callGraph){ private void executeAnalysis() throws Exception { + SootCallGraph sootCallGraph = new SootCallGraph(); + // For dumping the call graph for debugging purposes. //drawCallGraph(Scene.v().getCallGraph()); for (CompositeTaintFlowQueryImpl flowQuery : this.flowQueries) { + if (resultListener != null && resultListener.isCancelled()) { break; } - Analysis analysis = new CompositeTaintFlowAnalysis(icfg, flowQuery, resultListener); + + Analysis analysis = new CompositeTaintFlowAnalysis(sootCallGraph, flowQuery, resultListener); CompositeTaintFlowQueryResult singleResult = (CompositeTaintFlowQueryResult) analysis.run(); - this.result.addResult(flowQuery, singleResult); + + if (singleResult.size() != 0) { + this.result.addResult(flowQuery, singleResult); + } + if (resultListener != null) { resultListener.reportCompositeFlowResult((CompositeTaintFlowQueryResult) singleResult); } diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/CompositeTaintFlowAnalysis.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/CompositeTaintFlowAnalysis.java index fe3e94a..9a96c63 100644 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/CompositeTaintFlowAnalysis.java +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/CompositeTaintFlowAnalysis.java @@ -4,6 +4,7 @@ import boomerang.callgraph.ObservableICFG; import boomerang.callgraph.ObservableStaticICFG; +import boomerang.scene.jimple.SootCallGraph; import de.fraunhofer.iem.secucheck.analysis.Analysis; import de.fraunhofer.iem.secucheck.analysis.query.CompositeTaintFlowQuery; import de.fraunhofer.iem.secucheck.analysis.query.Method; @@ -20,14 +21,14 @@ public class CompositeTaintFlowAnalysis implements Analysis { private final CompositeTaintFlowQuery flowQuery; - private final ObservableICFG icfg; + private final SootCallGraph sootCallGraph; private final AnalysisResultListener resultListener; - public CompositeTaintFlowAnalysis(BiDiInterproceduralCFG icfg, + public CompositeTaintFlowAnalysis(SootCallGraph sootCallGraph, CompositeTaintFlowQuery flowQuery, AnalysisResultListener resultListener) throws Exception { this.flowQuery = flowQuery; - this.icfg = new ObservableStaticICFG(icfg); + this.sootCallGraph = sootCallGraph; this.resultListener = resultListener; // Resolve all methods. This is necessary if a flow participant is not part of // the user code... @@ -45,7 +46,7 @@ public AnalysisResult run() { if (this.resultListener != null && this.resultListener.isCancelled()) { break; } - Analysis analysis = new SingleFlowAnalysis(originalFlow, icfg, this.resultListener); + Analysis analysis = new SingleFlowAnalysis(originalFlow, sootCallGraph, this.resultListener); TaintFlowQueryResult retResult = (TaintFlowQueryResult) analysis.run(); if (retResult.size() == 0) { result.clear(); diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowAnalysis.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowAnalysis.java index 58b9986..6758d7a 100644 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowAnalysis.java +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowAnalysis.java @@ -2,11 +2,10 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import com.google.common.collect.Sets; @@ -16,19 +15,19 @@ import boomerang.Boomerang; import boomerang.ForwardQuery; import boomerang.Query; -import boomerang.callgraph.ObservableICFG; -import boomerang.jimple.Statement; -import boomerang.jimple.Val; -import boomerang.seedfactory.SeedFactory; +import boomerang.results.BackwardBoomerangResults; +import boomerang.results.ForwardBoomerangResults; +import boomerang.results.AbstractBoomerangResults.Context; +import boomerang.scene.AnalysisScope; +import boomerang.scene.ControlFlowGraph.Edge; +import boomerang.scene.Val; +import boomerang.scene.jimple.JimpleStatement; +import boomerang.scene.jimple.SootCallGraph; +import boomerang.util.AccessPath; import de.fraunhofer.iem.secucheck.analysis.Analysis; import de.fraunhofer.iem.secucheck.analysis.datastructures.DifferentTypedPair; -import de.fraunhofer.iem.secucheck.analysis.datastructures.Pair; import de.fraunhofer.iem.secucheck.analysis.datastructures.SameTypedPair; -import de.fraunhofer.iem.secucheck.analysis.query.InputParameter; import de.fraunhofer.iem.secucheck.analysis.query.Method; -import de.fraunhofer.iem.secucheck.analysis.query.MethodImpl; -import de.fraunhofer.iem.secucheck.analysis.query.OutputParameter; -import de.fraunhofer.iem.secucheck.analysis.query.ReturnValue; import de.fraunhofer.iem.secucheck.analysis.query.TaintFlowQuery; import de.fraunhofer.iem.secucheck.analysis.query.TaintFlowQueryImpl; import de.fraunhofer.iem.secucheck.analysis.result.AnalysisResult; @@ -38,36 +37,30 @@ import de.fraunhofer.iem.secucheck.analysis.result.TaintFlowQueryResult; import soot.Body; import soot.SootMethod; -import soot.Unit; -import soot.Value; -import soot.jimple.AssignStmt; import soot.jimple.IdentityStmt; -import soot.jimple.InstanceInvokeExpr; import soot.jimple.JimpleBody; import soot.jimple.ParameterRef; -import soot.jimple.Stmt; import soot.jimple.internal.JNopStmt; -import soot.tagkit.Host; -import soot.tagkit.PositionTag; -import soot.tagkit.AbstractHost; +import wpds.impl.Weight; import wpds.impl.Weight.NoWeight; class SingleFlowAnalysis implements Analysis { private final TaintFlowQueryImpl singleFlow; - private final ObservableICFG icfg; + private final SootCallGraph sootCallGraph; private final AnalysisResultListener resultListener; public SingleFlowAnalysis(TaintFlowQueryImpl singleFlow, - ObservableICFG icfg, + SootCallGraph sootCallGraph, AnalysisResultListener resultListener) { this.singleFlow = singleFlow; - this.icfg = icfg; + this.sootCallGraph = sootCallGraph; this.resultListener = resultListener; } @Override public AnalysisResult run() { + TaintFlowQueryResult result = new TaintFlowQueryResult(); List>> reachMap; @@ -86,15 +79,17 @@ public AnalysisResult run() { analyzePlainFlow(TaintFlowQueryImpl singleFlow){ List>> - reachMap = new ArrayList>>(); + reachMap = new ArrayList<>(); - SeedFactory seedFactory = getSeedFactory(singleFlow); - Boomerang boomerang = getBoomerang(seedFactory); - Seeds seeds = computeSeeds(seedFactory); + AnalysisScope analysisScope = getAnalysisScope(singleFlow); + Boomerang boomerang = getBoomerang(analysisScope); + Seeds seeds = computeSeeds(analysisScope); if (seeds.getSources().size() != 0 && seeds.getSinks().size() != 0) { + List sanitizers = getSanitizers(singleFlow); Map oldMethodBodies = new HashMap(); + try { oldMethodBodies = setEmptySootBodies(sanitizers); reachMap = analyzeInternal(boomerang, singleFlow, seeds.getSources(), @@ -104,6 +99,7 @@ public AnalysisResult run() { entry.getKey().setActiveBody(entry.getValue())); } } + return reachMap; } @@ -118,25 +114,30 @@ public AnalysisResult run() { newQuery2 = new TaintFlowQueryImpl(); newQuery1.getFrom().addAll(singleFlow.getFrom()); + if (singleFlow.getNotThrough() != null) newQuery1.getNotThrough().addAll(singleFlow.getNotThrough()); + newQuery1.getTo().addAll(singleFlow.getThrough()); newQuery2.getFrom().addAll(singleFlow.getThrough()); + if (singleFlow.getNotThrough() != null) newQuery2.getNotThrough().addAll(singleFlow.getNotThrough()); + newQuery2.getTo().addAll(singleFlow.getTo()); List>> - originalReachMap = - new ArrayList>>(), + originalReachMap = new ArrayList<>(), reachMap1 = analyzePlainFlow(newQuery1), reachMap2 = analyzePlainFlow(newQuery2); if (reachMap1.size() != 0 && reachMap2.size() != 0) { for (DifferentTypedPair> sourcePair : reachMap1) { + for (DifferentTypedPair> sinkPair : reachMap2) { + if (isSourceAndSinkMatching(sourcePair.getSecond(), sinkPair.getSecond())) { SameTypedPair stichedPair = stitchSourceAndSink(sourcePair.getSecond(), sinkPair.getSecond()); @@ -146,6 +147,7 @@ public AnalysisResult run() { (singleFlow, stichedPair)); } } + } } @@ -153,101 +155,129 @@ public AnalysisResult run() { } private List>> - analyzeInternal(Boomerang boomerang, - TaintFlowQueryImpl partialFlow, Set sources, + analyzeInternal(Boomerang boomerang, TaintFlowQueryImpl flowQuery, Set sources, Set sinks) { List>> reachMap = - new ArrayList>>(); + new ArrayList<>(); if (sources.size() != 0 && sinks.size() != 0) { - // Found more sinks than sources, running forward analysis - if (sources.size() <= sinks.size()) { - sources.forEach(source -> boomerang.solve(source)); - reachMap = getReachingPairs(boomerang, partialFlow, sources, sinks); - } else { - // Found less sinks than sources, running backward analysis - sinks.forEach(sink -> boomerang.solve(sink)); - reachMap = getReachingPairs(boomerang, partialFlow, sinks, sources); - } - } + + Map> forwardResults = new HashMap<>(); + sources.forEach(source -> forwardResults.put(source, boomerang.solve(source))); + reachMap = getReachingPairs(boomerang, flowQuery, sinks, forwardResults); + + } + return reachMap; } private List>> - getReachingPairs(Boomerang boomerang, TaintFlowQueryImpl flowQuery, Set queries, - Set reachable) { + getReachingPairs(Boomerang boomerang, TaintFlowQueryImpl flowQuery, Set sinks, + Map> sourceResults) { List>> reachMap = - new ArrayList>>(); - - for (Query start : queries) { - for (Query end : reachable) { - if (isValidPath(boomerang, start, end)) { - if (start instanceof ForwardQuery) { - reachMap.add(new DifferentTypedPair>( - flowQuery, getLocationDetailsPair(flowQuery, start, end))); - } else if (start instanceof BackwardQuery) { - reachMap.add(new DifferentTypedPair>( - flowQuery, getLocationDetailsPair(flowQuery, end, start))); - } + new ArrayList<>(); + + for (Entry> sourceEntry + : sourceResults.entrySet()) { + + for (BackwardQuery sink : sinks) { + + if (isValidPath(sourceEntry.getValue(), sink)) { + reachMap.add(new DifferentTypedPair<>( + flowQuery, getLocationDetailsPair(flowQuery, sourceEntry.getKey(), sink))); } + } } + return reachMap; } + private boolean isValidPath(ForwardBoomerangResults sourceResult, + BackwardQuery sink) { + + Table table = sourceResult.asStatementValWeightTable(); + + Edge sinkEdge = sink.cfgEdge(); + Val sinkValue = sink.var(); + + return table.contains(sinkEdge, sinkValue); + + } + private SameTypedPair getLocationDetailsPair(TaintFlowQueryImpl flowQuery, Query start, Query end){ LocationDetails startDetails = new LocationDetails(); - SootMethod sourceMethodDefinition = Utility.findSourceMethodDefinition(flowQuery, start.stmt().getMethod(), - start.stmt().getUnit().get()); - startDetails.setSourceClassName(sourceMethodDefinition.getDeclaringClass().getName()); - startDetails.setMethodSignature(sourceMethodDefinition.getSignature()); - - AbstractHost sourceHost = (AbstractHost) start.asNode().stmt().getUnit().get(); - startDetails.setUsageLineNumber(sourceHost.getJavaSourceStartLineNumber()); - startDetails.setUsageColumnNumber(sourceHost.getJavaSourceStartColumnNumber()); - startDetails.setUsageMethodSignature(start.stmt().getMethod().getSignature()); - startDetails.setUsageClassName(start.stmt().getMethod().getDeclaringClass().getName()); + startDetails.setSourceClassName(start.cfgEdge().getMethod().getDeclaringClass().getName()); + startDetails.setMethodSignature(start.cfgEdge().getMethod().getSubSignature()); + + // When parameter is tainted. + // Left and Right Op() methods don't work for IdentityStmt inside JimpleStatement. + if (start.cfgEdge().getY().isIdentityStmt() && start.cfgEdge().getY() instanceof JimpleStatement) { + JimpleStatement jimpleStament = (JimpleStatement) start.cfgEdge().getY(); + IdentityStmt identityStmt = (IdentityStmt)jimpleStament.getDelegate(); + if (identityStmt.getRightOp() instanceof ParameterRef) { + SootMethod sootMethod = Utility.getSootMethod(start.cfgEdge().getY().getMethod()); + startDetails.setUsageStartLineNumber(sootMethod.getJavaSourceStartLineNumber()); + startDetails.setUsageEndLineNumber(-1); + startDetails.setUsageStartColumnNumber(sootMethod.getJavaSourceStartColumnNumber()); + startDetails.setUsageEndColumnNumber(-1); + } + } else { + startDetails.setUsageStartLineNumber(start.cfgEdge().getY().getStartLineNumber()); + startDetails.setUsageEndLineNumber(start.cfgEdge().getY().getEndLineNumber()); + startDetails.setUsageStartColumnNumber(start.cfgEdge().getY().getStartColumnNumber()); + startDetails.setUsageEndColumnNumber(start.cfgEdge().getY().getEndColumnNumber()); + } + + startDetails.setUsageMethodSignature(start.cfgEdge().getY().getMethod().getSubSignature()); + startDetails.setUsageClassName(start.cfgEdge().getY().getMethod().getDeclaringClass().getName()); startDetails.setType(LocationType.Source); LocationDetails endDetails = new LocationDetails(); - SootMethod sinkMethodDefinition = Utility.findSinkMethodDefinition(flowQuery, end.stmt().getMethod(), - end.stmt().getUnit().get()); - endDetails.setSourceClassName(sinkMethodDefinition.getDeclaringClass().getName()); - endDetails.setMethodSignature(sinkMethodDefinition.getSignature()); - - AbstractHost sinkHost = (AbstractHost) end.asNode().stmt().getUnit().get(); - endDetails.setUsageLineNumber(sinkHost.getJavaSourceStartLineNumber()); - endDetails.setUsageColumnNumber(sinkHost.getJavaSourceStartColumnNumber()); - endDetails.setUsageMethodSignature(end.stmt().getMethod().getSignature()); - endDetails.setUsageClassName(end.stmt().getMethod().getDeclaringClass().getName()); + endDetails.setSourceClassName(end.cfgEdge().getMethod().getDeclaringClass().getName()); + endDetails.setMethodSignature(end.cfgEdge().getMethod().getSubSignature()); + + endDetails.setUsageStartLineNumber(end.cfgEdge().getY().getStartLineNumber()); + endDetails.setUsageEndLineNumber(end.cfgEdge().getY().getEndLineNumber()); + endDetails.setUsageStartColumnNumber(end.cfgEdge().getY().getStartColumnNumber()); + endDetails.setUsageEndColumnNumber(end.cfgEdge().getY().getEndColumnNumber()); + + endDetails.setUsageMethodSignature(end.cfgEdge().getY().getMethod().getSubSignature()); + endDetails.setUsageClassName(end.cfgEdge().getY().getMethod().getDeclaringClass().getName()); endDetails.setType(LocationType.Sink); return new SameTypedPair(startDetails, endDetails); + } - private SeedFactory getSeedFactory(TaintFlowQuery taintFlow) { - return new SingleFlowSeedFactory(taintFlow, this.icfg); + private AnalysisScope getAnalysisScope(TaintFlowQuery taintFlow) { + return new SingleFlowAnalysisScope(taintFlow, this.sootCallGraph); } - private Boomerang getBoomerang(SeedFactory seedFactory) { - return new SingleFlowBoomerang(seedFactory, this.icfg, new TaintAnalysisOptions()); + private Boomerang getBoomerang(AnalysisScope analysisScope) { + return new SingleFlowBoomerang(analysisScope, this.sootCallGraph, new TaintAnalysisOptions()); } private List getSanitizers(TaintFlowQuery partFlow) { + List sanitizers = new ArrayList(); + if (partFlow.getNotThrough() != null) partFlow.getNotThrough().forEach(y -> sanitizers.add((Method)y)); + return sanitizers; } - private Seeds computeSeeds(SeedFactory seedFactory) { + private Seeds computeSeeds(AnalysisScope analysisScope) { + Set sources = Sets.newHashSet(); Set sinks = Sets.newHashSet(); - Collection computeSeeds = seedFactory.computeSeeds(); + Collection computeSeeds = analysisScope.computeSeeds(); + for (Query q : computeSeeds) { if (q instanceof BackwardQuery) { sinks.add((BackwardQuery) q); @@ -255,11 +285,13 @@ private Seeds computeSeeds(SeedFactory seedFactory) { sources.add((ForwardQuery) q); } } + return new Seeds(sources, sinks); } private Map setEmptySootBodies(List methods){ - Map oldBodies = new HashMap(); + Map oldBodies = new HashMap<>(); + for (Method method : methods) { SootMethod sootMethod = Utility.getSootMethod(method); if (sootMethod != null) { @@ -273,7 +305,8 @@ private Map setEmptySootBodies(List methods){ replacementBody.insertIdentityStmts(); sootMethod.setActiveBody(replacementBody); } - } + } + return oldBodies; } @@ -300,12 +333,20 @@ private boolean isSourceAndSinkMatching(SameTypedPair sourcePai sinkPair.getFirst().getMethodSignature())) return false; - if (sourcePair.getSecond().getUsageLineNumber() != - sinkPair.getFirst().getUsageLineNumber()) + if (sourcePair.getSecond().getUsageStartLineNumber() != + sinkPair.getFirst().getUsageStartLineNumber()) + return false; + + if (sourcePair.getSecond().getUsageEndLineNumber() != + sinkPair.getFirst().getUsageEndLineNumber()) return false; - if (sourcePair.getSecond().getUsageColumnNumber() != - sinkPair.getFirst().getUsageColumnNumber()) + if (sourcePair.getSecond().getUsageStartColumnNumber() != + sinkPair.getFirst().getUsageStartColumnNumber()) + return false; + + if (sourcePair.getSecond().getUsageEndColumnNumber() != + sinkPair.getFirst().getUsageEndColumnNumber()) return false; return true; @@ -313,16 +354,6 @@ private boolean isSourceAndSinkMatching(SameTypedPair sourcePai private SameTypedPair stitchSourceAndSink( SameTypedPair sourcePair, SameTypedPair sinkPair) { - SameTypedPair stichedPair = - new SameTypedPair<>(sourcePair.getFirst(), sinkPair.getSecond()); - return stichedPair; - } - - private boolean isValidPath(Boomerang boomerang, Query start, Query end) { - // Quick check: Is the "end" included in the Table at all? - Statement s = end.asNode().stmt(); - Val v = end.asNode().fact(); - Table results = boomerang.getResults(start); - return results.get(s, v) == null ? false : true; + return new SameTypedPair<>(sourcePair.getFirst(), sinkPair.getSecond()); } } \ No newline at end of file diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowAnalysisScope.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowAnalysisScope.java new file mode 100644 index 0000000..ce9094f --- /dev/null +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowAnalysisScope.java @@ -0,0 +1,201 @@ +package de.fraunhofer.iem.secucheck.analysis.internal; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import com.google.common.collect.Sets; + +import boomerang.BackwardQuery; +import boomerang.ForwardQuery; +import boomerang.Query; +import boomerang.WeightedForwardQuery; +import boomerang.scene.AllocVal; +import boomerang.scene.AnalysisScope; +import boomerang.scene.ControlFlowGraph.Edge; +import boomerang.scene.Statement; +import boomerang.scene.Val; +import boomerang.scene.jimple.JimpleStatement; +import boomerang.scene.jimple.JimpleVal; +import boomerang.scene.jimple.SootCallGraph; +import de.fraunhofer.iem.secucheck.analysis.datastructures.SameTypedPair; +import de.fraunhofer.iem.secucheck.analysis.query.InputParameter; +import de.fraunhofer.iem.secucheck.analysis.query.Method; +import de.fraunhofer.iem.secucheck.analysis.query.OutputParameter; +import de.fraunhofer.iem.secucheck.analysis.query.TaintFlowQuery; +import soot.jimple.IdentityStmt; +import soot.jimple.ParameterRef; +import soot.jimple.internal.JIdentityStmt; +import wpds.impl.Weight; +import wpds.impl.Weight; + +public class SingleFlowAnalysisScope extends AnalysisScope { + + private final TaintFlowQuery taintFlow; + + private final Set sourceMethods = new HashSet<>(); + private final Set sinkMethods = new HashSet<>(); + + public SingleFlowAnalysisScope(TaintFlowQuery taintFlow, SootCallGraph sootCallGraph) { + super(sootCallGraph); + this.taintFlow = taintFlow; + } + + @Override + protected Collection generate(Edge cfgEdge) { + Set out = Sets.newHashSet(); + + // The target statement for the current edge. + Statement statement = cfgEdge.getTarget(); + + Collection sourceVariables = + generateSourceVariables(this.taintFlow, statement); + + sourceVariables.forEach(v -> out.add(new ForwardQuery(cfgEdge, v ))); + + Collection sinkVariables = generatedSinkVariables(this.taintFlow, statement); + + sinkVariables.forEach(v -> out.add(BackwardQuery.make(cfgEdge, v))); + + // Find source methods. + for (Method flowMethod : this.taintFlow.getFrom()) { + if (toStringEquals(statement.getMethod(), + wrapInAngularBrackets(flowMethod.getSignature()))) { + sourceMethods.add(statement.getMethod()); + } + } + + // Find target methods. + for (Method flowMethod : this.taintFlow.getTo()) { + if (toStringEquals(statement.getMethod(), + wrapInAngularBrackets(flowMethod.getSignature()))) { + sinkMethods.add(statement.getMethod()); + } + } + + return out; + } + + private Collection generateSourceVariables(TaintFlowQuery partialFlow, + Statement statement) { + + for (Method sourceMethod : partialFlow.getFrom()) { + + String sourceSootSignature = wrapInAngularBrackets(sourceMethod.getSignature()); + Collection out = Sets.newHashSet(); + + if (toStringEquals(statement.getMethod(), sourceSootSignature) && + statement.isIdentityStmt()) { + + // Left and Right Op() methods don't work for IdentityStmt inside JimpleStatement. + if (statement instanceof JimpleStatement) { + + JimpleStatement jimpleStament = (JimpleStatement) statement; + IdentityStmt identityStmt = (IdentityStmt)jimpleStament.getDelegate(); + + if (identityStmt.getRightOp() instanceof ParameterRef) { + ParameterRef parameterRef = (ParameterRef) identityStmt.getRightOp(); + + if (sourceMethod.getOutputParameters() != null) { + for (OutputParameter output : sourceMethod.getOutputParameters()) { + + int parameterIndex = output.getNumber(); + if (statement.getMethod().getParameterLocals().size() >= parameterIndex + && parameterRef.getIndex() == parameterIndex) { + + out.add(new AllocVal( + new JimpleVal(identityStmt.getLeftOp(), statement.getMethod()), + statement, + new JimpleVal(identityStmt.getRightOp(), statement.getMethod()) + )); + + } + } + } + } + } + + return out; + + } else if (statement.containsInvokeExpr() + && toStringEquals(statement.getInvokeExpr().getMethod().getSignature(), + sourceSootSignature)) { + + // Taint the return value + if (sourceMethod.getReturnValue() != null && statement.isAssign()) { + out.add(new AllocVal(statement.getLeftOp(), statement, statement.getRightOp())); + } + + if (sourceMethod.getOutputParameters() != null) { + for (OutputParameter output : sourceMethod.getOutputParameters()) { + int parameterIndex = output.getNumber(); + if (statement.getInvokeExpr().getArgs().size() >= parameterIndex) { + out.add(statement.getInvokeExpr().getArg(parameterIndex)); + } + } + } + + // Taint this object + if (sourceMethod.isOutputThis() && + statement.getInvokeExpr().isInstanceInvokeExpr()) { + out.add(statement.getInvokeExpr().getBase()); + } + + return out; + } + + } +// if (this.flow.getSource().getValueSource() != null) // a single value source +// { +// // TODO:handle this +// } + return Collections.emptySet(); + } + + private Collection generatedSinkVariables(TaintFlowQuery partialFlow, + Statement statement) { + + for (Method sinkMethod : partialFlow.getTo()) { + + String sinkSootSignature = wrapInAngularBrackets(sinkMethod.getSignature()); + Collection out = Sets.newHashSet(); + + if (statement.containsInvokeExpr() && + toStringEquals(statement.getInvokeExpr().getMethod().getSignature(), + sinkSootSignature)) { + + // Taint the return value. + if (sinkMethod.getInputParameters() != null) { + for (InputParameter input : sinkMethod.getInputParameters()) { + int parameterIndex = input.getNumber(); + if (statement.getInvokeExpr().getArgs().size() >= parameterIndex) { + out.add(statement.getInvokeExpr().getArg(parameterIndex)); + } + } + } + + // Taint this object. + if (sinkMethod.isInputThis() && + statement.getInvokeExpr().isInstanceInvokeExpr()) { + out.add(statement.getInvokeExpr().getBase()); + } + + return out; + } + + } + + // TODO: re-check the sink structure!! + return Collections.emptySet(); + } + + private static String wrapInAngularBrackets(String value) { + return "<" + value + ">"; + } + + private static boolean toStringEquals(Object object1, Object object2) { + return object1.toString().equals(object2.toString()); + } + +} diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowBoomerang.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowBoomerang.java index f93b9ab..d0e3a93 100644 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowBoomerang.java +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowBoomerang.java @@ -1,31 +1,20 @@ package de.fraunhofer.iem.secucheck.analysis.internal; import boomerang.Boomerang; -import boomerang.callgraph.ObservableICFG; -import boomerang.seedfactory.SeedFactory; -import soot.SootMethod; -import soot.Unit; -import wpds.impl.Weight.NoWeight; +import boomerang.scene.AnalysisScope; +import boomerang.scene.SootDataFlowScope; +import boomerang.scene.jimple.SootCallGraph; +import soot.Scene; public class SingleFlowBoomerang extends Boomerang { - private final SeedFactory seedFactory; - private final ObservableICFG icfg; + private final AnalysisScope analysisScope; + private final SootCallGraph sootCallGraph; - public SingleFlowBoomerang(SeedFactory seedFactory, - ObservableICFG icfg, TaintAnalysisOptions options){ - super(options); - this.seedFactory = seedFactory; - this.icfg = icfg; - } - - @Override - public ObservableICFG icfg() { - return this.icfg; - } - - @Override - public SeedFactory getSeedFactory() { - return this.seedFactory; + public SingleFlowBoomerang(AnalysisScope analysisScope, + SootCallGraph sootCallGraph, TaintAnalysisOptions options){ + super(sootCallGraph, SootDataFlowScope.make(Scene.v()), options); + this.analysisScope = analysisScope; + this.sootCallGraph = sootCallGraph; } } diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowSeedFactory.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowSeedFactory.java deleted file mode 100644 index bf4de8d..0000000 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/SingleFlowSeedFactory.java +++ /dev/null @@ -1,174 +0,0 @@ -package de.fraunhofer.iem.secucheck.analysis.internal; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - -import com.google.common.collect.Sets; - -import boomerang.BackwardQuery; -import boomerang.ForwardQuery; -import boomerang.Query; -import boomerang.callgraph.ObservableICFG; -import boomerang.jimple.Statement; -import boomerang.jimple.Val; -import boomerang.seedfactory.SeedFactory; -import de.fraunhofer.iem.secucheck.analysis.query.InputParameter; -import de.fraunhofer.iem.secucheck.analysis.query.Method; -import de.fraunhofer.iem.secucheck.analysis.query.OutputParameter; -import de.fraunhofer.iem.secucheck.analysis.query.TaintFlowQuery; -import soot.SootMethod; -import soot.Unit; -import soot.Value; -import soot.jimple.AssignStmt; -import soot.jimple.IdentityStmt; -import soot.jimple.InstanceInvokeExpr; -import soot.jimple.ParameterRef; -import soot.jimple.Stmt; -import wpds.impl.Weight.NoWeight; - -public class SingleFlowSeedFactory extends SeedFactory{ - - private final TaintFlowQuery taintFlow; - private final ObservableICFG icfg; - - private final Set sourceMethods = new HashSet(); - private final Set sinkMethods = new HashSet(); - - public SingleFlowSeedFactory(TaintFlowQuery taintFlow, ObservableICFG icfg) { - this.taintFlow = taintFlow; - this.icfg = icfg; - } - - @Override - protected Collection generate(SootMethod method, Stmt u) { - Set out = Sets.newHashSet(); - - Collection sourceVariables = generateSourceVariables(this.taintFlow, method, u); - sourceVariables.forEach(v -> - out.add(new ForwardQuery(new Statement(u, method), new Val(v, method))) ); - - Collection sinkVariables = generatedSinkVariables(this.taintFlow, method, u); - sinkVariables.forEach(v -> - out.add(new BackwardQuery(new Statement(u, method), new Val(v, method)))); - - // Find source method - for (Method flowMethod : this.taintFlow.getFrom()) { - if (method.toString().equals("<" + flowMethod.getSignature() + ">")) { - sourceMethods.add(method); - } - } - - // Find target method - for (Method flowMethod : this.taintFlow.getTo()) { - if (method.toString().equals("<" + flowMethod.getSignature() + ">")) { - sinkMethods.add(method); - } - } - return out; - } - - @Override - public ObservableICFG icfg() { return this.icfg; } - - private Collection generateSourceVariables(TaintFlowQuery partialFlow, - SootMethod method, Stmt actualStatement) { - - for (Object object : partialFlow.getFrom()) { - Method sourceMethod = (Method) object; - String sourceSootSignature = "<" + sourceMethod.getSignature() + ">"; - Collection out = Sets.newHashSet(); - - if (method.getSignature().equals(sourceSootSignature) && - actualStatement instanceof IdentityStmt) { - - IdentityStmt identity = (IdentityStmt) actualStatement; - Value right = identity.getRightOp(); - if (right instanceof ParameterRef) { - - ParameterRef parameterRef = (ParameterRef) right; - if (sourceMethod.getOutputParameters() != null) { - for (OutputParameter output : sourceMethod.getOutputParameters()) { - int parameterIndex = output.getNumber(); - if (parameterRef.getIndex() == parameterIndex - && method.getParameterCount() >= parameterIndex) { - out.add(identity.getLeftOp()); - } - } - } - - } - return out; - - } else if (actualStatement.containsInvokeExpr() - && actualStatement.toString().contains(sourceSootSignature)) { - - // taint the return value - if (sourceMethod.getReturnValue() != null && actualStatement instanceof AssignStmt) { - out.add(((AssignStmt) actualStatement).getLeftOp()); - } - - if (sourceMethod.getOutputParameters() != null) { - for (OutputParameter output : sourceMethod.getOutputParameters()) { - int parameterIndex = output.getNumber(); - if (actualStatement.getInvokeExpr().getArgCount() >= parameterIndex) { - out.add(actualStatement.getInvokeExpr().getArg(parameterIndex)); - } - } - } - - // taint this object - if (sourceMethod.isOutputThis() && actualStatement.getInvokeExpr() instanceof InstanceInvokeExpr) { - InstanceInvokeExpr instanceInvoke = (InstanceInvokeExpr) actualStatement.getInvokeExpr(); - out.add(instanceInvoke.getBase()); - } - - return out; - } - - } - - -// if (this.flow.getSource().getValueSource() != null) // a single value source -// { -// // TODO:handle this -// } - return Collections.emptySet(); - } - - private Collection generatedSinkVariables(TaintFlowQuery partialFlow, - SootMethod method, Stmt actualStatement) { - for (Object object : partialFlow.getTo()) { - Method sourceMethod = (Method) object; - String sourceSootSignature = "<" + sourceMethod.getSignature() + ">"; - Collection out = Sets.newHashSet(); - - if (actualStatement.containsInvokeExpr() - && actualStatement.toString().contains(sourceSootSignature)) { - - // taint the return value - if (sourceMethod.getInputParameters() != null) { - for (InputParameter input : sourceMethod.getInputParameters()) { - int parameterIndex = input.getNumber(); - if (actualStatement.getInvokeExpr().getArgCount() >= parameterIndex) { - out.add(actualStatement.getInvokeExpr().getArg(parameterIndex)); - } - } - } - - // taint this object - if (sourceMethod.isInputThis() && actualStatement.getInvokeExpr() instanceof InstanceInvokeExpr) { - InstanceInvokeExpr instanceInvoke = (InstanceInvokeExpr) actualStatement.getInvokeExpr(); - out.add(instanceInvoke.getBase()); - } - - return out; - } - - } - // TODO: re-check the sink structure!! - return Collections.emptySet(); - } -} diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/TaintAnalysisOptions.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/TaintAnalysisOptions.java index e9ba7ae..91b1c03 100644 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/TaintAnalysisOptions.java +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/TaintAnalysisOptions.java @@ -10,7 +10,7 @@ public boolean trackStrings() { } @Override - public boolean arrayFlows() { + public boolean allowMultipleQueries() { return true; } } diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/Utility.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/Utility.java index 1691801..c04454b 100644 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/Utility.java +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/internal/Utility.java @@ -4,9 +4,9 @@ import java.util.ArrayList; import java.util.List; +import boomerang.scene.WrappedClass; import de.fraunhofer.iem.secucheck.analysis.query.CompositeTaintFlowQuery; import de.fraunhofer.iem.secucheck.analysis.query.Method; -import de.fraunhofer.iem.secucheck.analysis.query.MethodImpl; import de.fraunhofer.iem.secucheck.analysis.query.TaintFlowQuery; import soot.Scene; import soot.SootClass; @@ -15,16 +15,16 @@ class Utility { - static List getMethods(CompositeTaintFlowQuery flowQuery) { - List methods = new ArrayList(); + static List getMethods(CompositeTaintFlowQuery flowQuery) { + List methods = new ArrayList<>(); for (TaintFlowQuery singleFlow: flowQuery.getTaintFlowQueries()) { methods.addAll(getMethods(singleFlow)); } return methods; } - static List getMethods(TaintFlowQuery flowQuery) { - List methods = new ArrayList(); + static List getMethods(TaintFlowQuery flowQuery) { + List methods = new ArrayList<>(); flowQuery.getFrom().forEach(y -> methods.add((Method)y)); flowQuery.getTo().forEach(y -> methods.add((Method)y)); @@ -37,7 +37,13 @@ static List getMethods(TaintFlowQuery flowQuery) { return methods; } - static SootMethod getSootMethod(Method method) { + static SootMethod getSootMethod(boomerang.scene.Method method) { + WrappedClass wrappedClass = method.getDeclaringClass(); + SootClass clazz = (SootClass) wrappedClass.getDelegate(); + return clazz.getMethod(method.getSubSignature()); + } + + static SootMethod getSootMethod(de.fraunhofer.iem.secucheck.analysis.query.Method method) { String[] signatures = method.getSignature().split(":"); SootClass sootClass = Scene.v().forceResolve(signatures[0], SootClass.BODIES); if (sootClass != null && signatures.length >= 2) { @@ -48,7 +54,7 @@ static SootMethod getSootMethod(Method method) { static SootMethod findSourceMethodDefinition(TaintFlowQuery partialFlow, SootMethod method, Stmt actualStatement) { - for (Method sourceMethod : partialFlow.getFrom()) { + for (de.fraunhofer.iem.secucheck.analysis.query.Method sourceMethod : partialFlow.getFrom()) { String sourceSootSignature = "<" + sourceMethod.getSignature() + ">"; if (method.getSignature().equals(sourceSootSignature)) { return method; @@ -62,7 +68,7 @@ static SootMethod findSourceMethodDefinition(TaintFlowQuery partialFlow, static SootMethod findSinkMethodDefinition(TaintFlowQuery partialFlow, SootMethod method, Stmt actualStatement) { - for (Method sinkMethod : partialFlow.getTo()) { + for (de.fraunhofer.iem.secucheck.analysis.query.Method sinkMethod : partialFlow.getTo()) { String sinkSootSignature = "<" + sinkMethod.getSignature() + ">"; if (actualStatement.containsInvokeExpr() && actualStatement.toString().contains(sinkSootSignature)) { diff --git a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/result/LocationDetails.java b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/result/LocationDetails.java index 0e9702f..5bd359a 100644 --- a/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/result/LocationDetails.java +++ b/de.fraunhofer.iem.secucheck.analysis/src/main/java/de/fraunhofer/iem/secucheck/analysis/result/LocationDetails.java @@ -8,8 +8,10 @@ public class LocationDetails { private String methodSignature; private String usageMethodSignature; - private int usageLineNumber; - private int usageColNumber; + private int usageStartLineNumber; + private int usageEndLineNumber; + private int usageStartColNumber; + private int usageEndColNumber; private LocationType type; @@ -23,9 +25,10 @@ public LocationDetails() { } public LocationType getType() { return type; } - public int getUsageLineNumber() { return usageLineNumber; } - public int getUsageColumnNumber() { return usageColNumber; } - + public int getUsageStartLineNumber() { return usageStartLineNumber; } + public int getUsageEndLineNumber() { return usageEndLineNumber; } + public int getUsageStartColumnNumber() { return usageStartColNumber; } + public int getUsageEndColumnNumber() { return usageEndColNumber; } public void setSourceClassName(String sourceClassName) { this.sourceClassName = sourceClassName; } public void setUsageClassName(String usageClassName) { this.usageClassName = usageClassName; } @@ -35,6 +38,8 @@ public LocationDetails() { } public void setType(LocationType type) { this.type = type; } - public void setUsageLineNumber(int usageLineNumber) { this.usageLineNumber = usageLineNumber; } - public void setUsageColumnNumber(int usageColNumber) { this.usageColNumber = usageColNumber; } + public void setUsageStartLineNumber(int usageStartLineNumber) { this.usageStartLineNumber = usageStartLineNumber; } + public void setUsageEndLineNumber(int usageEndLineNumber) { this.usageEndLineNumber = usageEndLineNumber; } + public void setUsageStartColumnNumber(int usageStartColNumber) { this.usageStartColNumber = usageStartColNumber; } + public void setUsageEndColumnNumber(int usageEndColNumber) { this.usageEndColNumber = usageEndColNumber; } } \ No newline at end of file