Skip to content

Commit

Permalink
Merge pull request #17 from CodeShield-Security/develop
Browse files Browse the repository at this point in the history
Adding testcases
  • Loading branch information
johspaeth authored Dec 11, 2020
2 parents b350f03 + dcfe3ee commit 8f3c57c
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package boomerang.flowfunction;

import boomerang.DefaultBoomerangOptions;
import boomerang.BoomerangOptions;
import boomerang.scene.ControlFlowGraph.Edge;
import boomerang.scene.Field;
import boomerang.scene.InvokeExpr;
Expand All @@ -27,9 +27,9 @@
public class DefaultBackwardFlowFunction implements IBackwardFlowFunction {

private final Strategies<Weight> strategies;
private final DefaultBoomerangOptions options;
private final BoomerangOptions options;

public DefaultBackwardFlowFunction(DefaultBoomerangOptions opts) {
public DefaultBackwardFlowFunction(BoomerangOptions opts) {
this.options = opts;
this.strategies = new Strategies<>(opts);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ protected boolean killFlow(Statement curr, Val value) {
}

@Override
public Collection<State> callToReturn(ForwardQuery query, Edge edge, Val fact) {
public Collection<State> callToReturnFlow(ForwardQuery query, Edge edge, Val fact) {
if (FlowFunctionUtils.isSystemArrayCopy(edge.getStart().getInvokeExpr().getMethod())) {
return systemArrayCopyFlow(edge, fact);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public interface IBackwardFlowFunction {
* Called by the backward analysis, when data-flow by-passes a call site with data-flow fact. Here
* logic can be added to handle native calls, or methods that are excluded from propagation.
*
* @param edge Edge that bypasses the call site. edge.getStart() is the call site,
* edge.getTarget() is the call site, edge.getStart() is any predecessor
* @param edge Edge that bypasses the call site. edge.getTarget() is the call site,
* edge.getStart() is any predecessor
* @param fact The fact that by-passes the call site.
* @return A set of data-flow states (states in the pushdown system, typically of type
* Node<Edge,Val>)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,52 @@
import wpds.interfaces.State;

public interface IForwardFlowFunction {

/**
* Called by the forward analysis, when the forward solver reaches the returnStmt (any last
* statement of callee method) of callee method with data-flow fact returnedVal.
*
* @param callee The method the data-flow analysis returns from. The caller method is not
* available, as it will be internally added by the framework.
* @param returnStmt The statement from which the method returns from (will be any last/exit
* statement of the callee method)
* @param returnedVal The data-flow fact that is returned.
* @return A set of data-flow facts (Val) which will be propagated at any call site of the callee
* method.
*/
Collection<Val> returnFlow(Method callee, Statement returnStmt, Val returnedVal);

/**
* Called by the forward analysis, when the forward solver reaches the callSite. Will be invoked
* once per available callee (in the call graph).
*
* @param callSite A call site reached by the backward analysis.
* @param factAtCallSite The data-flow fact reaching the callSite
* @param callee The callee that may be invoked at the callSite
* @return A set of data-flow facts (Val) that will be propagated at the entry statements of
* method callee
*/
Collection<Val> callFlow(Statement callSite, Val factAtCallSite, Method callee);

/**
* Called by the forward analysis, for any non return statements or call site statements.
*
* @param edge The control-flow graph edge that will be propagated next.
* @param fact The incoming data-flow fact that reaches the edge.
* @return A set of data-flow states (states in the pushdown system, typically of type
* Node<Edge,Val>).
*/
Collection<State> normalFlow(ForwardQuery query, Edge edge, Val fact);

Collection<State> callToReturn(ForwardQuery query, Edge edge, Val fact);
/**
* Called by the forward analysis, when data-flow by-passes a call site with data-flow fact. Here
* logic can be added to handle native calls, or methods that are excluded from propagation.
*
* @param edge Edge that bypasses the call site. edge.getStart() is the call site,
* edge.getTarget() is any succsessor
* @param fact The fact that by-passes the call site.
* @return A set of data-flow states (states in the pushdown system, typically of type
* Node<Edge,Val>)
*/
Collection<State> callToReturnFlow(ForwardQuery query, Edge edge, Val fact);
}
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ private void byPassFlowAtCallSite(
@Override
public void getSuccessor(Statement returnSite) {
for (State s :
flowFunctions.callToReturn(
flowFunctions.callToReturnFlow(
query, new Edge(callSite, returnSite), currNode.fact())) {
propagate(currNode, s);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package boomerang.guided;

import boomerang.BackwardQuery;
import boomerang.ForwardQuery;
import boomerang.Query;
import boomerang.scene.ControlFlowGraph.Edge;
import boomerang.scene.Statement;
import boomerang.scene.Val;
import java.util.Collection;
import java.util.Collections;

public class ArrayContainerCollectionManager implements IDemandDrivenGuidedManager {

@Override
public Collection<Query> onForwardFlow(ForwardQuery query, Edge dataFlowEdge, Val dataFlowVal) {
Statement targetStmt = dataFlowEdge.getStart();
// Any statement of type someVariable[..] = rightOp
if (targetStmt.isAssign() && targetStmt.getLeftOp().isArrayRef()) {
// If propagated fact also matches "someVariable"
if (targetStmt.getLeftOp().getArrayBase().getX().equals(dataFlowVal)) {
// Do start a new backward query for rightOp
return Collections.singleton(BackwardQuery.make(dataFlowEdge, targetStmt.getRightOp()));
}
}
return Collections.emptySet();
}

@Override
public Collection<Query> onBackwardFlow(BackwardQuery query, Edge dataFlowEdge, Val dataFlowVal) {
return Collections.emptySet();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package boomerang.guided;

import boomerang.BackwardQuery;
import boomerang.Boomerang;
import boomerang.DefaultBoomerangOptions;
import boomerang.ForwardQuery;
import boomerang.flowfunction.IBackwardFlowFunction;
import boomerang.flowfunction.IForwardFlowFunction;
import boomerang.guided.flowfunction.CustomBackwardFlowFunction;
import boomerang.guided.flowfunction.CustomForwardFlowFunction;
import boomerang.guided.targets.CustomFlowFunctionTarget;
import boomerang.results.BackwardBoomerangResults;
import boomerang.results.ForwardBoomerangResults;
import boomerang.scene.AllocVal;
import boomerang.scene.ControlFlowGraph.Edge;
import boomerang.scene.Method;
import boomerang.scene.SootDataFlowScope;
import boomerang.scene.Statement;
import boomerang.scene.Val;
import boomerang.scene.jimple.BoomerangPretransformer;
import boomerang.scene.jimple.JimpleMethod;
import boomerang.scene.jimple.SootCallGraph;
import com.google.common.collect.Lists;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import soot.G;
import soot.PackManager;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.options.Options;
import wpds.impl.Weight.NoWeight;

public class CustomFlowFunctionTest {

public static String CG = "cha";

@Test
public void killOnSystemExitBackwardTest() {
setupSoot(CustomFlowFunctionTarget.class);
SootMethod m =
Scene.v()
.getMethod(
"<boomerang.guided.targets.CustomFlowFunctionTarget: void main(java.lang.String[])>");
BackwardQuery query = selectQueryForStatement(m);

SootCallGraph sootCallGraph = new SootCallGraph();
Boomerang solver =
new Boomerang(
sootCallGraph, SootDataFlowScope.make(Scene.v()), new CustomBoomerangOptions());

System.out.println("Solving query: " + query);
BackwardBoomerangResults<NoWeight> backwardQueryResults = solver.solve(query);
System.out.println(backwardQueryResults.getAllocationSites());

// For the query no allocation site is found, as between queryFor and the allocation site there
// exists a System.exit call.
Assert.assertEquals(true, backwardQueryResults.isEmpty());
}

@Test
public void killOnSystemExitForwardTest() {
setupSoot(CustomFlowFunctionTarget.class);
SootMethod m =
Scene.v()
.getMethod(
"<boomerang.guided.targets.CustomFlowFunctionTarget: void main(java.lang.String[])>");
ForwardQuery query = selectFirstIntAssignment(m);

SootCallGraph sootCallGraph = new SootCallGraph();
Boomerang solver =
new Boomerang(
sootCallGraph, SootDataFlowScope.make(Scene.v()), new CustomBoomerangOptions());

System.out.println("Solving query: " + query);
ForwardBoomerangResults<NoWeight> res = solver.solve(query);
System.out.println(res.asStatementValWeightTable());

boolean t =
res.asStatementValWeightTable().cellSet().stream()
.map(c -> c.getRowKey().getTarget())
.anyMatch(
statement ->
statement.containsInvokeExpr()
&& statement.getInvokeExpr().getMethod().getName().equals("queryFor"));
Assert.assertEquals(false, t);
}

public static BackwardQuery selectQueryForStatement(SootMethod m) {
Method method = JimpleMethod.of(m);
method.getStatements().stream().filter(x -> x.containsInvokeExpr()).forEach(x -> x.toString());
Statement queryStatement =
method.getStatements().stream()
.filter(x -> x.containsInvokeExpr())
.filter(x -> x.getInvokeExpr().getMethod().getName().equals("queryFor"))
.findFirst()
.get();
Val arg = queryStatement.getInvokeExpr().getArg(0);

Statement predecessor =
method.getControlFlowGraph().getPredsOf(queryStatement).stream().findFirst().get();
Edge cfgEdge = new Edge(predecessor, queryStatement);
return BackwardQuery.make(cfgEdge, arg);
}

public static ForwardQuery selectFirstIntAssignment(SootMethod m) {
Method method = JimpleMethod.of(m);
method.getStatements().stream().forEach(x -> System.out.println(x.toString()));
Statement intAssignStmt =
method.getStatements().stream()
.filter(x -> x.isAssign() && !x.getLeftOp().getType().isRefType())
.findFirst()
.get();
Val arg = new AllocVal(intAssignStmt.getLeftOp(), intAssignStmt, intAssignStmt.getRightOp());

Statement succs =
method.getControlFlowGraph().getSuccsOf(intAssignStmt).stream().findFirst().get();
Edge cfgEdge = new Edge(intAssignStmt, succs);
return new ForwardQuery(cfgEdge, arg);
}

protected void setupSoot(Class cls) {
G.v().reset();
setupSoot();
setApplicationClass(cls);
PackManager.v().runPacks();
BoomerangPretransformer.v().reset();
BoomerangPretransformer.v().apply();
}

private void setupSoot() {
Options.v().set_whole_program(true);
Options.v().setPhaseOption("cg." + CG, "on");
Options.v().setPhaseOption("cg." + CG, "verbose:true");
Options.v().set_output_format(Options.output_format_none);
Options.v().set_no_bodies_for_excluded(true);
Options.v().set_allow_phantom_refs(true);
Options.v().setPhaseOption("jb", "use-original-names:true");
Options.v().set_keep_line_number(true);
Options.v().set_prepend_classpath(true);
Options.v().set_process_dir(getProcessDir());
}

private void setApplicationClass(Class cls) {
Scene.v().loadNecessaryClasses();
List<SootMethod> eps = Lists.newArrayList();
for (SootClass sootClass : Scene.v().getClasses()) {
if (sootClass.toString().equals(cls.getName())
|| (sootClass.toString().contains(cls.getName() + "$"))) {
sootClass.setApplicationClass();
eps.addAll(sootClass.getMethods());
}
}
Scene.v().setEntryPoints(eps);
}

private List<String> getProcessDir() {
Path path = Paths.get("target/test-classes");
return Lists.newArrayList(path.toAbsolutePath().toString());
}

private class CustomBoomerangOptions extends DefaultBoomerangOptions {

@Override
public IForwardFlowFunction getForwardFlowFunctions() {
return new CustomForwardFlowFunction(this);
}

@Override
public IBackwardFlowFunction getBackwardFlowFunction() {
return new CustomBackwardFlowFunction(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import boomerang.ForwardQuery;
import boomerang.Query;
import boomerang.QueryGraph;
import boomerang.guided.targets.ArrayContainerTarget;
import boomerang.guided.targets.BasicTarget;
import boomerang.guided.targets.BranchingAfterNewStringTest;
import boomerang.guided.targets.BranchingTest;
Expand Down Expand Up @@ -217,6 +218,18 @@ public void pingPongInterpoceduralTest() {
runAnalysis(getPingPongSpecification(), query, "hello", "world");
}

@Test
public void arrayContainerTest() {
setupSoot(ArrayContainerTarget.class);
SootMethod m =
Scene.v()
.getMethod(
"<boomerang.guided.targets.ArrayContainerTarget: void main(java.lang.String[])>");
BackwardQuery query = selectFirstBaseOfToString(m);

runAnalysis(new ArrayContainerCollectionManager(), query, "hello", "world");
}

private Specification getPingPongSpecification() {
return Specification.create(
"<ON{B}java.lang.StringBuilder: java.lang.StringBuilder append(GO{B}java.lang.String)>",
Expand Down Expand Up @@ -281,9 +294,14 @@ private boolean isStringOrIntAllocation(Statement stmt) {

protected void runAnalysis(
Specification specification, BackwardQuery query, Object... expectedValues) {
runAnalysis(new SimpleSpecificationGuidedManager(specification), query, expectedValues);
}

protected void runAnalysis(
IDemandDrivenGuidedManager queryManager, BackwardQuery query, Object... expectedValues) {
DemandDrivenGuidedAnalysis demandDrivenGuidedAnalysis =
new DemandDrivenGuidedAnalysis(
new SimpleSpecificationGuidedManager(specification),
queryManager,
new IntAndStringBoomerangOptions() {
@Override
public Optional<AllocVal> getAllocationVal(Method m, Statement stmt, Val fact) {
Expand Down Expand Up @@ -318,8 +336,7 @@ public boolean allowMultipleQueries() {
&& isStringOrIntAllocation(x.asNode().stmt().getStart()));
Assert.assertEquals(
Sets.newHashSet(expectedValues),
res.map(
t ->((AllocVal) t.var()).getAllocVal())
res.map(t -> ((AllocVal) t.var()).getAllocVal())
.filter(x -> x.isStringConstant() || x.isIntConstant())
.map(x -> (x.isIntConstant() ? x.getIntValue() : x.getStringValue()))
.collect(Collectors.toSet()));
Expand Down
Loading

0 comments on commit 8f3c57c

Please sign in to comment.