diff --git a/soot-infoflow-android/schema/SourcesAndSinks.xsd b/soot-infoflow-android/schema/SourcesAndSinks.xsd
index b71d54ae2..c3f217e2f 100644
--- a/soot-infoflow-android/schema/SourcesAndSinks.xsd
+++ b/soot-infoflow-android/schema/SourcesAndSinks.xsd
@@ -96,6 +96,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -109,6 +132,8 @@
+
+
diff --git a/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/AbstractXMLSourceSinkParser.java b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/AbstractXMLSourceSinkParser.java
index 34a37f8e7..874a446b3 100644
--- a/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/AbstractXMLSourceSinkParser.java
+++ b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/AbstractXMLSourceSinkParser.java
@@ -24,6 +24,8 @@
import soot.jimple.infoflow.android.data.AndroidMethod;
import soot.jimple.infoflow.android.data.CategoryDefinition;
import soot.jimple.infoflow.data.AbstractMethodAndClass;
+import soot.jimple.infoflow.data.ValueOnPath;
+import soot.jimple.infoflow.data.ValueOnPath.Parameter;
import soot.jimple.infoflow.river.conditions.SignatureFlowCondition;
import soot.jimple.infoflow.sourcesSinks.definitions.AccessPathTuple;
import soot.jimple.infoflow.sourcesSinks.definitions.FieldSourceSinkDefinition;
@@ -112,11 +114,15 @@ protected class SAXHandler extends DefaultHandler {
protected ICategoryFilter categoryFilter = null;
+ private Set turnAroundPaths;
private Set signaturesOnPath = new HashSet<>();
private Set classNamesOnPath = new HashSet<>();
+ private Set valuesOnPath = new HashSet<>();
private Set excludedClassNames = new HashSet<>();
private Set conditions = new HashSet<>();
+ private ValueOnPath vop;
+ private Parameter param;
public SAXHandler() {
}
@@ -177,10 +183,18 @@ public void startElement(String uri, String localName, String qName, Attributes
handleStarttagSignatureOnPath(attributes);
break;
+ case XMLConstants.VALUE_ON_PATH_TAG:
+ handleStarttagValueOnPath(attributes);
+ break;
+
case XMLConstants.CLASS_NAME_ON_PATH_TAG:
handleStarttagClassNameOnPath(attributes);
break;
+ case XMLConstants.TURN_AROUND_TAG:
+ handleStarttagTurnAround(attributes);
+ break;
+
case XMLConstants.EXCLUDE_CLASS_NAME_TAG:
handleStarttagExcludeClassName(attributes);
break;
@@ -254,6 +268,22 @@ protected void handleStarttagAccesspath(Attributes attributes) {
}
protected void handleStarttagParam(Attributes attributes, String qNameLower) {
+ if (vop != null) {
+ String tempStr = attributes.getValue(XMLConstants.INDEX_ATTRIBUTE);
+ if (tempStr != null && !tempStr.isEmpty())
+ paramIndex = Integer.parseInt(tempStr);
+ tempStr = attributes.getValue(XMLConstants.REGEX_ATTRIBUTE);
+ boolean regex = false;
+ if (tempStr != null && !tempStr.isEmpty())
+ regex = Boolean.parseBoolean(tempStr);
+ tempStr = attributes.getValue(XMLConstants.CASE_SENSITIVE_ATTRIBUTE);
+ boolean casesensitive = false;
+ if (tempStr != null && !tempStr.isEmpty())
+ casesensitive = Boolean.parseBoolean(tempStr);
+ param = new ValueOnPath.Parameter(paramIndex, regex, casesensitive);
+ vop.add(param);
+ return;
+ }
if ((methodSignature != null || fieldSignature != null) && attributes != null) {
String tempStr = attributes.getValue(XMLConstants.INDEX_ATTRIBUTE);
if (tempStr != null && !tempStr.isEmpty())
@@ -290,6 +320,25 @@ protected void handleStarttagSignatureOnPath(Attributes attributes) {
}
}
+ protected void handleStarttagValueOnPath(Attributes attributes) {
+ String invocation = getStringAttribute(attributes, XMLConstants.INVOCATION_ATTRIBUTE);
+ if (invocation != null) {
+ if (valuesOnPath == null)
+ valuesOnPath = new HashSet<>();
+ vop = new ValueOnPath("<" + invocation + ">");
+ valuesOnPath.add(vop);
+ }
+ }
+
+ protected void handleStarttagTurnAround(Attributes attributes) {
+ String invocationName = getStringAttribute(attributes, XMLConstants.INVOCATION_ATTRIBUTE);
+ if (invocationName != null) {
+ if (turnAroundPaths == null)
+ turnAroundPaths = new HashSet<>();
+ turnAroundPaths.add(invocationName);
+ }
+ }
+
protected void handleStarttagClassNameOnPath(Attributes attributes) {
String className = getStringAttribute(attributes, XMLConstants.CLASS_NAME_ATTRIBUTE);
if (className != null) {
@@ -331,6 +380,10 @@ private String parseSignature(Attributes attributes) {
**/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
+ if (param != null) {
+ param.setContentToMatch(new String(ch, start, length));
+ param = null;
+ }
}
/**
@@ -391,15 +444,18 @@ public void endElement(String uri, String localName, String qName) throws SAXExc
accessPathParentElement = "";
paramIndex = -1;
paramTypes.clear();
+ vop = null;
+ param = null;
break;
case XMLConstants.ADDITIONAL_FLOW_CONDITION_TAG:
- if (!classNamesOnPath.isEmpty() || !signaturesOnPath.isEmpty()) {
+ if (!classNamesOnPath.isEmpty() || !signaturesOnPath.isEmpty() || !valuesOnPath.isEmpty()) {
SignatureFlowCondition additionalFlowCondition = new SignatureFlowCondition(classNamesOnPath,
- signaturesOnPath, excludedClassNames);
+ signaturesOnPath, valuesOnPath, excludedClassNames);
// Reset both for a new condition
classNamesOnPath = new HashSet<>();
signaturesOnPath = new HashSet<>();
+ valuesOnPath = new HashSet<>();
excludedClassNames = new HashSet<>();
@@ -422,7 +478,8 @@ protected void handleEndtagMethod() {
if (tempMeth != null) {
@SuppressWarnings("unchecked")
ISourceSinkDefinition ssd = createMethodSourceSinkDefinition(tempMeth, baseAPs,
- paramAPs.toArray(new Set[paramAPs.size()]), returnAPs, callType, category, conditions);
+ paramAPs.toArray(new Set[paramAPs.size()]), returnAPs, callType, category, conditions,
+ turnAroundPaths);
addSourceSinkDefinition(methodSignature, ssd);
} else {
logger.error("Invalid method signature: " + methodSignature);
@@ -431,6 +488,7 @@ protected void handleEndtagMethod() {
}
// Start a new method and discard our old data
+ turnAroundPaths = null;
methodSignature = null;
fieldSignature = null;
baseAPs = new HashSet<>();
@@ -666,23 +724,25 @@ protected abstract ISourceSinkDefinition createMethodSourceSinkDefinition(Abstra
/**
* Factory method for {@link MethodSourceSinkDefinition} instances
*
- * @param method The method that is to be defined as a source or sink
- * @param baseAPs The access paths rooted in the base object that shall be
- * considered as sources or sinks
- * @param paramAPs The access paths rooted in parameters that shall be
- * considered as sources or sinks. The index in the set
- * corresponds to the index of the formal parameter to which
- * the respective set of access paths belongs.
- * @param returnAPs The access paths rooted in the return object that shall be
- * considered as sources or sinks
- * @param callType The type of call (normal call, callback, etc.)
- * @param conditions Conditions which has to be true for the definition to be
- * valid
+ * @param method The method that is to be defined as a source or sink
+ * @param baseAPs The access paths rooted in the base object that shall
+ * be considered as sources or sinks
+ * @param paramAPs The access paths rooted in parameters that shall be
+ * considered as sources or sinks. The index in the set
+ * corresponds to the index of the formal parameter to
+ * which the respective set of access paths belongs.
+ * @param returnAPs The access paths rooted in the return object that
+ * shall be considered as sources or sinks
+ * @param callType The type of call (normal call, callback, etc.)
+ * @param conditions Conditions which has to be true for the definition to
+ * be valid
+ * @param turnAroundPaths a set of turn around path method invocations
* @return The newly created {@link MethodSourceSinkDefinition} instance
*/
protected abstract ISourceSinkDefinition createMethodSourceSinkDefinition(AbstractMethodAndClass method,
Set baseAPs, Set[] paramAPs, Set returnAPs,
- CallType callType, ISourceSinkCategory category, Set conditions);
+ CallType callType, ISourceSinkCategory category, Set conditions,
+ Set turnAroundPaths);
/**
* Reads the method or field signature from the given attribute map
diff --git a/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLConstants.java b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLConstants.java
index b85af5c66..422d1cafb 100644
--- a/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLConstants.java
+++ b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLConstants.java
@@ -18,13 +18,16 @@ public class XMLConstants {
public static final String ACCESSPATH_TAG = "accesspath";
public static final String PATHELEMENT_TAG = "pathelement";
public static final String ADDITIONAL_FLOW_CONDITION_TAG = "additionalflowcondition";
+ public static final String TURN_AROUND_TAG = "turnaround";
public static final String SIGNATURE_ON_PATH_TAG = "signatureonpath";
+ public static final String VALUE_ON_PATH_TAG = "valueonpath";
public static final String CLASS_NAME_ON_PATH_TAG = "classnameonpath";
public static final String CLASS_NAME_ATTRIBUTE = "className";
public static final String EXCLUDE_CLASS_NAME_TAG = "excludeclassname";
public static final String ID_ATTRIBUTE = "id";
public static final String SIGNATURE_ATTRIBUTE = "signature";
+ public static final String INVOCATION_ATTRIBUTE = "invocation";
public static final String CALL_TYPE = "callType";
public static final String TYPE_ATTRIBUTE = "type";
public static final String INDEX_ATTRIBUTE = "index";
@@ -33,6 +36,8 @@ public class XMLConstants {
public static final String LENGTH_ATTRIBUTE = "length";
public static final String FIELD_ATTRIBUTE = "field";
public static final String DESCRIPTION_ATTRIBUTE = "description";
+ public static final String REGEX_ATTRIBUTE = "regex";
+ public static final String CASE_SENSITIVE_ATTRIBUTE = "caseSensitive";
public static final String TRUE = "true";
diff --git a/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLSourceSinkParser.java b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLSourceSinkParser.java
index 62e5ba3ef..d92fc2df0 100644
--- a/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLSourceSinkParser.java
+++ b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/XMLSourceSinkParser.java
@@ -212,13 +212,17 @@ protected ISourceSinkDefinition createMethodSourceSinkDefinition(AbstractMethodA
return null;
}
+ @Override
protected ISourceSinkDefinition createMethodSourceSinkDefinition(AbstractMethodAndClass method,
Set baseAPs, Set[] paramAPs, Set returnAPs,
- CallType callType, ISourceSinkCategory category, Set conditions) {
+ CallType callType, ISourceSinkCategory category, Set conditions,
+ Set turnAround) {
ISourceSinkDefinition ssdef = createMethodSourceSinkDefinition(method, baseAPs, paramAPs, returnAPs, callType,
category);
if (ssdef != null)
ssdef.setConditions(conditions);
+ if (turnAround != null)
+ ssdef.setTurnArounds(turnAround);
return ssdef;
}
diff --git a/soot-infoflow-cmd/schema/SourcesAndSinks.xsd b/soot-infoflow-cmd/schema/SourcesAndSinks.xsd
index 6e7719332..c3f217e2f 100644
--- a/soot-infoflow-cmd/schema/SourcesAndSinks.xsd
+++ b/soot-infoflow-cmd/schema/SourcesAndSinks.xsd
@@ -50,6 +50,7 @@
+
@@ -95,6 +96,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -108,9 +132,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/handler/SummaryTaintPropagationHandler.java b/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/handler/SummaryTaintPropagationHandler.java
index f47f49e19..39bde6ff4 100644
--- a/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/handler/SummaryTaintPropagationHandler.java
+++ b/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/handler/SummaryTaintPropagationHandler.java
@@ -16,6 +16,7 @@
import soot.jimple.infoflow.handlers.TaintPropagationHandler;
import soot.jimple.infoflow.methodSummary.generator.gaps.GapManager;
import soot.jimple.infoflow.methodSummary.generator.gaps.IGapManager;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
import soot.jimple.infoflow.solver.cfg.IInfoflowCFG;
import soot.util.ConcurrentHashMultiMap;
import soot.util.MultiMap;
@@ -201,7 +202,7 @@ protected void addResult(Abstraction abs, Stmt stmt) {
@Override
public boolean notifyFlowOut(Unit u, Abstraction d1, Abstraction incoming, Set outgoing,
- InfoflowManager manager, FlowFunctionType type) {
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
// Do not propagate through excluded methods
SootMethod sm = manager.getICFG().getMethodOf(u);
if (excludedMethods.contains(sm)) {
diff --git a/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/xml/SummaryReader.java b/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/xml/SummaryReader.java
index a1a4353e7..a62cb3ceb 100644
--- a/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/xml/SummaryReader.java
+++ b/soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/xml/SummaryReader.java
@@ -28,6 +28,7 @@
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import soot.Scene;
import soot.jimple.infoflow.collections.data.IndexConstraint;
import soot.jimple.infoflow.collections.data.KeyConstraint;
import soot.jimple.infoflow.methodSummary.data.sourceSink.ConstraintType;
@@ -57,7 +58,7 @@ private enum State {
}
/**
- * It takes quite a while to create a new XML Input Factory
+ * It takes quite a while to create a new XML Input Factory
*/
private static class CachedFactory {
WeakReference thread;
@@ -93,7 +94,7 @@ public void read(Reader reader, ClassMethodSummaries summaries)
throws XMLStreamException, SummaryXMLException, IOException {
XMLStreamReader xmlreader = null;
try {
- //Sadly, the XML Input Factory is not thread safe :/
+ // Sadly, the XML Input Factory is not thread safe :/
CachedFactory cachedFact = cachedFactory;
if (cachedFact == null || !cachedFact.isValidForThisThread()) {
cachedFact = new CachedFactory();
@@ -555,7 +556,10 @@ private String[] getAccessPath(Map attributes) {
String ap = attributes.get(XMLConstants.ATTRIBUTE_ACCESSPATH);
if (ap != null) {
if (ap.length() > 3) {
- String[] res = ap.substring(1, ap.length() - 1).split(",");
+ String apR = ap;
+ if (ap.startsWith("[") && ap.endsWith("]"))
+ apR = ap.substring(1, ap.length() - 1);
+ String[] res = apR.split(",");
for (int i = 0; i < res.length; i++) {
String curElement = res[i].trim();
@@ -578,13 +582,28 @@ private String[] getAccessPathTypes(Map attributes) {
String ap = attributes.get(XMLConstants.ATTRIBUTE_ACCESSPATHTYPES);
if (ap != null) {
if (ap.length() > 3) {
- String[] res = ap.substring(1, ap.length() - 1).split(",");
+ String apR = ap;
+ if (ap.startsWith("[") && ap.endsWith("]"))
+ apR = ap.substring(1, ap.length() - 1);
+ String[] res = apR.split(",");
for (int i = 0; i < res.length; i++)
res[i] = res[i].trim();
return res;
}
+ return null;
+ } else {
+ // infer the access path types as default behavior
+ String[] a = getAccessPath(attributes);
+ if (a == null)
+ return null;
+ String[] res = new String[a.length];
+ for (int i = 0; i < res.length; i++) {
+ String subsig = Scene.signatureToSubsignature(a[i]);
+ String fieldType = subsig.substring(0, subsig.indexOf(" "));
+ res[i] = fieldType;
+ }
+ return res;
}
- return null;
}
private boolean isMatchStrict(Map attributes) {
diff --git a/soot-infoflow-summaries/summariesManual/android.net.Uri.xml b/soot-infoflow-summaries/summariesManual/android.net.Uri.xml
index 8a13d2e74..82fc3e268 100644
--- a/soot-infoflow-summaries/summariesManual/android.net.Uri.xml
+++ b/soot-infoflow-summaries/summariesManual/android.net.Uri.xml
@@ -323,5 +323,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/soot-infoflow/pom.xml b/soot-infoflow/pom.xml
index 496a2afbc..9bb94e131 100644
--- a/soot-infoflow/pom.xml
+++ b/soot-infoflow/pom.xml
@@ -157,12 +157,6 @@
7.0.2
test
-
- io.agentscope
- agentscope
- 1.0.9
- compile
-
diff --git a/soot-infoflow/src/soot/jimple/infoflow/AbstractInfoflow.java b/soot-infoflow/src/soot/jimple/infoflow/AbstractInfoflow.java
index 09f2dba07..a75338f1f 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/AbstractInfoflow.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/AbstractInfoflow.java
@@ -126,6 +126,7 @@
import soot.jimple.infoflow.river.IUsageContextProvider;
import soot.jimple.infoflow.river.SecondaryFlowGenerator;
import soot.jimple.infoflow.river.SecondaryFlowListener;
+import soot.jimple.infoflow.river.TurnAroundFlowGenerator;
import soot.jimple.infoflow.solver.DefaultSolverPeerGroup;
import soot.jimple.infoflow.solver.IInfoflowSolver;
import soot.jimple.infoflow.solver.ISolverPeerGroup;
@@ -667,11 +668,14 @@ private static List patchStringConcatInstruction(Stmt callSite, DynamicInv
while (uses.hasNext()) {
Value lop = assign.getLeftOp();
if (uses.next().getValue() == lop) {
- //Since FlowDroid doesn't support tracking the taint over this statement, we have a problem:
- //e.g.
- //tainted = dynamicinvoke "makeConcatWithConstants" (tainted, tainted2) ...
- //this would erroneously clear the taint on tainted
- //to avoid that, we introduce an alias before that statement and use that instead for our concatenation.
+ // Since FlowDroid doesn't support tracking the taint over this statement, we
+ // have a problem:
+ // e.g.
+ // tainted = dynamicinvoke "makeConcatWithConstants" (tainted, tainted2) ...
+ // this would erroneously clear the taint on tainted
+ // to avoid that, we introduce an alias before that statement and use that
+ // instead for our concatenation.
Local alias = lg.generateLocal(lop.getType());
Body body = callSite.getContainingBody();
AssignStmt assignAlias = Jimple.v().newAssignStmt(alias, lop);
@@ -964,8 +968,8 @@ protected void unsplitAllBodies() {
for (SootClass sc : Scene.v().getClasses()) {
for (SootMethod m : sc.getMethods()) {
if (m.hasActiveBody()) {
- //We could use the local packer here, but we know exactly what was being split
- //so we can be faster here
+ // We could use the local packer here, but we know exactly what was being split
+ // so we can be faster here
Body body = m.getActiveBody();
Iterator it = body.getUseAndDefBoxesIterator();
while (it.hasNext()) {
@@ -987,9 +991,9 @@ protected void unsplitAllBodies() {
}
}
- //With newer soot versions, locals are reused more often, which
- //can be a problem for FlowDroid. So, we split the locals prior to
- //running FlowDroid.
+ // With newer soot versions, locals are reused more often, which
+ // can be a problem for FlowDroid. So, we split the locals prior to
+ // running FlowDroid.
protected void splitAllBodies(Iterator extends MethodOrMethodContext> it) {
FlowDroidLocalSplitter splitter = getLocalSplitter();
while (it.hasNext()) {
@@ -1132,6 +1136,8 @@ public Thread newThread(Runnable r) {
if (config.getAdditionalFlowsEnabled()) {
// Add the SecondaryFlowGenerator to the main forward taint analysis
TaintPropagationHandler forwardHandler = forwardProblem.getTaintPropagationHandler();
+ // TODO:
+ forwardHandler = new SecondaryFlowListener();
if (forwardHandler != null) {
if (forwardHandler instanceof SequentialTaintPropagationHandler) {
((SequentialTaintPropagationHandler) forwardHandler).addHandler(new SecondaryFlowGenerator());
@@ -1165,7 +1171,10 @@ public Thread newThread(Runnable r) {
memoryWatcher.addSolver((IMemoryBoundedSolver) additionalSolver);
// Set all handlers to the additional problem
- additionalProblem.setTaintPropagationHandler(new SecondaryFlowListener());
+ SequentialTaintPropagationHandler seqTpg = new SequentialTaintPropagationHandler();
+ seqTpg.addHandler(new SecondaryFlowListener());
+ seqTpg.addHandler(new TurnAroundFlowGenerator(forwardSolver));
+ additionalProblem.setTaintPropagationHandler(seqTpg);
additionalProblem.setTaintWrapper(taintWrapper);
additionalNativeCallHandler = new BackwardNativeCallHandler();
additionalProblem.setNativeCallHandler(additionalNativeCallHandler);
@@ -1891,6 +1900,11 @@ private int scanMethodForSourcesSinks(final ISourceSinkManager sourcesSinks, Abs
s.addTag(FlowDroidSinkStatement.INSTANCE);
if (getConfig().getLogSourcesAndSinks())
collectedSinks.add(s);
+ for (ISourceSinkDefinition def : sos.sinkInfo.getDefinitions()) {
+ if (def.getTurnArounds() != null) {
+ sourcesSinks.addTurnArounds(def.getTurnArounds());
+ }
+ }
sinkCount++;
break;
case BOTH:
diff --git a/soot-infoflow/src/soot/jimple/infoflow/collections/strategies/widening/WideningTaintPropagationHandler.java b/soot-infoflow/src/soot/jimple/infoflow/collections/strategies/widening/WideningTaintPropagationHandler.java
index 6629e7260..6c3cd1ecf 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/collections/strategies/widening/WideningTaintPropagationHandler.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/collections/strategies/widening/WideningTaintPropagationHandler.java
@@ -10,6 +10,7 @@
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.Abstraction;
import soot.jimple.infoflow.handlers.TaintPropagationHandler;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
/**
* Widening through a taint propagation handler. Because of the nature, a full
@@ -40,7 +41,7 @@ public void notifyFlowIn(Unit stmt, Abstraction taint, InfoflowManager manager,
@Override
public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing,
- InfoflowManager manager, FlowFunctionType type) {
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
if (type != FlowFunctionType.CallToReturnFlowFunction)
return false;
diff --git a/soot-infoflow/src/soot/jimple/infoflow/data/ValueOnPath.java b/soot-infoflow/src/soot/jimple/infoflow/data/ValueOnPath.java
new file mode 100644
index 000000000..bda6b0d2f
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/data/ValueOnPath.java
@@ -0,0 +1,107 @@
+package soot.jimple.infoflow.data;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+public class ValueOnPath {
+
+ public static class Parameter {
+
+ private int paramIdx;
+ private boolean regex, casesensitive;
+ private String value;
+ private Pattern matcher;
+
+ public Parameter(int paramIndex, boolean regex, boolean casesensitive) {
+ this.paramIdx = paramIndex;
+ this.regex = regex;
+ this.casesensitive = casesensitive;
+ }
+
+ public int getParameterIndex() {
+ return paramIdx;
+ }
+
+ public boolean isRegex() {
+ return regex;
+ }
+
+ public boolean isCaseSensitive() {
+ return casesensitive;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(casesensitive, paramIdx, regex, value);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Parameter other = (Parameter) obj;
+ return casesensitive == other.casesensitive && paramIdx == other.paramIdx && regex == other.regex
+ && Objects.equals(value, other.value);
+ }
+
+ public void setContentToMatch(String str) {
+ this.value = str;
+ }
+
+ public String getContentToMatch() {
+ return value;
+ }
+
+ public Pattern getRegexMatcher() {
+ if (matcher == null)
+ matcher = Pattern.compile(value, isCaseSensitive() ? 0 : Pattern.CASE_INSENSITIVE);
+ return matcher;
+ }
+
+ }
+
+ private String invocation;
+ private Set parameters;
+
+ public ValueOnPath(String inv) {
+ this.invocation = inv;
+ }
+
+ public String getInvocation() {
+ return invocation;
+ }
+
+ public void add(Parameter parameter) {
+ if (parameters == null)
+ parameters = new HashSet<>();
+ parameters.add(parameter);
+ }
+
+ public Set getParameters() {
+ return parameters;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(invocation, parameters);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ValueOnPath other = (ValueOnPath) obj;
+ return Objects.equals(invocation, other.invocation) && Objects.equals(parameters, other.parameters);
+ }
+
+}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/handlers/SequentialTaintPropagationHandler.java b/soot-infoflow/src/soot/jimple/infoflow/handlers/SequentialTaintPropagationHandler.java
index f64cbd586..68c2a718b 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/handlers/SequentialTaintPropagationHandler.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/handlers/SequentialTaintPropagationHandler.java
@@ -7,6 +7,7 @@
import soot.Unit;
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.Abstraction;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
/**
* Taint propagation handler that processes a sequence of inner handlers. For
@@ -63,13 +64,13 @@ public void notifyFlowIn(Unit stmt, Abstraction taint, InfoflowManager manager,
@Override
public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing,
- InfoflowManager manager, FlowFunctionType type) {
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
if (innerHandlers.isEmpty())
return false;
boolean killed = false;
for (TaintPropagationHandler handler : innerHandlers) {
- if (handler.notifyFlowOut(stmt, d1, incoming, outgoing, manager, type))
+ if (handler.notifyFlowOut(stmt, d1, incoming, outgoing, manager, results, type))
killed = true;
}
return killed;
diff --git a/soot-infoflow/src/soot/jimple/infoflow/handlers/TaintPropagationHandler.java b/soot-infoflow/src/soot/jimple/infoflow/handlers/TaintPropagationHandler.java
index a3e981fc3..f1ac720ea 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/handlers/TaintPropagationHandler.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/handlers/TaintPropagationHandler.java
@@ -5,6 +5,7 @@
import soot.Unit;
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.Abstraction;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
/**
* Handler interface for callbacks during taint propagation
@@ -25,14 +26,10 @@ public enum FlowFunctionType {
* Handler function that is invoked when a taint is proagated in the data flow
* engine
*
- * @param stmt
- * The statement over which the taint is propagated
- * @param taint
- * The taint being propagated
- * @param manager
- * The manager object that gives access to the data flow engine
- * @param type
- * The type of data flow edge being processed
+ * @param stmt The statement over which the taint is propagated
+ * @param taint The taint being propagated
+ * @param manager The manager object that gives access to the data flow engine
+ * @param type The type of data flow edge being processed
*/
public void notifyFlowIn(Unit stmt, Abstraction taint, InfoflowManager manager, FlowFunctionType type);
@@ -40,22 +37,17 @@ public enum FlowFunctionType {
* Handler function that is invoked when a new taint is generated in the data
* flow engine
*
- * @param stmt
- * The statement over which the taint is propagated
- * @param d1
- * The abstraction at the beginning of the current method
- * @param incoming
- * The original abstraction from which the outgoing ones were
- * computed
- * @param outgoing
- * The set of taints being propagated
- * @param manager
- * The manager object that gives access to the data flow engine
- * @param type
- * The type of data flow edge being processed
+ * @param stmt The statement over which the taint is propagated
+ * @param d1 The abstraction at the beginning of the current method
+ * @param incoming The original abstraction from which the outgoing ones were
+ * computed
+ * @param outgoing The set of taints being propagated
+ * @param manager The manager object that gives access to the data flow engine
+ * @param results The results object
+ * @param type The type of data flow edge being processed
* @return Whether to kill the outgoing set
*/
public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing,
- InfoflowManager manager, FlowFunctionType type);
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type);
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/problems/AbstractInfoflowProblem.java b/soot-infoflow/src/soot/jimple/infoflow/problems/AbstractInfoflowProblem.java
index 07b1fc387..4917b85af 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/problems/AbstractInfoflowProblem.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/problems/AbstractInfoflowProblem.java
@@ -320,7 +320,8 @@ protected boolean isExceptionHandler(Unit u) {
protected Set notifyOutFlowHandlers(Unit stmt, Abstraction d1, Abstraction incoming,
Set outgoing, FlowFunctionType functionType) {
if (taintPropagationHandler != null && outgoing != null && !outgoing.isEmpty()) {
- boolean res = taintPropagationHandler.notifyFlowOut(stmt, d1, incoming, outgoing, manager, functionType);
+ boolean res = taintPropagationHandler.notifyFlowOut(stmt, d1, incoming, outgoing, manager, results,
+ functionType);
if (res)
return null;
}
@@ -387,10 +388,11 @@ public PropagationRuleManager getPropagationRules() {
}
/**
- * Checks whether the arguments of a given invoke expression
- * has a reference to a given base object while ignoring the given index
- * @param e the invoke expr
- * @param actualBase the base to look for
+ * Checks whether the arguments of a given invoke expression has a reference to
+ * a given base object while ignoring the given index
+ *
+ * @param e the invoke expr
+ * @param actualBase the base to look for
* @param ignoreIndex the index to ignore
* @return true if there is another reference
*/
diff --git a/soot-infoflow/src/soot/jimple/infoflow/problems/rules/forward/SinkPropagationRule.java b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/forward/SinkPropagationRule.java
index c4039b3cc..82f40f314 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/problems/rules/forward/SinkPropagationRule.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/forward/SinkPropagationRule.java
@@ -1,6 +1,7 @@
package soot.jimple.infoflow.problems.rules.forward;
import java.util.Collection;
+import java.util.Collections;
import soot.SootMethod;
import soot.Value;
@@ -17,6 +18,8 @@
import soot.jimple.infoflow.data.AbstractionAtSink;
import soot.jimple.infoflow.data.AccessPath;
import soot.jimple.infoflow.problems.rules.AbstractTaintPropagationRule;
+import soot.jimple.infoflow.river.IAdditionalFlowSinkPropagationRule;
+import soot.jimple.infoflow.river.SecondarySinkDefinition;
import soot.jimple.infoflow.sourcesSinks.manager.ISourceSinkManager;
import soot.jimple.infoflow.sourcesSinks.manager.SinkInfo;
import soot.jimple.infoflow.util.BaseSelector;
@@ -27,7 +30,7 @@
*
* @author Steven Arzt
*/
-public class SinkPropagationRule extends AbstractTaintPropagationRule {
+public class SinkPropagationRule extends AbstractTaintPropagationRule implements IAdditionalFlowSinkPropagationRule {
private boolean killState = false;
@@ -185,7 +188,8 @@ public Collection propagateReturnFlow(Collection calle
/**
* Registers a taint result
- * @param sinkInfo information about the sink (must not be null)
+ *
+ * @param sinkInfo information about the sink (must not be null)
* @param abstractionAtSink the abstraction at sink (must not be null)
*/
protected void registerTaintResult(SinkInfo sinkInfo, AbstractionAtSink abstractionAtSink) {
@@ -198,4 +202,19 @@ protected void setKillState() {
killState = true;
}
+ @Override
+ public void processSecondaryFlowSink(Abstraction d1, Abstraction source, Stmt stmt) {
+ // Static fields are not part of the conditional flow model.
+ if (!source.isAbstractionActive() || source.getAccessPath().isStaticFieldRef())
+ return;
+
+ // Only proceed if stmt could influence the taint
+ if (!stmt.containsInvokeExpr() || !isTaintVisibleInCallee(stmt, source))
+ return;
+
+ getResults().addResult(
+ new AbstractionAtSink(Collections.singleton(SecondarySinkDefinition.INSTANCE), source, stmt));
+
+ }
+
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowPostProcessor.java b/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowPostProcessor.java
index c23747e59..7690dffc7 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowPostProcessor.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowPostProcessor.java
@@ -43,7 +43,7 @@ public InfoflowResults onResultsAvailable(InfoflowResults results, IInfoflowCFG
// One of the conditions must match. Within both, a class name and a signature
// must match.
if (conditions != null && !conditions.isEmpty()
- && conditions.stream().noneMatch(cond -> cond.evaluate(dfRes, results)))
+ && conditions.stream().noneMatch(cond -> cond.evaluate(dfRes, results, manager)))
tbr.add(dfRes.getSink());
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowSourceSinkManagerWrapper.java b/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowSourceSinkManagerWrapper.java
index e38a79271..63e5be5a8 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowSourceSinkManagerWrapper.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowSourceSinkManagerWrapper.java
@@ -5,64 +5,71 @@
import soot.jimple.Stmt;
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.AccessPath;
-import soot.jimple.infoflow.sourcesSinks.manager.*;
+import soot.jimple.infoflow.sourcesSinks.manager.IReversibleSourceSinkManager;
+import soot.jimple.infoflow.sourcesSinks.manager.SinkInfo;
+import soot.jimple.infoflow.sourcesSinks.manager.SourceInfo;
/**
- * Wraps a SourceSinkManager and only redirects calls to methods of IConditionalFlowManager
- * to the wrapped SourceSinkManager.
- * Provide this to the Additional Flow such that it knows the conditions but doesn't accept sources.
+ * Wraps a SourceSinkManager and only redirects calls to methods of
+ * IConditionalFlowManager to the wrapped SourceSinkManager. Provide this to the
+ * Additional Flow such that it knows the conditions but doesn't accept sources.
*
* @author Tim Lange
*/
public class ConditionalFlowSourceSinkManagerWrapper implements IReversibleSourceSinkManager, IConditionalFlowManager {
- private final IConditionalFlowManager inner;
+ private final IConditionalFlowManager inner;
- public ConditionalFlowSourceSinkManagerWrapper(IConditionalFlowManager inner) {
- this.inner = inner;
- }
+ public ConditionalFlowSourceSinkManagerWrapper(IConditionalFlowManager inner) {
+ this.inner = inner;
+ }
- @Override
- public boolean isSecondarySink(Stmt stmt) {
- return inner.isSecondarySink(stmt);
- }
+ @Override
+ public boolean isSecondarySink(Stmt stmt) {
+ return inner.isSecondarySink(stmt);
+ }
- @Override
- public void registerSecondarySink(Stmt stmt) {
- // NO-OP
- }
+ @Override
+ public void registerSecondarySink(Stmt stmt) {
+ // NO-OP
+ }
- @Override
- public void registerSecondarySink(SootMethod sm) {
- // NO-OP
- }
+ @Override
+ public void registerSecondarySink(SootMethod sm) {
+ // NO-OP
+ }
- @Override
- public boolean isConditionalSink(Stmt stmt, SootClass baseClass) {
- return inner.isConditionalSink(stmt, baseClass);
- }
+ @Override
+ public boolean isConditionalSink(Stmt stmt, SootClass baseClass) {
+ return inner.isConditionalSink(stmt, baseClass);
+ }
- @Override
- public void initialize() {
- // NO-OP
- }
+ @Override
+ public boolean isTurnAroundPoint(SootMethod method) {
+ return inner.isTurnAroundPoint(method);
+ }
- @Override
- public SourceInfo getSourceInfo(Stmt sCallSite, InfoflowManager manager) {
- return null;
- }
+ @Override
+ public void initialize() {
+ // NO-OP
+ }
- @Override
- public SinkInfo getSinkInfo(Stmt sCallSite, InfoflowManager manager, AccessPath ap) {
- return null;
- }
+ @Override
+ public SourceInfo getSourceInfo(Stmt sCallSite, InfoflowManager manager) {
+ return null;
+ }
- @Override
- public SinkInfo getInverseSourceInfo(Stmt sCallSite, InfoflowManager manager, AccessPath ap) {
- return null;
- }
+ @Override
+ public SinkInfo getSinkInfo(Stmt sCallSite, InfoflowManager manager, AccessPath ap) {
+ return null;
+ }
- @Override
- public SourceInfo getInverseSinkInfo(Stmt sCallSite, InfoflowManager manager) {
- return null;
- }
+ @Override
+ public SinkInfo getInverseSourceInfo(Stmt sCallSite, InfoflowManager manager, AccessPath ap) {
+ return null;
+ }
+
+ @Override
+ public SourceInfo getInverseSinkInfo(Stmt sCallSite, InfoflowManager manager) {
+ return null;
+ }
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalSecondarySourceDefinition.java b/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalSecondarySourceDefinition.java
index 8c74bc8f9..fb4a68a02 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalSecondarySourceDefinition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalSecondarySourceDefinition.java
@@ -12,10 +12,6 @@
public class ConditionalSecondarySourceDefinition extends AbstractSourceSinkDefinition {
public static ConditionalSecondarySourceDefinition INSTANCE = new ConditionalSecondarySourceDefinition();
- private ConditionalSecondarySourceDefinition() {
- //
- }
-
@Override
public ISourceSinkDefinition getSourceOnlyDefinition() {
return null;
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java b/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java
index e110bd6e0..8d6c3a2ca 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java
@@ -5,41 +5,52 @@
import soot.jimple.Stmt;
/**
- * A source sink manager that is able to manage sinks with conditions, i.e. the sink context.
+ * A source sink manager that is able to manage sinks with conditions, i.e. the
+ * sink context.
*
* @author Tim Lange
*/
public interface IConditionalFlowManager {
- /**
- * Checks if a sink is reached in the secondary flow
- *
- * @param stmt Sink Statement
- * @return true if stmt is a secondary sink
- */
- boolean isSecondarySink(Stmt stmt);
+ /**
+ * Checks if a sink is reached in the secondary flow
+ *
+ * @param stmt Sink Statement
+ * @return true if stmt is a secondary sink
+ */
+ boolean isSecondarySink(Stmt stmt);
- /**
- * Checks whether stmt is a conditional sink and needs a secondary flow.
- * Ensures that the statement contains a InstanceInvokeExpr.
- *
- * @param stmt Sink Statement
- * @param baseClass Class of the tainted base
- * @return true if stmt is a conditional sink
- */
- boolean isConditionalSink(Stmt stmt, SootClass baseClass);
+ /**
+ * Checks whether stmt is a conditional sink and needs a secondary flow. Ensures
+ * that the statement contains a InstanceInvokeExpr.
+ *
+ * @param stmt Sink Statement
+ * @param baseClass Class of the tainted base
+ * @return true if stmt is a conditional sink
+ */
+ boolean isConditionalSink(Stmt stmt, SootClass baseClass);
- /**
- * Register a secondary sink at runtime.
- *
- * @param stmt Secondary sink statement
- */
- void registerSecondarySink(Stmt stmt);
+ /**
+ * Register a secondary sink at runtime.
+ *
+ * @param stmt Secondary sink statement
+ */
+ void registerSecondarySink(Stmt stmt);
- /**
- * Register a secondary sink at runtime.
- *
- * @param sm Secondary sink method
- */
- void registerSecondarySink(SootMethod sm);
+ /**
+ * Register a secondary sink at runtime.
+ *
+ * @param sm Secondary sink method
+ */
+ void registerSecondarySink(SootMethod sm);
+
+ /**
+ * Checks whether a called soot method is considered a turnaround point by any
+ * sink
+ *
+ * @param method the method
+ * @return true when the called soot method is considered a turnaround point by
+ * any sink
+ */
+ public boolean isTurnAroundPoint(SootMethod method);
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java b/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java
index aae6fdd0a..cef8b5820 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java
@@ -7,14 +7,13 @@
import heros.solver.PathEdge;
import soot.RefType;
import soot.Unit;
-import soot.Value;
-import soot.ValueBox;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.Abstraction;
import soot.jimple.infoflow.data.AccessPath;
import soot.jimple.infoflow.handlers.TaintPropagationHandler;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.manager.ISourceSinkManager;
@@ -56,13 +55,13 @@ public void notifyFlowIn(Unit stmt, Abstraction taint, InfoflowManager manager,
@Override
public boolean notifyFlowOut(Unit unit, Abstraction d1, Abstraction incoming, Set outgoing,
- InfoflowManager manager, FlowFunctionType type) {
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
// We only need to handle CallToReturn edges
if (type != FlowFunctionType.CallToReturnFlowFunction)
return false;
// Check whether any use matches the incoming taint
- if (!isReadAt(unit, incoming.getAccessPath()))
+ if (!Utils.isReadAt(unit, incoming.getAccessPath()))
return false;
ensureCondFlowManager(manager);
@@ -72,7 +71,8 @@ public boolean notifyFlowOut(Unit unit, Abstraction d1, Abstraction incoming, Se
// Check for sink contexts
if (stmt.containsInvokeExpr() && stmt.getInvokeExpr() instanceof InstanceInvokeExpr) {
- Abstraction baseTaint = getTaintFromLocal(outgoing, ((InstanceInvokeExpr) stmt.getInvokeExpr()).getBase());
+ Abstraction baseTaint = Utils.getTaintFromLocal(outgoing,
+ ((InstanceInvokeExpr) stmt.getInvokeExpr()).getBase());
// Is the base tainted in the outgoing set?
if (baseTaint != null && baseTaint.getAccessPath().getBaseType() instanceof RefType) {
@@ -92,6 +92,7 @@ public boolean notifyFlowOut(Unit unit, Abstraction d1, Abstraction incoming, Se
// Query the backward analysis
for (Abstraction addAbs : additionalAbsSet)
for (Unit pred : manager.getICFG().getPredsOf(unit))
+ // from forwards to backwards analysis
manager.additionalManager.getMainSolver().processEdge(new PathEdge<>(d1, pred, addAbs));
return false;
}
@@ -100,7 +101,7 @@ public boolean notifyFlowOut(Unit unit, Abstraction d1, Abstraction incoming, Se
* Creates a new abstraction that is injected into the backward direction.
*
* @param baseTaint Taint of the base local
- * @param stmt Current statement
+ * @param stmt Current statement
* @return New abstraction
*/
protected Abstraction createAdditionalFlowAbstraction(Abstraction baseTaint, Stmt stmt) {
@@ -115,8 +116,8 @@ protected Abstraction createAdditionalFlowAbstraction(Abstraction baseTaint, Stm
/**
* Creates a new abstraction that is injected into the backward direction.
*
- * @param spec Flow Specification
- * @param stmt Current statement
+ * @param spec Flow Specification
+ * @param stmt Current statement
* @param manager Infoflow Manager
* @return New abstraction
*/
@@ -130,34 +131,4 @@ protected Abstraction createAdditionalFlowAbstraction(AdditionalFlowInfoSpecific
return newAbs.deriveNewAbstractionWithTurnUnit(stmt);
}
- /**
- * Check whether baseLocal is tainted in the outgoing set.
- * Assumes baseLocal is an object and the check happens at a call site.
- *
- * @param outgoing outgoing taint set
- * @param baseLocal base local
- * @return corresponding abstraction if baseLocal is tainted else null
- */
- protected Abstraction getTaintFromLocal(Set outgoing, Value baseLocal) {
- for (Abstraction abs : outgoing)
- if (abs.getAccessPath().getPlainValue() == baseLocal)
- return abs;
-
- return null;
- }
-
- /**
- * Check whether the access path is read at unit.
- *
- * @param unit unit
- * @param ap access path
- * @return true if ap is read at unit
- */
- protected boolean isReadAt(Unit unit, AccessPath ap) {
- for (ValueBox box : unit.getUseBoxes())
- if (box.getValue() == ap.getPlainValue())
- return true;
-
- return false;
- }
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowListener.java b/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowListener.java
index 33d08f26d..af4409962 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowListener.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowListener.java
@@ -7,6 +7,7 @@
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.Abstraction;
import soot.jimple.infoflow.handlers.TaintPropagationHandler;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
import soot.jimple.infoflow.problems.rules.ITaintPropagationRule;
import soot.jimple.infoflow.problems.rules.PropagationRuleManager;
@@ -61,7 +62,7 @@ public void notifyFlowIn(Unit unit, Abstraction incoming, InfoflowManager manage
@Override
public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing,
- InfoflowManager manager, FlowFunctionType type) {
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
// NO-OP
return false;
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/SecondarySinkDefinition.java b/soot-infoflow/src/soot/jimple/infoflow/river/SecondarySinkDefinition.java
index f4525c71e..ea55ebf0e 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/SecondarySinkDefinition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/SecondarySinkDefinition.java
@@ -17,10 +17,6 @@ public class SecondarySinkDefinition extends AbstractSourceSinkDefinition {
public static final SecondarySinkDefinition INSTANCE = new SecondarySinkDefinition();
- private SecondarySinkDefinition() {
- //
- }
-
@Override
public ISourceSinkDefinition getSourceOnlyDefinition() {
return null;
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundFlowGenerator.java b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundFlowGenerator.java
new file mode 100644
index 000000000..c3b981739
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundFlowGenerator.java
@@ -0,0 +1,110 @@
+package soot.jimple.infoflow.river;
+
+import java.util.Collections;
+import java.util.Set;
+
+import heros.solver.PathEdge;
+import soot.RefType;
+import soot.Unit;
+import soot.jimple.InstanceInvokeExpr;
+import soot.jimple.Stmt;
+import soot.jimple.infoflow.InfoflowManager;
+import soot.jimple.infoflow.data.Abstraction;
+import soot.jimple.infoflow.data.AbstractionAtSink;
+import soot.jimple.infoflow.handlers.TaintPropagationHandler;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
+import soot.jimple.infoflow.solver.IInfoflowSolver;
+import soot.jimple.infoflow.sourcesSinks.manager.ISourceSinkManager;
+
+/**
+ * TaintPropagationHandler querying the forward analysis when reaching a
+ * turnaround point. Attach to the backward analysis.
+ *
+ */
+
+public class TurnAroundFlowGenerator implements TaintPropagationHandler {
+ // SourceSinkManager that also keeps track of conditions
+ private IConditionalFlowManager condFlowManager = null;
+ private IInfoflowSolver forwardSolver;
+
+ public TurnAroundFlowGenerator(IInfoflowSolver forwardSolver) {
+ this.forwardSolver = forwardSolver;
+ }
+
+ /**
+ * Ensures the condFlowManager field is always set.
+ *
+ * @param manager Infoflow Manager
+ */
+ private void ensureCondFlowManager(InfoflowManager manager) {
+ if (condFlowManager != null)
+ return;
+
+ if (!manager.getConfig().getAdditionalFlowsEnabled())
+ throw new IllegalStateException("Additional flows are not enabled!");
+
+ ISourceSinkManager ssm = manager.getSourceSinkManager();
+ if (ssm instanceof IConditionalFlowManager) {
+ condFlowManager = (IConditionalFlowManager) ssm;
+ return;
+ }
+
+ throw new IllegalStateException("Additional Flows enabled but no ConditionalFlowManager in place!");
+ }
+
+ @Override
+ public void notifyFlowIn(Unit stmt, Abstraction taint, InfoflowManager manager, FlowFunctionType type) {
+ // NO-OP
+ }
+
+ @Override
+ public boolean notifyFlowOut(Unit unit, Abstraction d1, Abstraction incoming, Set outgoing,
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
+ // We only need to handle CallToReturn edges
+ if (type != FlowFunctionType.CallToReturnFlowFunction)
+ return false;
+
+ // Check whether any use matches the incoming taint
+ if (!Utils.isReadAt(unit, incoming.getAccessPath()))
+ return false;
+
+ ensureCondFlowManager(manager);
+
+ Stmt stmt = (Stmt) unit;
+
+ // Check for sink contexts
+ if (stmt.containsInvokeExpr() && stmt.getInvokeExpr() instanceof InstanceInvokeExpr) {
+ Abstraction baseTaint = Utils.getTaintFromLocal(outgoing, ((InstanceInvokeExpr) stmt.getInvokeExpr()).getBase());
+
+ // Is the base tainted in the outgoing set?
+ if (baseTaint != null && baseTaint.getAccessPath().getBaseType() instanceof RefType) {
+ if (manager.getSourceSinkManager().isTurnAroundPoint(stmt.getInvokeExpr().getMethod())) {
+ Abstraction newAbs = createAdditionalFlowAbstraction(baseTaint, stmt);
+ // Query the forward analysis
+ forwardSolver.processEdge(new PathEdge<>(d1, unit, newAbs));
+
+ results.addResult(new AbstractionAtSink(
+ Collections.singleton(TurnAroundSecondarySinkDefinition.INSTANCE), incoming, stmt));
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates a new abstraction that is injected into the forward direction.
+ *
+ * @param baseTaint Taint of the base local
+ * @param stmt Current statement
+ * @return New abstraction
+ */
+ protected Abstraction createAdditionalFlowAbstraction(Abstraction baseTaint, Stmt stmt) {
+ Abstraction newAbs = new Abstraction(Collections.singleton(TurnAroundSecondarySinkDefinition.INSTANCE),
+ baseTaint.getAccessPath(), stmt, null, false, false);
+ newAbs.setCorrespondingCallSite(stmt);
+ newAbs.setSourceContext(new AdditionalFlowInfoSourceContext(TurnAroundSecondarySinkDefinition.INSTANCE,
+ baseTaint.getAccessPath(), stmt));
+ return newAbs.deriveNewAbstractionWithTurnUnit(stmt);
+ }
+}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundSecondarySinkDefinition.java b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundSecondarySinkDefinition.java
new file mode 100644
index 000000000..0ad14d94d
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundSecondarySinkDefinition.java
@@ -0,0 +1,12 @@
+package soot.jimple.infoflow.river;
+
+/**
+ * This is used as a sink to denote a connection from a primary flow sink to a
+ * turnaround point.
+ *
+ * @author Marc Miltenberger
+ */
+public class TurnAroundSecondarySinkDefinition extends SecondarySinkDefinition {
+ public static TurnAroundSecondarySinkDefinition INSTANCE = new TurnAroundSecondarySinkDefinition();
+
+}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundSecondarySourceDefinition.java b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundSecondarySourceDefinition.java
new file mode 100644
index 000000000..5d06e34f2
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundSecondarySourceDefinition.java
@@ -0,0 +1,30 @@
+package soot.jimple.infoflow.river;
+
+import soot.jimple.infoflow.sourcesSinks.definitions.AbstractSourceSinkDefinition;
+import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinition;
+
+/**
+ * This is used as a source to denote a connection from a turnaround sink to a
+ * secondary sink.
+ *
+ * @author Marc Miltenberger
+ */
+public class TurnAroundSecondarySourceDefinition extends AbstractSourceSinkDefinition {
+ public static TurnAroundSecondarySourceDefinition INSTANCE = new TurnAroundSecondarySourceDefinition();
+
+ @Override
+ public ISourceSinkDefinition getSourceOnlyDefinition() {
+ return null;
+ }
+
+ @Override
+ public ISourceSinkDefinition getSinkOnlyDefinition() {
+ return null;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/Utils.java b/soot-infoflow/src/soot/jimple/infoflow/river/Utils.java
new file mode 100644
index 000000000..6c266a242
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/Utils.java
@@ -0,0 +1,46 @@
+package soot.jimple.infoflow.river;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import soot.Unit;
+import soot.Value;
+import soot.ValueBox;
+import soot.jimple.infoflow.data.Abstraction;
+import soot.jimple.infoflow.data.AccessPath;
+
+public class Utils {
+
+ /**
+ * Check whether baseLocal is tainted in the outgoing set. Assumes baseLocal is
+ * an object and the check happens at a call site.
+ *
+ * @param outgoing outgoing taint set
+ * @param baseLocal base local
+ * @return corresponding abstraction if baseLocal is tainted else null
+ */
+ public static Abstraction getTaintFromLocal(Set outgoing, Value baseLocal) {
+ for (Abstraction abs : outgoing)
+ if (abs.getAccessPath().getPlainValue() == baseLocal)
+ return abs;
+
+ return null;
+ }
+
+ /**
+ * Check whether the access path is read at unit.
+ *
+ * @param unit unit
+ * @param ap access path
+ * @return true if ap is read at unit
+ */
+ public static boolean isReadAt(Unit unit, AccessPath ap) {
+ Iterator it = unit.getUseBoxesIterator();
+ while (it.hasNext())
+ if (it.next().getValue() == ap.getPlainValue())
+ return true;
+
+ return false;
+ }
+
+}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/conditions/SignatureFlowCondition.java b/soot-infoflow/src/soot/jimple/infoflow/river/conditions/SignatureFlowCondition.java
index 7ba030f55..3cddc1a0d 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/conditions/SignatureFlowCondition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/conditions/SignatureFlowCondition.java
@@ -1,7 +1,9 @@
package soot.jimple.infoflow.river.conditions;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -10,15 +12,26 @@
import soot.SootClass;
import soot.SootMethod;
import soot.Type;
+import soot.Value;
+import soot.jimple.ClassConstant;
+import soot.jimple.Constant;
+import soot.jimple.InvokeExpr;
+import soot.jimple.NumericConstant;
import soot.jimple.Stmt;
+import soot.jimple.StringConstant;
+import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.SootMethodAndClass;
+import soot.jimple.infoflow.data.ValueOnPath;
+import soot.jimple.infoflow.data.ValueOnPath.Parameter;
import soot.jimple.infoflow.results.DataFlowResult;
import soot.jimple.infoflow.results.InfoflowResults;
import soot.jimple.infoflow.results.ResultSinkInfo;
import soot.jimple.infoflow.results.ResultSourceInfo;
import soot.jimple.infoflow.river.ConditionalSecondarySourceDefinition;
+import soot.jimple.infoflow.river.TurnAroundSecondarySinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.SourceSinkCondition;
import soot.jimple.infoflow.util.SootMethodRepresentationParser;
+import soot.util.HashMultiMap;
import soot.util.MultiMap;
/**
@@ -37,25 +50,35 @@ public class SignatureFlowCondition extends SourceSinkCondition {
private Set methodsOnPath = null;
private Set classesOnPath = null;
private Set excludedClasses = null;
+ private Set valuesOnPath = null;
/**
* Create a new additional flow condition
*
* @param classNamesOnPath class names that have to be on the path
* @param signaturesOnPath signatures that have to be on the path
+ * @param valuesOnPath values that have to be on path
* @param excludedClassNames class names of primary sinks that should be
* filtered without context, e.g.
* ByteArrayOutputStream for OutputStream
*/
public SignatureFlowCondition(Set classNamesOnPath, Set signaturesOnPath,
- Set excludedClassNames) {
+ Set valuesOnPath, Set excludedClassNames) {
this.classNamesOnPath = classNamesOnPath;
this.signaturesOnPath = signaturesOnPath;
+ this.valuesOnPath = valuesOnPath;
this.excludedClassNames = excludedClassNames;
+ if (valuesOnPath != null) {
+ for (ValueOnPath v : valuesOnPath) {
+ if (signaturesOnPath == null)
+ signaturesOnPath = new HashSet<>();
+ signaturesOnPath.add(v.getInvocation());
+ }
+ }
}
@Override
- public boolean evaluate(DataFlowResult result, InfoflowResults results) {
+ public boolean evaluate(DataFlowResult result, InfoflowResults results, InfoflowManager manager) {
// If we have nothing to check, we accept everything
if (isEmpty())
return true;
@@ -75,35 +98,28 @@ public boolean evaluate(DataFlowResult result, InfoflowResults results) {
// Because we injected the taint in the SecondaryFlowGenerator with a
// SecondarySinkDefinition,
// if there is a flow containing the sink, it is always also in the MultiMap.
- Pair, Set> flows = getSignaturesAndClassNamesReachedFromSink(additionalResults, sinkStmt);
- ensureSootMethodsOnPath();
- boolean sigMatch = signaturesOnPath == null || signaturesOnPath.isEmpty()
- || flows.getO1().stream().anyMatch(this::signatureMatches);
- ensureSootClassesOnPath();
- boolean classMatch = classesOnPath == null || classesOnPath.isEmpty()
- || flows.getO2().stream().anyMatch(c -> this.classMatches(c, classesOnPath));
- return sigMatch && classMatch;
+ return checkConditions(result, additionalResults, sinkStmt, manager);
}
- private boolean signatureMatches(String sig) {
+ private boolean signatureMatches(String sig, Set methodsCheck) {
SootMethod sm = Scene.v().grabMethod(sig);
if (sm == null)
return false;
- if (methodsOnPath.contains(sm))
+ if (methodsCheck.contains(sm))
return true;
for (SootClass ifc : sm.getDeclaringClass().getInterfaces()) {
SootMethod superMethod = ifc.getMethodUnsafe(sm.getSubSignature());
- if (superMethod != null && methodsOnPath.contains(superMethod))
+ if (superMethod != null && methodsCheck.contains(superMethod))
return true;
}
SootClass superClass = sm.getDeclaringClass().getSuperclassUnsafe();
while (superClass != null) {
SootMethod superMethod = superClass.getMethodUnsafe(sm.getSubSignature());
- if (superMethod != null && methodsOnPath.contains(superMethod))
+ if (superMethod != null && methodsCheck.contains(superMethod))
return true;
superClass = superClass.getSuperclassUnsafe();
}
@@ -225,29 +241,70 @@ private Set resolveSootClassesToSet(Set classNameSet) {
}
/**
- * Retrieves the signatures and classes that can be reached from the primary
- * sink/secondary source
+ * Checks the conditions
+ *
+ * @param result
*
* @param additionalResults MultiMap containing the additional results
* @param primarySinkStmt Sink of interest
- * @return A list of all callee signatures and a list of declaring classes on
- * the path from the sink on
+ * @param manager
+ * @return true if the conditions matched
*/
- private Pair, Set> getSignaturesAndClassNamesReachedFromSink(
- MultiMap additionalResults, Stmt primarySinkStmt) {
+ protected boolean checkConditions(DataFlowResult result,
+ MultiMap additionalResults, Stmt primarySinkStmt,
+ InfoflowManager manager) {
Set sigSet = new HashSet<>();
Set classSet = new HashSet<>();
+ MultiMap valueStmtMap = new HashMultiMap<>();
+ List> turnAroundFlows = new ArrayList<>();
for (ResultSinkInfo secondarySinkInfo : additionalResults.keySet()) {
for (ResultSourceInfo secondarySourceInfo : additionalResults.get(secondarySinkInfo)) {
+ if (secondarySourceInfo.getDefinition() instanceof TurnAroundSecondarySinkDefinition) {
+ turnAroundFlows.add(new Pair<>(secondarySourceInfo, secondarySinkInfo));
+ }
+
+ }
+ }
+
+ for (ResultSinkInfo secondarySinkInfo : additionalResults.keySet()) {
+ for (ResultSourceInfo secondarySourceInfo : additionalResults.get(secondarySinkInfo)) {
+ if (!(secondarySourceInfo.getDefinition() instanceof ConditionalSecondarySourceDefinition))
+ continue;
// Match secondary source with primary sink of interest
- if (secondarySourceInfo.getStmt() == primarySinkStmt
- && secondarySourceInfo.getDefinition() instanceof ConditionalSecondarySourceDefinition) {
+ boolean matchesStmt = secondarySourceInfo.getStmt() == primarySinkStmt;
+ boolean hasTurnAround = false;
+ Stmt valueStmt = secondarySinkInfo.getStmt();
+ if (!matchesStmt) {
+ hasTurnAround = secondarySinkInfo.getDefinition() instanceof TurnAroundSecondarySinkDefinition;
+ if (hasTurnAround) {
+ valueStmt = null;
+ Stmt stmt = secondarySinkInfo.getStmt();
+ for (Pair ta : turnAroundFlows) {
+ ResultSourceInfo src = ta.getO1();
+ if (src.getStmt() == stmt
+ && src.getAccessPath().equals(secondarySinkInfo.getAccessPath())) {
+ matchesStmt = true;
+ valueStmt = ta.getO2().getStmt();
+ if (valueStmt.containsInvokeExpr()) {
+ SootMethod callee = valueStmt.getInvokeExpr().getMethod();
+ sigSet.add(callee.getSignature());
+ classSet.add(callee.getDeclaringClass().getName());
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (matchesStmt) {
if (secondarySourceInfo.getPath() == null) {
// Fall back if path reconstruction is not enabled
SootMethod callee = secondarySinkInfo.getStmt().getInvokeExpr().getMethod();
sigSet.add(callee.getSignature());
classSet.add(callee.getDeclaringClass().getName());
+ if (valueStmt != null) {
+ mapValueOnPath(valueStmtMap, valueStmt);
+ }
} else {
Stmt[] path = secondarySourceInfo.getPath();
for (Stmt stmt : path) {
@@ -256,13 +313,76 @@ private Pair, Set> getSignaturesAndClassNamesReachedFromSink
SootMethod callee = stmt.getInvokeExpr().getMethod();
sigSet.add(callee.getSignature());
classSet.add(callee.getDeclaringClass().getName());
+ mapValueOnPath(valueStmtMap, stmt);
}
}
}
}
}
}
- return new Pair<>(sigSet, classSet);
+ boolean sigMatch = signaturesOnPath == null || signaturesOnPath.isEmpty()
+ || sigSet.stream().anyMatch(c -> this.signatureMatches(c, methodsOnPath));
+ boolean classMatch = classesOnPath == null || classesOnPath.isEmpty()
+ || classSet.stream().anyMatch(c -> this.classMatches(c, classesOnPath));
+ boolean valuesMatch = valuesOnPath == null || valuesOnPath.isEmpty()
+ || valuesOnPath.stream().anyMatch(c -> this.valuesMatches(c, valueStmtMap.get(c)));
+ return sigMatch && classMatch && valuesMatch;
+ }
+
+ private void mapValueOnPath(MultiMap results, Stmt stmt) {
+ if (valuesOnPath != null) {
+ for (ValueOnPath v : valuesOnPath) {
+ SootMethod m = Scene.v().grabMethod(v.getInvocation());
+
+ if (m != null && signatureMatches(stmt.getInvokeExpr().getMethod().getSignature(),
+ Collections.singleton(m))) {
+ results.put(v, stmt);
+ }
+ }
+ }
+ }
+
+ private boolean valuesMatches(ValueOnPath c, Set stmts) {
+ nextStmt: for (Stmt s : stmts) {
+ InvokeExpr inv = s.getInvokeExpr();
+ // we use AND on the parameters
+ for (Parameter p : c.getParameters()) {
+ int idx = p.getParameterIndex();
+ if (idx < 0 || idx >= inv.getArgCount()) {
+ continue nextStmt;
+ }
+ Value v = inv.getArg(idx);
+ if (v instanceof Constant) {
+ String cmp;
+ if (v instanceof StringConstant)
+ cmp = ((StringConstant) v).value;
+ else if (v instanceof NumericConstant)
+ cmp = String.valueOf(((NumericConstant) v).getNumericValue());
+ else if (v instanceof ClassConstant)
+ cmp = ((ClassConstant) v).getValue();
+ else
+ continue nextStmt;
+
+ String vopContent = p.getContentToMatch();
+
+ boolean matched = false;
+ if (p.isRegex()) {
+ matched = p.getRegexMatcher().matcher(cmp).matches();
+ } else {
+ if (!p.isCaseSensitive()) {
+ matched = cmp.equalsIgnoreCase(vopContent);
+ } else {
+ matched = cmp.equals(vopContent);
+ }
+ }
+ if (!matched)
+ continue nextStmt;
+ }
+ }
+ // all matched
+ return true;
+ }
+ return false;
}
/**
diff --git a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/AbstractSourceSinkDefinition.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/AbstractSourceSinkDefinition.java
index 666403369..053bc2279 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/AbstractSourceSinkDefinition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/AbstractSourceSinkDefinition.java
@@ -13,6 +13,7 @@ public abstract class AbstractSourceSinkDefinition implements ISourceSinkDefinit
protected ISourceSinkCategory category;
protected Set conditions;
+ protected Set turnArounds;
public AbstractSourceSinkDefinition() {
}
@@ -67,8 +68,22 @@ public boolean equals(Object obj) {
if (other.conditions != null)
return false;
} else if (!conditions.equals(other.conditions))
+ return false;
+ if (turnArounds == null) {
+ if (other.turnArounds != null)
return false;
+ } else if (!turnArounds.equals(other.turnArounds))
+ return false;
return true;
}
+ @Override
+ public void setTurnArounds(Set turnArounds) {
+ this.turnArounds = turnArounds;
+ }
+
+ @Override
+ public Set getTurnArounds() {
+ return turnArounds;
+ }
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/ISourceSinkDefinition.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/ISourceSinkDefinition.java
index ba1d9d210..4ff12510b 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/ISourceSinkDefinition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/ISourceSinkDefinition.java
@@ -58,10 +58,26 @@ public interface ISourceSinkDefinition {
/**
* Sets the conditions under which the source/sink definition is valid
*
- * @param conditions
- * A set with the conditions under which the source/sink definition
- * is valid, optionally null if no such conditions exist
+ * @param conditions A set with the conditions under which the source/sink
+ * definition is valid, optionally null if no
+ * such conditions exist
*/
public void setConditions(Set conditions);
+ /**
+ * Sets the turn around points where the flow direction for River flows is
+ * injected into a forward analysis
+ *
+ * @param turnAround the method signatures that indicate turn around points
+ */
+ public void setTurnArounds(Set turnAround);
+
+ /**
+ * Returns the turn around points where the flow direction for River flows is
+ * injected into a forward analysis
+ *
+ * @return returns the method signatures that indicate turn around points
+ */
+ public Set getTurnArounds();
+
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/MethodSourceSinkDefinition.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/MethodSourceSinkDefinition.java
index eb5777561..9b19a89d0 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/MethodSourceSinkDefinition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/MethodSourceSinkDefinition.java
@@ -324,6 +324,7 @@ protected MethodSourceSinkDefinition buildNewDefinition(Set bas
MethodSourceSinkDefinition def = buildNewDefinition(method, baseAPTs, paramAPTs, returnAPTs, callType);
def.category = category;
def.conditions = conditions;
+ def.turnArounds = turnArounds;
return def;
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/SourceSinkCondition.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/SourceSinkCondition.java
index abec30387..ca3bb84b8 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/SourceSinkCondition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/SourceSinkCondition.java
@@ -7,6 +7,7 @@
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
+import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.SootMethodAndClass;
import soot.jimple.infoflow.results.DataFlowResult;
import soot.jimple.infoflow.results.InfoflowResults;
@@ -25,10 +26,11 @@ public abstract class SourceSinkCondition {
*
* @param result The data flow result
* @param results All results of this data flow analysis
+ * @param manager The infoflow manager
* @return True if the given data flow result matches the condition, otherwise
* false
*/
- public abstract boolean evaluate(DataFlowResult result, InfoflowResults results);
+ public abstract boolean evaluate(DataFlowResult result, InfoflowResults results, InfoflowManager manager);
/**
* Gets all methods referenced by this condition
diff --git a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/BaseSourceSinkManager.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/BaseSourceSinkManager.java
index df347680b..91a1892cf 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/BaseSourceSinkManager.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/BaseSourceSinkManager.java
@@ -161,6 +161,8 @@ public Collection load(SootClass sc) throws Exception {
});
+ private Set turnArounds;
+
/**
* Creates a new instance of the {@link BaseSourceSinkManager} class with either
* strong or weak matching.
@@ -1154,4 +1156,26 @@ public boolean isConditionalSink(Stmt stmt, SootClass baseClass) {
return false;
}
+
+ @Override
+ public boolean isTurnAroundPoint(SootMethod method) {
+ Set ta = this.turnArounds;
+ if (ta == null)
+ return false;
+ return ta.contains(method);
+ }
+
+ @Override
+ public void addTurnArounds(Set turnArounds) {
+ if (this.turnArounds == null) {
+ this.turnArounds = new HashSet<>(turnArounds.size());
+ }
+ for (String ta : turnArounds) {
+ SootMethod m = Scene.v().grabMethod("<" + ta + ">");
+ if (m != null) {
+ this.turnArounds.add(m);
+ }
+ }
+ }
+
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/ISourceSinkManager.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/ISourceSinkManager.java
index 7a6026194..92f9ecf85 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/ISourceSinkManager.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/ISourceSinkManager.java
@@ -10,6 +10,9 @@
******************************************************************************/
package soot.jimple.infoflow.sourcesSinks.manager;
+import java.util.Set;
+
+import soot.SootMethod;
import soot.jimple.Stmt;
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.AccessPath;
@@ -20,37 +23,52 @@
public interface ISourceSinkManager {
/**
- * Initialization method that is called after the Soot instance has been
- * created and before the actual data flow tracking is started.
+ * Initialization method that is called after the Soot instance has been created
+ * and before the actual data flow tracking is started.
*/
public void initialize();
/**
- * Determines if a method called by the Stmt is a source method or not. If
- * so, additional information is returned
+ * Determines if a method called by the Stmt is a source method or not. If so,
+ * additional information is returned
*
- * @param sCallSite
- * a Stmt which should include an invokeExrp calling a method
- * @param manager
- * The manager object for interacting with the solver
- * @return A SourceInfo object containing additional information if this
- * call is a source, otherwise null
+ * @param sCallSite a Stmt which should include an invokeExrp calling a method
+ * @param manager The manager object for interacting with the solver
+ * @return A SourceInfo object containing additional information if this call is
+ * a source, otherwise null
*/
public SourceInfo getSourceInfo(Stmt sCallSite, InfoflowManager manager);
/**
* Checks if the given access path at this statement will leak.
*
- * @param sCallSite
- * The call site to check
- * @param manager
- * The manager object for interacting with the solver
- * @param ap
- * The access path to check. Pass null to check whether the given
- * statement can be a sink for any given access path.
- * @return A SinkInfo object containing additional information if this call
- * is a sink, otherwise null
+ * @param sCallSite The call site to check
+ * @param manager The manager object for interacting with the solver
+ * @param ap The access path to check. Pass null to check whether the
+ * given statement can be a sink for any given access path.
+ * @return A SinkInfo object containing additional information if this call is a
+ * sink, otherwise null
*/
public SinkInfo getSinkInfo(Stmt sCallSite, InfoflowManager manager, AccessPath ap);
+ /**
+ * Checks whether a called soot method is considered a turnaround point by any
+ * sink
+ *
+ * @param method the method
+ * @return true when the called soot method is considered a turnaround point by
+ * any sink
+ */
+ public default boolean isTurnAroundPoint(SootMethod method) {
+ return false;
+ }
+
+ /**
+ * Adds turn arounds from a the given set
+ *
+ * @param turnArounds the turn around points
+ */
+ public default void addTurnArounds(Set turnArounds) {
+ }
+
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/util/DebugFlowFunctionTaintPropagationHandler.java b/soot-infoflow/src/soot/jimple/infoflow/util/DebugFlowFunctionTaintPropagationHandler.java
index bdc17f99a..5274e7d3d 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/util/DebugFlowFunctionTaintPropagationHandler.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/util/DebugFlowFunctionTaintPropagationHandler.java
@@ -7,6 +7,7 @@
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.Abstraction;
import soot.jimple.infoflow.handlers.TaintPropagationHandler;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
/**
* Prints all propagations to stdout. Useful to debug small test cases.
@@ -56,7 +57,7 @@ public void notifyFlowIn(Unit stmt, Abstraction taint, InfoflowManager manager,
@Override
public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing,
- InfoflowManager manager, FlowFunctionType type) {
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
if (this.filter != null && !this.filter.evaluate(manager.getICFG().getMethodOf(stmt).toString()))
return false;
diff --git a/soot-infoflow/test/soot/jimple/infoflow/test/junit/HeapTests.java b/soot-infoflow/test/soot/jimple/infoflow/test/junit/HeapTests.java
index dbff82201..dc51fb34a 100644
--- a/soot-infoflow/test/soot/jimple/infoflow/test/junit/HeapTests.java
+++ b/soot-infoflow/test/soot/jimple/infoflow/test/junit/HeapTests.java
@@ -20,7 +20,11 @@
import org.junit.Ignore;
import org.junit.Test;
-import soot.*;
+import soot.RefType;
+import soot.Scene;
+import soot.SootField;
+import soot.SootMethod;
+import soot.Unit;
import soot.jimple.AssignStmt;
import soot.jimple.DefinitionStmt;
import soot.jimple.InstanceInvokeExpr;
@@ -36,6 +40,7 @@
import soot.jimple.infoflow.entryPointCreators.DefaultEntryPointCreator;
import soot.jimple.infoflow.entryPointCreators.SequentialEntryPointCreator;
import soot.jimple.infoflow.handlers.TaintPropagationHandler;
+import soot.jimple.infoflow.problems.TaintPropagationResults;
import soot.jimple.infoflow.results.InfoflowResults;
import soot.jimple.infoflow.sourcesSinks.definitions.MethodSourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.manager.ISourceSinkManager;
@@ -1049,7 +1054,8 @@ public SourceInfo getSourceInfo(Stmt sCallSite, InfoflowManager manager) {
if (sCallSite instanceof AssignStmt) {
AssignStmt assignStmt = (AssignStmt) sCallSite;
if (assignStmt.getRightOp().toString().contains("taintedBySourceSinkManager"))
- return new SourceInfo(manager.getAccessPathFactory().createAccessPath(assignStmt.getLeftOp(), true));
+ return new SourceInfo(
+ manager.getAccessPathFactory().createAccessPath(assignStmt.getLeftOp(), true));
else
return null;
}
@@ -1279,7 +1285,6 @@ public void activationStatementTest1() {
negativeCheckInfoflow(infoflow);
}
-
@Test(timeout = 300000)
public void callSiteCreatesAlias() {
IInfoflow infoflow = initInfoflow();
@@ -1309,7 +1314,8 @@ public void notifyFlowIn(Unit stmt, Abstraction taint, InfoflowManager manager,
}
@Override
- public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing, InfoflowManager manager, FlowFunctionType type) {
+ public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing,
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
return false;
}
});
@@ -1318,7 +1324,6 @@ public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Se
checkInfoflow(infoflow, 1);
}
-
@Test(timeout = 300000)
public void testRecursiveAccessPath() {
IInfoflow infoflow = initInfoflow();
@@ -1339,8 +1344,8 @@ public void testRemoveEntailedAbstractions1() {
epoints.add("");
infoflow.computeInfoflow(appPath, libPath, epoints, sources, sinks);
checkInfoflow(infoflow, 1);
- Assert.assertEquals(2, infoflow.getResults().getResultSet().stream()
- .map(res -> res.getSource().getStmt()).distinct().count());
+ Assert.assertEquals(2,
+ infoflow.getResults().getResultSet().stream().map(res -> res.getSource().getStmt()).distinct().count());
}
@Test(timeout = 300000)
@@ -1353,7 +1358,7 @@ public void testRemoveEntailedAbstractions2() {
epoints.add("");
infoflow.computeInfoflow(appPath, libPath, epoints, sources, sinks);
checkInfoflow(infoflow, 1);
- Assert.assertEquals(2, infoflow.getResults().getResultSet().stream()
- .map(res -> res.getSource().getStmt()).distinct().count());
+ Assert.assertEquals(2,
+ infoflow.getResults().getResultSet().stream().map(res -> res.getSource().getStmt()).distinct().count());
}
}