diff --git a/soot-infoflow-android/schema/SourcesAndSinks.xsd b/soot-infoflow-android/schema/SourcesAndSinks.xsd
index b71d54ae2..423027874 100644
--- a/soot-infoflow-android/schema/SourcesAndSinks.xsd
+++ b/soot-infoflow-android/schema/SourcesAndSinks.xsd
@@ -3,18 +3,34 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -27,6 +43,7 @@
+
@@ -41,6 +58,7 @@
+
@@ -57,9 +75,11 @@
+
+
@@ -81,6 +101,7 @@
+
@@ -96,6 +117,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -109,6 +154,9 @@
+
+
+
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..99b70bd26 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;
@@ -105,6 +107,7 @@ protected class SAXHandler extends DefaultHandler {
protected String accessPathParentElement = "";
protected String description = "";
+ protected boolean triggerAdditionalFlow;
protected Set baseAPs = new HashSet<>();
protected List> paramAPs = new ArrayList<>();
@@ -112,11 +115,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() {
}
@@ -158,11 +165,16 @@ public void startElement(String uri, String localName, String qName, Attributes
case XMLConstants.BASE_TAG:
accessPathParentElement = qNameLower;
description = attributes.getValue(XMLConstants.DESCRIPTION_ATTRIBUTE);
+ String t = attributes.getValue(XMLConstants.TRIGGERADDITIONALFLOW_ATTRIBUTE);
+ // true by default for the base tag
+ triggerAdditionalFlow = t == null || t.equalsIgnoreCase("true");
break;
case XMLConstants.RETURN_TAG:
accessPathParentElement = qNameLower;
description = attributes.getValue(XMLConstants.DESCRIPTION_ATTRIBUTE);
+ t = attributes.getValue(XMLConstants.TRIGGERADDITIONALFLOW_ATTRIBUTE);
+ triggerAdditionalFlow = t != null && t.equalsIgnoreCase("true");
break;
case XMLConstants.PARAM_TAG:
@@ -177,10 +189,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 +274,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())
@@ -265,6 +301,8 @@ protected void handleStarttagParam(Attributes attributes, String qNameLower) {
}
accessPathParentElement = qNameLower;
description = attributes.getValue(XMLConstants.DESCRIPTION_ATTRIBUTE);
+ String t = attributes.getValue(XMLConstants.TRIGGERADDITIONALFLOW_ATTRIBUTE);
+ triggerAdditionalFlow = t != null && t.equalsIgnoreCase("true");
}
protected void handleStarttagPathelement(Attributes attributes) {
@@ -290,6 +328,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 +388,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 +452,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 +486,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 +496,7 @@ protected void handleEndtagMethod() {
}
// Start a new method and discard our old data
+ turnAroundPaths = null;
methodSignature = null;
fieldSignature = null;
baseAPs = new HashSet<>();
@@ -489,6 +555,8 @@ protected void handleEndtagAccesspath() {
if (description != null && !description.isEmpty())
apt.setDescription(description);
+ apt.setTriggerAdditionalFlow(triggerAdditionalFlow);
+
// Simplify the AP after setting the description for not breaking the generic
// source definition
apt = apt.simplify();
@@ -515,6 +583,7 @@ protected void handleEndtagAccesspath() {
isSink = false;
pathElements = null;
pathElementTypes = null;
+ triggerAdditionalFlow = false;
description = null;
}
@@ -666,23 +735,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/PreprocessorHandler.java b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/PreprocessorHandler.java
new file mode 100644
index 000000000..0b962563a
--- /dev/null
+++ b/soot-infoflow-android/src/soot/jimple/infoflow/android/source/parsers/xml/PreprocessorHandler.java
@@ -0,0 +1,265 @@
+package soot.jimple.infoflow.android.source.parsers.xml;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.Attributes2Impl;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Resolves stereotypes, which are essentially like C macros.
+ */
+public class PreprocessorHandler extends DefaultHandler {
+ /* Example:
+
+
+ .*${ALGORITHMNAME}.*
+
+
+ .*${ALGORITHMNAME}.*
+
+
+ .*${ALGORITHMNAME}.*
+
+
+ .*${ALGORITHMNAME}.*
+
+
+ .*${ALGORITHMNAME}.*
+
+
+ .*${ALGORITHMNAME}.*
+
+
+
+
+
+ DES
+
+
+ RC4
+
+
+ Blowfish
+
+
+ */
+
+ static interface IHandler {
+ public void apply(DefaultHandler handler, Map replacements) throws SAXException;
+ }
+
+ private static class CharacterHandler implements IHandler {
+
+ private String string;
+
+ public CharacterHandler(char[] ch, int start, int length) {
+ this.string = new String(ch, start, length);
+ }
+
+ @Override
+ public void apply(DefaultHandler handler, Map replacements) throws SAXException {
+ String s = string;
+ for (Entry i : replacements.entrySet()) {
+ s = s.replace(i.getKey(), i.getValue());
+ }
+ handler.characters(s.toCharArray(), 0, s.length());
+ }
+
+ }
+
+ private static class StartElementHandler implements IHandler {
+
+ private String uri;
+ private String localName;
+ private String qName;
+ private Attributes attributes;
+
+ public StartElementHandler(String uri, String localName, String qName, Attributes attributes) {
+ this.uri = uri;
+ this.localName = localName;
+ this.qName = qName;
+ //we have to clone
+ this.attributes = new Attributes2Impl(attributes);
+ }
+
+ @Override
+ public void apply(DefaultHandler handler, Map replacements) throws SAXException {
+ Attributes2Impl copy = new Attributes2Impl();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ String uri = attributes.getURI(i);
+ String localName = attributes.getLocalName(i);
+ String qName = attributes.getQName(i);
+ String type = attributes.getType(i);
+ String value = attributes.getValue(i);
+ if (value != null) {
+ for (Entry e : replacements.entrySet()) {
+ value = value.replace(e.getKey(), e.getValue());
+ }
+ }
+ copy.addAttribute(uri, localName, qName, type, value);
+ }
+ handler.startElement(uri, localName, qName, copy);
+ }
+
+ }
+
+ private static class EndElementHandler implements IHandler {
+
+ private String uri;
+ private String localName;
+ private String qName;
+
+ public EndElementHandler(String uri, String localName, String qName) {
+ this.uri = uri;
+ this.localName = localName;
+ this.qName = qName;
+ }
+
+ @Override
+ public void apply(DefaultHandler handler, Map replacements) throws SAXException {
+ handler.endElement(uri, localName, qName);
+ }
+
+ }
+
+ private static class RecordingHandler extends DefaultHandler implements IHandler {
+ private List children = new ArrayList<>();
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ children.add(new CharacterHandler(ch, start, length));
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ children.add(new StartElementHandler(uri, localName, qName, attributes));
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ children.add(new EndElementHandler(uri, localName, qName));
+ }
+
+ public void apply(DefaultHandler handler, Map replacements) throws SAXException {
+ for (IHandler c : children)
+ c.apply(handler, replacements);
+
+ }
+
+ }
+
+ private DefaultHandler inner;
+ private Map stereotypes = new HashMap<>();
+ private RecordingHandler definingStereotype;
+ private String stereotypeId;
+
+ private Map replacements;
+ private String replacementVariable;
+ private String replacementValue;
+
+ public PreprocessorHandler(DefaultHandler inner) {
+ this.inner = inner;
+ }
+
+ @Override
+ public void startDocument() throws SAXException {
+ inner.startDocument();
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (definingStereotype != null) {
+ definingStereotype.characters(ch, start, length);
+ } else if (replacementVariable != null) {
+ this.replacementValue = new String(ch, start, length);
+ } else {
+ inner.characters(ch, start, length);
+ }
+
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ if (definingStereotype != null) {
+ if (qName.equals("defineStereotype"))
+ throw new IllegalArgumentException("Defining a stereotype within a stereotype is not supported");
+ definingStereotype.startElement(uri, localName, qName, attributes);
+ return;
+ }
+ switch (qName) {
+ case "defineStereotype":
+ if (stereotypeId != null)
+ throw new IllegalStateException();
+ stereotypeId = attributes.getValue("id");
+ if (stereotypeId == null)
+ throw new IllegalArgumentException("No stereotype id defined");
+ definingStereotype = new RecordingHandler();
+ return;
+ case "stereotype":
+ if (stereotypeId != null)
+ throw new IllegalStateException();
+ stereotypeId = attributes.getValue("id");
+ replacements = new HashMap<>();
+ if (stereotypeId == null)
+ throw new IllegalArgumentException("No stereotype id defined");
+ return;
+ default:
+ if (replacements != null) {
+ //within stereotype replacement
+ this.replacementVariable = qName;
+ return;
+ }
+ }
+ inner.startElement(uri, localName, qName, attributes);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (definingStereotype != null && !qName.equals("defineStereotype")) {
+ definingStereotype.endElement(uri, localName, qName);
+ return;
+ }
+ switch (qName) {
+ case "defineStereotype":
+ stereotypes.putIfAbsent(stereotypeId, definingStereotype);
+ definingStereotype = null;
+ stereotypeId = null;
+ return;
+ case "stereotype":
+ RecordingHandler st = stereotypes.get(stereotypeId);
+ if (st == null)
+ throw new IllegalArgumentException(
+ String.format("Stereotype %s was not found, known stereotypes at this point: %s", stereotypeId,
+ stereotypes.keySet()));
+ PreprocessorHandler recursion = new PreprocessorHandler(this.inner);
+ recursion.stereotypes = stereotypes;
+ st.apply(recursion, replacements);
+ stereotypeId = null;
+ replacements = null;
+ return;
+ default:
+ if (replacementVariable != null) {
+ if (replacementValue == null)
+ throw new IllegalStateException("No replacement value defined");
+ replacements.put("${" + replacementVariable + "}", replacementValue);
+ replacementValue = null;
+ replacementVariable = null;
+ return;
+ }
+ }
+ inner.endElement(uri, localName, qName);
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ inner.endDocument();
+ }
+
+}
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..b7f91c3c7 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,9 @@ 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 TRIGGERADDITIONALFLOW_ATTRIBUTE = "triggerAdditionalFlow";
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..b00d852c1 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;
}
@@ -253,7 +257,7 @@ protected IAccessPathBasedSourceSinkDefinition createFieldSourceSinkDefinition(S
@Override
protected void runParse(SAXParser parser, InputStream stream) {
try {
- parser.parse(stream, new SAXHandler(this.categoryFilter));
+ parser.parse(stream, new PreprocessorHandler(new SAXHandler(this.categoryFilter)));
} catch (SAXException | IOException e) {
e.printStackTrace();
}
diff --git a/soot-infoflow-cmd/schema/SourcesAndSinks.xsd b/soot-infoflow-cmd/schema/SourcesAndSinks.xsd
index 6e7719332..423027874 100644
--- a/soot-infoflow-cmd/schema/SourcesAndSinks.xsd
+++ b/soot-infoflow-cmd/schema/SourcesAndSinks.xsd
@@ -3,18 +3,34 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -27,6 +43,7 @@
+
@@ -41,6 +58,7 @@
+
@@ -50,15 +68,18 @@
+
+
+
@@ -80,6 +101,7 @@
+
@@ -95,6 +117,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -108,9 +154,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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..4d9cc5d72 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;
@@ -81,8 +82,8 @@ public boolean isValidForThisThread() {
private CachedFactory cachedFactory;
/**
- * Reads a summary xml and places the new summaries into the given data object.
- * This method closes the reader.
+ * Reads a summary xml and places the new summaries into the given data object. This
+ * method closes the reader.
*
* @param reader The reader from which to read the method summaries
* @param summaries The data object in which to place the summaries
@@ -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) {
@@ -595,6 +614,8 @@ private boolean isMatchStrict(Map attributes) {
}
private boolean isParameter(Map attributes) {
+ if (attributes.get(ATTRIBUTE_FLOWTYPE) == null)
+ System.out.println();
return attributes.get(ATTRIBUTE_FLOWTYPE).equals(SourceSinkType.Parameter.toString());
}
@@ -642,8 +663,8 @@ private GapDefinition getGapDefinition(Map attributes, MethodSum
/**
* Sets whether summaries shall be validated after they are read from disk
*
- * @param validateSummariesOnRead True if summaries shall be validated after
- * they are read from disk, otherwise false
+ * @param validateSummariesOnRead True if summaries shall be validated after they
+ * are read from disk, otherwise false
*/
public void setValidateSummariesOnRead(boolean validateSummariesOnRead) {
this.validateSummariesOnRead = validateSummariesOnRead;
diff --git a/soot-infoflow-summaries/summariesManual/android.content.SharedPreferences$Editor.xml b/soot-infoflow-summaries/summariesManual/android.content.SharedPreferences$Editor.xml
new file mode 100644
index 000000000..242e8d2c5
--- /dev/null
+++ b/soot-infoflow-summaries/summariesManual/android.content.SharedPreferences$Editor.xml
@@ -0,0 +1,260 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/soot-infoflow-summaries/summariesManual/android.content.SharedPreferences.xml b/soot-infoflow-summaries/summariesManual/android.content.SharedPreferences.xml
new file mode 100644
index 000000000..4576b4afa
--- /dev/null
+++ b/soot-infoflow-summaries/summariesManual/android.content.SharedPreferences.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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-summaries/summariesManual/java.io.OutputStream.xml b/soot-infoflow-summaries/summariesManual/java.io.OutputStream.xml
index f78005a0f..7be96773a 100644
--- a/soot-infoflow-summaries/summariesManual/java.io.OutputStream.xml
+++ b/soot-infoflow-summaries/summariesManual/java.io.OutputStream.xml
@@ -13,6 +13,14 @@
+
+
+
+
+
+
@@ -24,6 +32,12 @@
AccessPath="[java.io.OutputStream: java.io.OutputStream innerStream]"
AccessPathTypes="[java.io.OutputStream]" />
+
+
+
+
@@ -34,6 +48,12 @@
AccessPath="[java.io.OutputStream: java.io.OutputStream innerStream]"
AccessPathTypes="[java.io.OutputStream]" />
+
+
+
+
diff --git a/soot-infoflow-summaries/summariesManual/java.net.URL.xml b/soot-infoflow-summaries/summariesManual/java.net.URL.xml
index 502794c9b..9f103e172 100644
--- a/soot-infoflow-summaries/summariesManual/java.net.URL.xml
+++ b/soot-infoflow-summaries/summariesManual/java.net.URL.xml
@@ -601,6 +601,12 @@
AccessPath="[java.net.URLConnection: java.net.URL url]"
AccessPathTypes="[java.net.URL]" />
+
+
+
+
diff --git a/soot-infoflow-summaries/summariesManual/java.net.URLConnection.xml b/soot-infoflow-summaries/summariesManual/java.net.URLConnection.xml
index cdede943c..33666ab07 100644
--- a/soot-infoflow-summaries/summariesManual/java.net.URLConnection.xml
+++ b/soot-infoflow-summaries/summariesManual/java.net.URLConnection.xml
@@ -217,6 +217,12 @@
AccessPath="[java.io.OutputStream: byte[] innerArray]"
AccessPathTypes="[byte[]]" />
+
+
+
+
diff --git a/soot-infoflow-summaries/summariesManual/java.security.MessageDigest.xml b/soot-infoflow-summaries/summariesManual/java.security.MessageDigest.xml
new file mode 100644
index 000000000..88f673125
--- /dev/null
+++ b/soot-infoflow-summaries/summariesManual/java.security.MessageDigest.xml
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/soot-infoflow-summaries/summariesManual/java.sql.Connection.xml b/soot-infoflow-summaries/summariesManual/java.sql.Connection.xml
new file mode 100644
index 000000000..fb937e811
--- /dev/null
+++ b/soot-infoflow-summaries/summariesManual/java.sql.Connection.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soot-infoflow-summaries/summariesManual/java.sql.PreparedStatement.xml b/soot-infoflow-summaries/summariesManual/java.sql.PreparedStatement.xml
new file mode 100644
index 000000000..e2cda190b
--- /dev/null
+++ b/soot-infoflow-summaries/summariesManual/java.sql.PreparedStatement.xml
@@ -0,0 +1,459 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soot-infoflow-summaries/summariesManual/java.sql.Statement.xml b/soot-infoflow-summaries/summariesManual/java.sql.Statement.xml
new file mode 100644
index 000000000..4db0df9b8
--- /dev/null
+++ b/soot-infoflow-summaries/summariesManual/java.sql.Statement.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soot-infoflow-summaries/summariesManual/javax.crypto.Cipher.xml b/soot-infoflow-summaries/summariesManual/javax.crypto.Cipher.xml
index a262a17b3..0f7df165f 100644
--- a/soot-infoflow-summaries/summariesManual/javax.crypto.Cipher.xml
+++ b/soot-infoflow-summaries/summariesManual/javax.crypto.Cipher.xml
@@ -1,6 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -8,6 +44,10 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
@@ -22,6 +62,15 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
+
+
+
+
@@ -31,6 +80,11 @@
+
+
+
+
@@ -45,6 +99,15 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
+
+
+
+
@@ -59,6 +122,11 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
@@ -73,6 +141,11 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
@@ -89,6 +162,11 @@
+
+
+
+
@@ -104,6 +182,15 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
+
+
+
+
@@ -118,6 +205,15 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
+
+
+
+
@@ -132,6 +228,11 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
@@ -146,6 +247,11 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
@@ -162,6 +268,15 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
+
+
+
+
@@ -176,6 +291,15 @@
AccessPathTypes="[byte[]]" />
+
+
+
+
+
+
+
+
@@ -192,6 +316,11 @@
+
+
+
+
diff --git a/soot-infoflow-summaries/summariesManual/javax.crypto.CipherOutputStream.xml b/soot-infoflow-summaries/summariesManual/javax.crypto.CipherOutputStream.xml
new file mode 100644
index 000000000..d89e098ca
--- /dev/null
+++ b/soot-infoflow-summaries/summariesManual/javax.crypto.CipherOutputStream.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/soot-infoflow-summaries/summariesManual/org.asynchttpclient.Response.xml b/soot-infoflow-summaries/summariesManual/org.asynchttpclient.Response.xml
index 76f0f9a03..c9af11f26 100644
--- a/soot-infoflow-summaries/summariesManual/org.asynchttpclient.Response.xml
+++ b/soot-infoflow-summaries/summariesManual/org.asynchttpclient.Response.xml
@@ -5,8 +5,7 @@
+ AccessPath="org.asynchttpclient.Response: byte[] bytes" />
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..2ad1b595a 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/AbstractInfoflow.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/AbstractInfoflow.java
@@ -126,6 +126,8 @@
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.river.TurnAroundFlowListener;
import soot.jimple.infoflow.solver.DefaultSolverPeerGroup;
import soot.jimple.infoflow.solver.IInfoflowSolver;
import soot.jimple.infoflow.solver.ISolverPeerGroup;
@@ -667,11 +669,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 +969,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 +992,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,18 +1137,10 @@ public Thread newThread(Runnable r) {
if (config.getAdditionalFlowsEnabled()) {
// Add the SecondaryFlowGenerator to the main forward taint analysis
TaintPropagationHandler forwardHandler = forwardProblem.getTaintPropagationHandler();
- if (forwardHandler != null) {
- if (forwardHandler instanceof SequentialTaintPropagationHandler) {
- ((SequentialTaintPropagationHandler) forwardHandler).addHandler(new SecondaryFlowGenerator());
- } else {
- SequentialTaintPropagationHandler seqTpg = new SequentialTaintPropagationHandler();
- seqTpg.addHandler(forwardHandler);
- seqTpg.addHandler(new SecondaryFlowGenerator());
- forwardProblem.setTaintPropagationHandler(seqTpg);
- }
- } else {
- forwardProblem.setTaintPropagationHandler(new SecondaryFlowGenerator());
- }
+ forwardHandler = SequentialTaintPropagationHandler.concat(forwardHandler, new SecondaryFlowGenerator());
+ forwardHandler = SequentialTaintPropagationHandler.concat(forwardHandler, new SecondaryFlowListener());
+
+ forwardProblem.setTaintPropagationHandler(forwardHandler);
if (!(manager.getSourceSinkManager() instanceof IConditionalFlowManager))
throw new IllegalStateException("Additional Flows enabled but no ConditionalFlowManager in place!");
@@ -1165,7 +1162,11 @@ 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));
+ seqTpg.addHandler(new TurnAroundFlowListener());
+ additionalProblem.setTaintPropagationHandler(seqTpg);
additionalProblem.setTaintWrapper(taintWrapper);
additionalNativeCallHandler = new BackwardNativeCallHandler();
additionalProblem.setNativeCallHandler(additionalNativeCallHandler);
@@ -1891,6 +1892,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..623df96d6
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/data/ValueOnPath.java
@@ -0,0 +1,188 @@
+package soot.jimple.infoflow.data;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Can be used to express conditions on values that are used in statements on the path.
+ * This class can be used to enforce that there is a specific method invocation call
+ * where a specific constant value is used as a parameter.
+ */
+public class ValueOnPath {
+
+ /**
+ * A value condition on a specific parameter
+ */
+ public static class Parameter {
+
+ private int paramIdx;
+ private boolean regex, casesensitive;
+ private String value;
+ private Pattern matcher;
+
+ /**
+ * Creates a new parameter
+ *
+ * @param paramIndex the 0-based parameter index
+ * @param regex whether the parameter value is used as a regular
+ * expression
+ * @param casesensitive whether the check is case sensitive
+ */
+ public Parameter(int paramIndex, boolean regex, boolean casesensitive) {
+ this.paramIdx = paramIndex;
+ this.regex = regex;
+ this.casesensitive = casesensitive;
+ }
+
+ /**
+ * Returns the parameter index where the parameter condition applies
+ *
+ * @return parameter index
+ */
+ public int getParameterIndex() {
+ return paramIdx;
+ }
+
+ /**
+ * Returns true if the parameter value is treated as a regular expression. If
+ * false, it is a regular string equals check
+ *
+ * @return whether the value is treated as a regular expression
+ */
+ public boolean isRegex() {
+ return regex;
+ }
+
+ /**
+ * Returns true if the parameter value is checked case sensitive
+ *
+ * @return whether the value is checked case sensitive
+ */
+ 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;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Value '" + value + "' on parameter " + paramIdx);
+ if (regex)
+ sb.append(", regex");
+ if (casesensitive)
+ sb.append(", case sensitive");
+ return sb.toString();
+ }
+
+ }
+
+ private String invocation;
+ private Set parameters;
+
+ /**
+ * Creates a new value on path condition
+ *
+ * @param inv the invocation site where this condition applies
+ */
+ public ValueOnPath(String inv) {
+ this.invocation = inv;
+ }
+
+ /**
+ * Returns the soot method signature of the invocation site where this condition
+ * applies
+ *
+ * @return the invocation site
+ */
+ public String getInvocation() {
+ return invocation;
+ }
+
+ /**
+ * Adds a parameter condition. Note that the parameters are combined using
+ * AND, i.e. all of them have to be true in order to fulfill this condition.
+ *
+ * @param parameter the new parameters condition
+ * @return true if the parameter condition has been added successfully
+ */
+ public boolean add(Parameter parameter) {
+ if (parameters == null)
+ parameters = new HashSet<>();
+ return parameters.add(parameter);
+ }
+
+ /**
+ * Returns a set of parameter conditions. Note that the parameters are combined
+ * using AND, i.e. all of them have to be true in order to fulfill this
+ * condition.
+ *
+ * @return the parameters
+ */
+ 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);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Value condition on invocation site " + getInvocation() + ": ");
+ boolean first = true;
+ for (Parameter p : getParameters()) {
+ if (first)
+ first = false;
+ else
+ sb.append(", ");
+ sb.append(p.toString());
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/handlers/SequentialTaintPropagationHandler.java b/soot-infoflow/src/soot/jimple/infoflow/handlers/SequentialTaintPropagationHandler.java
index f64cbd586..c271d9f49 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;
@@ -87,4 +88,17 @@ public void addAllHandlers(TaintPropagationHandler[] handlers) {
}
}
+ public static TaintPropagationHandler concat(TaintPropagationHandler first, TaintPropagationHandler second) {
+ if (first instanceof SequentialTaintPropagationHandler) {
+ SequentialTaintPropagationHandler f = (SequentialTaintPropagationHandler) first;
+ f.addHandler(second);
+ return f;
+ } else {
+ SequentialTaintPropagationHandler seq = new SequentialTaintPropagationHandler();
+ seq.addHandler(first);
+ seq.addHandler(second);
+ return seq;
+ }
+ }
+
}
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..afcf4f5b8 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/problems/AbstractInfoflowProblem.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/problems/AbstractInfoflowProblem.java
@@ -46,7 +46,7 @@
/**
* abstract super class which - concentrates functionality used by
* InfoflowProblem and AliasProblem - contains helper functions which should not
- * pollute the naturally large InfofflowProblems
+ * pollute the naturally large InfoflowProblems
*
*/
public abstract class AbstractInfoflowProblem extends DefaultJimpleIFDSTabulationProblem {
@@ -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/BackwardPropagationRuleManagerFactory.java b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/BackwardPropagationRuleManagerFactory.java
index 4a7223df7..3b771eee8 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/problems/rules/BackwardPropagationRuleManagerFactory.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/BackwardPropagationRuleManagerFactory.java
@@ -16,6 +16,7 @@
import soot.jimple.infoflow.problems.rules.backward.BackwardsWrapperRule;
import soot.jimple.infoflow.problems.rules.forward.SkipSystemClassRule;
import soot.jimple.infoflow.problems.rules.forward.StopAfterFirstKFlowsPropagationRule;
+import soot.jimple.infoflow.river.RiverPropagationRule;
/**
* Backward implementation of the {@link IPropagationRuleManagerFactory} class
@@ -49,6 +50,8 @@ public PropagationRuleManager createRuleManager(InfoflowManager manager, Abstrac
if (manager.getConfig().getImplicitFlowMode().trackControlFlowDependencies())
ruleList.add(BackwardsImplicitFlowRule.class);
+ if (manager.getConfig().getAdditionalFlowsEnabled())
+ ruleList.add(RiverPropagationRule.class);
return new PropagationRuleManager(manager, zeroValue, results, ruleList);
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/problems/rules/DefaultPropagationRuleManagerFactory.java b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/DefaultPropagationRuleManagerFactory.java
index bcdc98fe7..aad56609f 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/problems/rules/DefaultPropagationRuleManagerFactory.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/DefaultPropagationRuleManagerFactory.java
@@ -20,6 +20,7 @@
import soot.jimple.infoflow.problems.rules.forward.StrongUpdatePropagationRule;
import soot.jimple.infoflow.problems.rules.forward.TypingPropagationRule;
import soot.jimple.infoflow.problems.rules.forward.WrapperPropagationRule;
+import soot.jimple.infoflow.river.RiverPropagationRule;
/**
* Default implementation of the {@link IPropagationRuleManagerFactory} class
@@ -62,6 +63,8 @@ public PropagationRuleManager createRuleManager(InfoflowManager manager, Abstrac
ruleList.add(SkipSystemClassRule.class);
if (manager.getConfig().getStopAfterFirstKFlows() > 0)
ruleList.add(StopAfterFirstKFlowsPropagationRule.class);
+ if (manager.getConfig().getAdditionalFlowsEnabled())
+ ruleList.add(RiverPropagationRule.class);
return new PropagationRuleManager(manager, zeroValue, results, ruleList);
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/problems/rules/backward/BackwardsSourcePropagationRule.java b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/backward/BackwardsSourcePropagationRule.java
index 21a0e13f3..7a94172eb 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/problems/rules/backward/BackwardsSourcePropagationRule.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/backward/BackwardsSourcePropagationRule.java
@@ -1,15 +1,12 @@
package soot.jimple.infoflow.problems.rules.backward;
import java.util.Collection;
-import java.util.Collections;
import soot.SootMethod;
import soot.Value;
import soot.jimple.AssignStmt;
import soot.jimple.IdentityStmt;
import soot.jimple.IfStmt;
-import soot.jimple.InstanceInvokeExpr;
-import soot.jimple.InvokeExpr;
import soot.jimple.LookupSwitchStmt;
import soot.jimple.ReturnStmt;
import soot.jimple.Stmt;
@@ -19,8 +16,7 @@
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.river.Utils;
import soot.jimple.infoflow.sourcesSinks.manager.IReversibleSourceSinkManager;
import soot.jimple.infoflow.sourcesSinks.manager.SinkInfo;
import soot.jimple.infoflow.util.BaseSelector;
@@ -34,8 +30,7 @@
* @author Steven Arzt
* @author Tim Lange
*/
-public class BackwardsSourcePropagationRule extends AbstractTaintPropagationRule
- implements IAdditionalFlowSinkPropagationRule {
+public class BackwardsSourcePropagationRule extends AbstractTaintPropagationRule {
private boolean killState = false;
@@ -105,51 +100,10 @@ public Collection propagateCallFlow(Abstraction d1, Abstraction sou
return null;
}
- /**
- * Checks whether the given taint is visible inside the method called at the
- * given call site
- *
- * @param stmt A call site where a sink method is called
- * @param source The taint that has arrived at the given statement
- * @return True if the callee has access to the tainted value, false otherwise
- */
- protected boolean isTaintVisibleInCallee(Stmt stmt, Abstraction source) {
- InvokeExpr iexpr = stmt.getInvokeExpr();
- final Aliasing aliasing = getAliasing();
-
- // Is an argument tainted?
- final Value apBaseValue = source.getAccessPath().getPlainValue();
- if (apBaseValue != null && aliasing != null) {
- for (int i = 0; i < iexpr.getArgCount(); i++) {
- if (aliasing.mayAlias(iexpr.getArg(i), apBaseValue)) {
- if (source.getAccessPath().getTaintSubFields() || source.getAccessPath().isLocal())
- return true;
- }
- }
- }
-
- // Is the base object tainted?
- if (iexpr instanceof InstanceInvokeExpr) {
- if (((InstanceInvokeExpr) iexpr).getBase() == source.getAccessPath().getPlainValue())
- return true;
- }
-
- // Is return tainted?
- if (stmt instanceof AssignStmt && aliasing != null
- && aliasing.mayAlias(apBaseValue, ((AssignStmt) stmt).getLeftOp()))
- return true;
-
- return false;
- }
-
@Override
public Collection propagateCallToReturnFlow(Abstraction d1, Abstraction source, Stmt stmt,
ByReferenceBoolean killSource, ByReferenceBoolean killAll) {
- if (stmt.toString().equals(
- "r1 = virtualinvoke r0.()"))
- System.out.println("x");
-
if (!(manager.getSourceSinkManager() instanceof IReversibleSourceSinkManager))
return null;
final IReversibleSourceSinkManager ssm = (IReversibleSourceSinkManager) manager.getSourceSinkManager();
@@ -158,7 +112,7 @@ public Collection propagateCallToReturnFlow(Abstraction d1, Abstrac
if (source.isAbstractionActive() && !source.getAccessPath().isStaticFieldRef()
&& !source.getAccessPath().isEmpty()) {
// Is the taint even visible inside the callee?
- if (!stmt.containsInvokeExpr() || isTaintVisibleInCallee(stmt, source)) {
+ if (!stmt.containsInvokeExpr() || Utils.isTaintVisibleInCallee(stmt, source, getAliasing())) {
// Get the sink descriptor
SinkInfo sourceInfo = ssm.getInverseSourceInfo(stmt, getManager(), source.getAccessPath());
@@ -190,26 +144,4 @@ public Collection propagateReturnFlow(Collection calle
return null;
}
- // Note: Do not get confused with on the terms source/sink. In the general case,
- // the backward
- // analysis starts the analysis at sinks and records results at the source. For
- // secondary flows,
- // the secondary source is equal to the primary sink and the secondary sink is
- // an interesting
- // statement (an additional flow condition or a usage context) at which we
- // record a result.
- // That's why the backward source rule is also the secondary flow sink rule. */
- @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/problems/rules/forward/SinkPropagationRule.java b/soot-infoflow/src/soot/jimple/infoflow/problems/rules/forward/SinkPropagationRule.java
index c4039b3cc..626d1ffe7 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
@@ -185,7 +185,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) {
diff --git a/soot-infoflow/src/soot/jimple/infoflow/results/xml/InfoflowResultsSerializer.java b/soot-infoflow/src/soot/jimple/infoflow/results/xml/InfoflowResultsSerializer.java
index cfdb87154..f8c83a3fd 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/results/xml/InfoflowResultsSerializer.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/results/xml/InfoflowResultsSerializer.java
@@ -1,5 +1,6 @@
package soot.jimple.infoflow.results.xml;
+import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -68,29 +69,33 @@ public InfoflowResultsSerializer(IInfoflowCFG cfg, InfoflowConfiguration config)
*/
public void serialize(InfoflowResults results, String fileName) throws XMLStreamException, IOException {
this.startTime = System.currentTimeMillis();
- try (OutputStream out = new FileOutputStream(fileName)) {
+ File f = new File(fileName);
+ f.getParentFile().mkdirs(); // create parent directories
+ try (OutputStream out = new FileOutputStream(f)) {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = factory.createXMLStreamWriter(out, "UTF-8");
writer.writeStartDocument("UTF-8", "1.0");
writer.writeStartElement(XmlConstants.Tags.root);
writer.writeAttribute(XmlConstants.Attributes.fileFormatVersion, FILE_FORMAT_VERSION + "");
- writer.writeAttribute(XmlConstants.Attributes.terminationState,
- terminationStateToString(results.getTerminationState()));
// Write out the data flow results
- if (results != null && !results.isEmpty()) {
- writer.writeStartElement(XmlConstants.Tags.results);
- writeDataFlows(results, writer);
- writer.writeEndElement();
- }
-
- // Write out performance data
- InfoflowPerformanceData performanceData = results.getPerformanceData();
- if (performanceData != null && !performanceData.isEmpty()) {
- writer.writeStartElement(XmlConstants.Tags.performanceData);
- writePerformanceData(performanceData, writer);
- writer.writeEndElement();
+ if (results != null) {
+ writer.writeAttribute(XmlConstants.Attributes.terminationState,
+ terminationStateToString(results.getTerminationState()));
+ if (!results.isEmpty()) {
+ writer.writeStartElement(XmlConstants.Tags.results);
+ writeDataFlows(results, writer);
+ writer.writeEndElement();
+ }
+
+ // Write out performance data
+ InfoflowPerformanceData performanceData = results.getPerformanceData();
+ if (performanceData != null && !performanceData.isEmpty()) {
+ writer.writeStartElement(XmlConstants.Tags.performanceData);
+ writePerformanceData(performanceData, writer);
+ writer.writeEndElement();
+ }
}
writer.writeEndDocument();
@@ -99,8 +104,7 @@ public void serialize(InfoflowResults results, String fileName) throws XMLStream
}
/**
- * Converts the termination state from the enumeration to a human-readable
- * string
+ * Converts the termination state from the enumeration to a human-readable string
*
* @param terminationState The termination state
* @return A human-readable version of the termination state
@@ -123,8 +127,7 @@ private String terminationStateToString(int terminationState) {
}
/**
- * Writes out the given data flow performance data into the given XML stream
- * writer
+ * Writes out the given data flow performance data into the given XML stream writer
*
* @param performanceData The performance data to write out
* @param writer The stream writer into which to write the data
@@ -148,8 +151,8 @@ private void writePerformanceData(InfoflowPerformanceData performanceData, XMLSt
}
/**
- * Writes a single performance data entry into the XML file. An entry has a name
- * and a value, where the name describes the performance metric.
+ * Writes a single performance data entry into the XML file. An entry has a name and
+ * a value, where the name describes the performance metric.
*
* @param entryName The name that describes the performance metric
* @param entryValue The value of the performance metric
@@ -339,8 +342,8 @@ protected void writeAccessPath(AccessPath accessPath, XMLStreamWriter writer) th
* Sets whether the taint propagation path shall be serialized along with the
* respective data flow result
*
- * @param serialize True if taint propagation paths shall be serialized,
- * otherwise false
+ * @param serialize True if taint propagation paths shall be serialized, otherwise
+ * false
*/
public void setSerializeTaintPath(boolean serialize) {
this.serializeTaintPath = serialize;
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/BackwardNoSinkRuleManagerFactory.java b/soot-infoflow/src/soot/jimple/infoflow/river/BackwardNoSinkRuleManagerFactory.java
index c3425b6a6..6d6064220 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/BackwardNoSinkRuleManagerFactory.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/BackwardNoSinkRuleManagerFactory.java
@@ -50,6 +50,7 @@ public PropagationRuleManager createRuleManager(InfoflowManager manager, Abstrac
if (manager.getConfig().getImplicitFlowMode().trackControlFlowDependencies())
ruleList.add(new BackwardsImplicitFlowRule());
+ ruleList.add(new RiverPropagationRule());
return new PropagationRuleManager(manager, zeroValue, results, ruleList.toArray(new ITaintPropagationRule[0]));
}
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..4e1aefe61 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowSourceSinkManagerWrapper.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/ConditionalFlowSourceSinkManagerWrapper.java
@@ -5,64 +5,72 @@
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.ConditionalSinkInfo;
+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 ConditionalSinkInfo getConditionalSinkInfo(Stmt stmt, SootClass baseClass) {
+ return inner.getConditionalSinkInfo(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/IAdditionalFlowSinkPropagationRule.java b/soot-infoflow/src/soot/jimple/infoflow/river/IAdditionalFlowSinkPropagationRule.java
deleted file mode 100644
index 61bbd6105..000000000
--- a/soot-infoflow/src/soot/jimple/infoflow/river/IAdditionalFlowSinkPropagationRule.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package soot.jimple.infoflow.river;
-
-import soot.jimple.Stmt;
-import soot.jimple.infoflow.data.Abstraction;
-
-/**
- * Interface for Backward SourcePropagationRules that support conditional flows.
- * Note that in Secondary Flows the "source" is the sink of the primary flow and the
- * "sinks" are the statements reached in between
- *
- * @author Tim Lange
- */
-public interface IAdditionalFlowSinkPropagationRule {
- /**
- * Records a secondary flow taint reaching a statement.
- * Important: This method does not check whether the secondary flow should be recorded.
- *
- * @param d1 The calling context
- * @param source The current taint abstraction
- * @param stmt The current statement, which is assumed to be a sink
- */
- void processSecondaryFlowSink(Abstraction d1, Abstraction source, Stmt stmt);
-}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java b/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java
index e110bd6e0..6f6df4ed8 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/IConditionalFlowManager.java
@@ -3,43 +3,55 @@
import soot.SootClass;
import soot.SootMethod;
import soot.jimple.Stmt;
+import soot.jimple.infoflow.sourcesSinks.manager.ConditionalSinkInfo;
/**
- * 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 information about the conditional sink
+ */
+ ConditionalSinkInfo getConditionalSinkInfo(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/RiverPropagationRule.java b/soot-infoflow/src/soot/jimple/infoflow/river/RiverPropagationRule.java
new file mode 100644
index 000000000..43387f7f9
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/RiverPropagationRule.java
@@ -0,0 +1,91 @@
+package soot.jimple.infoflow.river;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import soot.SootMethod;
+import soot.jimple.Stmt;
+import soot.jimple.infoflow.data.Abstraction;
+import soot.jimple.infoflow.data.AbstractionAtSink;
+import soot.jimple.infoflow.problems.rules.AbstractTaintPropagationRule;
+import soot.jimple.infoflow.util.ByReferenceBoolean;
+
+/**
+ * Contains river-specific code that i.e. adds dataflow results when secondary
+ * sinks are reached.
+ */
+public class RiverPropagationRule extends AbstractTaintPropagationRule {
+
+ @Override
+ public Collection propagateNormalFlow(Abstraction d1, Abstraction source, Stmt stmt, Stmt destStmt,
+ ByReferenceBoolean killSource, ByReferenceBoolean killAll) {
+ return null;
+ }
+
+ @Override
+ public Collection propagateCallFlow(Abstraction d1, Abstraction source, Stmt stmt, SootMethod dest,
+ ByReferenceBoolean killAll) {
+ return null;
+ }
+
+ @Override
+ public Collection propagateCallToReturnFlow(Abstraction d1, Abstraction source, Stmt stmt,
+ ByReferenceBoolean killSource, ByReferenceBoolean killAll) {
+ return null;
+ }
+
+ @Override
+ public Collection propagateReturnFlow(Collection callerD1s, Abstraction calleeD1,
+ Abstraction source, Stmt stmt, Stmt retSite, Stmt callSite, ByReferenceBoolean killAll) {
+ return null;
+ }
+
+ // Note: Do not get confused with on the terms source/sink. In the general case,
+ // the backward
+ // analysis starts the analysis at sinks and records results at the source. For
+ // secondary flows,
+ // the secondary source is equal to the primary sink and the secondary sink is
+ // an interesting
+ // statement (an additional flow condition or a usage context) at which we
+ // record a result.
+ // That's why the backward source rule is also the secondary flow sink rule. */
+ /**
+ * Records a secondary flow taint reaching a statement. Important: This method
+ * does not check whether the secondary flow should be recorded.
+ *
+ * @param d1 The calling context
+ * @param source The current taint abstraction
+ * @param stmt The current statement, which is assumed to be a sink
+ */
+ 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() || !Utils.isTaintVisibleInCallee(stmt, source, getAliasing()))
+ return;
+
+ getResults().addResult(
+ new AbstractionAtSink(Collections.singleton(SecondarySinkDefinition.INSTANCE), source, stmt));
+ }
+
+ /**
+ * Records a secondary flow taint reaching a turn-around point. Important: This
+ * method does not check whether the secondary flow should be recorded.
+ *
+ * @param d1 The calling context
+ * @param source The current taint abstraction
+ * @param stmt The current statement, which is assumed to be a sink
+ */
+ public void processTurnAroundSink(Abstraction d1, Abstraction source, Stmt stmt) {
+
+ // Static fields are not part of the conditional flow model.
+ if (!source.isAbstractionActive() || source.getAccessPath().isStaticFieldRef())
+ return;
+
+ getResults().addResult(
+ new AbstractionAtSink(Collections.singleton(TurnAroundSecondarySinkDefinition.INSTANCE), source, stmt));
+ }
+
+}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java b/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java
index aae6fdd0a..4bdd5ff60 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/SecondaryFlowGenerator.java
@@ -5,17 +5,19 @@
import java.util.Set;
import heros.solver.PathEdge;
+import soot.Local;
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.ConditionalSinkInfo;
import soot.jimple.infoflow.sourcesSinks.manager.ISourceSinkManager;
/**
@@ -56,13 +58,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,14 +74,27 @@ 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());
+ Value baseLocal = ((InstanceInvokeExpr) stmt.getInvokeExpr()).getBase();
+ Abstraction baseTaint = Utils.getTaintFromLocal(outgoing, baseLocal);
// Is the base tainted in the outgoing set?
if (baseTaint != null && baseTaint.getAccessPath().getBaseType() instanceof RefType) {
RefType ref = (RefType) baseTaint.getAccessPath().getBaseType();
- if (condFlowManager.isConditionalSink(stmt, ref.getSootClass())) {
- Abstraction newAbs = createAdditionalFlowAbstraction(baseTaint, stmt);
- additionalAbsSet.add(newAbs);
+ ConditionalSinkInfo info = condFlowManager.getConditionalSinkInfo(stmt, ref.getSootClass());
+ if (info != null) {
+ Set locals = info.getTriggeredAdditionalFlows(stmt);
+ if (locals != null) {
+ for (Local l : locals) {
+ Abstraction newAbs;
+ if (l == baseLocal) {
+ newAbs = createAdditionalFlowAbstraction(baseTaint, stmt);
+ } else {
+ newAbs = createAdditionalFlowAbstraction(baseTaint.deriveNewAbstraction(
+ manager.getAccessPathFactory().createAccessPath(l, true), stmt), stmt);
+ }
+ additionalAbsSet.add(newAbs);
+ }
+ }
}
}
}
@@ -92,6 +107,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 +116,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 +131,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 +146,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..b29210cca 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;
@@ -15,7 +16,7 @@
* Attach to the backward analysis.
*/
public class SecondaryFlowListener implements TaintPropagationHandler {
- private IAdditionalFlowSinkPropagationRule sinkRule = null;
+ private RiverPropagationRule sinkRule = null;
/**
* Ensures that the field sourceRule is always set.
@@ -31,8 +32,8 @@ private void ensureSourcePropagationRule(InfoflowManager manager) {
PropagationRuleManager ruleManager = manager.getMainSolver().getTabulationProblem().getPropagationRules();
for (ITaintPropagationRule rule : ruleManager.getRules()) {
- if (rule instanceof IAdditionalFlowSinkPropagationRule) {
- sinkRule = (IAdditionalFlowSinkPropagationRule) rule;
+ if (rule instanceof RiverPropagationRule) {
+ sinkRule = (RiverPropagationRule) rule;
return;
}
}
@@ -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..2bc2698ae
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundFlowGenerator.java
@@ -0,0 +1,108 @@
+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.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));
+
+ }
+ }
+ }
+
+ 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/TurnAroundFlowListener.java b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundFlowListener.java
new file mode 100644
index 000000000..c54c73c3f
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/TurnAroundFlowListener.java
@@ -0,0 +1,75 @@
+package soot.jimple.infoflow.river;
+
+import java.util.Set;
+
+import soot.Unit;
+import soot.jimple.InvokeExpr;
+import soot.jimple.Stmt;
+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;
+
+/**
+ * TaintPropagationHandler to record which statements secondary flows reach.
+ * Attach to the backward analysis.
+ */
+public class TurnAroundFlowListener implements TaintPropagationHandler {
+ private RiverPropagationRule sinkRule = null;
+
+ /**
+ * Ensures that the field sourceRule is always set.
+ *
+ * @param manager
+ */
+ private void ensureSourcePropagationRule(InfoflowManager manager) {
+ if (sinkRule != null)
+ return;
+
+ if (!manager.getConfig().getAdditionalFlowsEnabled())
+ throw new IllegalStateException("Additional flows are not enabled!");
+
+ PropagationRuleManager ruleManager = manager.getMainSolver().getTabulationProblem().getPropagationRules();
+ for (ITaintPropagationRule rule : ruleManager.getRules()) {
+ if (rule instanceof RiverPropagationRule) {
+ sinkRule = (RiverPropagationRule) rule;
+ return;
+ }
+ }
+
+ throw new IllegalStateException(
+ "Enabled additional flows but no IConditionalFlowSinkPropagationRule in place!");
+ }
+
+ @Override
+ public void notifyFlowIn(Unit unit, Abstraction incoming, InfoflowManager manager, FlowFunctionType type) {
+ if (type != FlowFunctionType.CallToReturnFlowFunction)
+ return;
+
+ ensureSourcePropagationRule(manager);
+ if (!(manager.getSourceSinkManager() instanceof IConditionalFlowManager))
+ return;
+ if (!Utils.isReadAt(unit, incoming.getAccessPath()))
+ return;
+
+ final IConditionalFlowManager ssm = (IConditionalFlowManager) manager.getSourceSinkManager();
+
+ Stmt stmt = (Stmt) unit;
+ InvokeExpr inv = stmt.getInvokeExprUnsafe();
+ if (inv != null && ssm.isTurnAroundPoint(inv.getMethod())) {
+ // Record the statement
+ sinkRule.processTurnAroundSink(null, incoming, stmt);
+ }
+
+ }
+
+ @Override
+ public boolean notifyFlowOut(Unit stmt, Abstraction d1, Abstraction incoming, Set outgoing,
+ InfoflowManager manager, TaintPropagationResults results, FlowFunctionType type) {
+ // NO-OP
+ return false;
+ }
+
+}
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..317ab9920
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/Utils.java
@@ -0,0 +1,88 @@
+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.AssignStmt;
+import soot.jimple.InstanceInvokeExpr;
+import soot.jimple.InvokeExpr;
+import soot.jimple.Stmt;
+import soot.jimple.infoflow.aliasing.Aliasing;
+import soot.jimple.infoflow.data.Abstraction;
+import soot.jimple.infoflow.data.AccessPath;
+
+public class Utils {
+
+ /**
+ * Checks whether the given taint is visible inside the method called at the
+ * given call site
+ *
+ * @param stmt A call site where a sink method is called
+ * @param source The taint that has arrived at the given statement
+ * @param aliasing The aliasing strategy
+ * @return True if the callee has access to the tainted value, false otherwise
+ */
+ public static boolean isTaintVisibleInCallee(Stmt stmt, Abstraction source, Aliasing aliasing) {
+ InvokeExpr iexpr = stmt.getInvokeExpr();
+
+ // Is an argument tainted?
+ final Value apBaseValue = source.getAccessPath().getPlainValue();
+ if (apBaseValue != null && aliasing != null) {
+ for (int i = 0; i < iexpr.getArgCount(); i++) {
+ if (aliasing.mayAlias(iexpr.getArg(i), apBaseValue)) {
+ if (source.getAccessPath().getTaintSubFields() || source.getAccessPath().isLocal())
+ return true;
+ }
+ }
+ }
+
+ // Is the base object tainted?
+ if (iexpr instanceof InstanceInvokeExpr) {
+ if (((InstanceInvokeExpr) iexpr).getBase() == source.getAccessPath().getPlainValue())
+ return true;
+ }
+
+ // Is return tainted?
+ if (stmt instanceof AssignStmt && aliasing != null
+ && aliasing.mayAlias(apBaseValue, ((AssignStmt) stmt).getLeftOp()))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * 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..b1d56c4ce 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/river/conditions/SignatureFlowCondition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/river/conditions/SignatureFlowCondition.java
@@ -1,34 +1,51 @@
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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import heros.solver.Pair;
import soot.Scene;
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;
/**
- * A condition that checks additional data flow to see whether a source or sink
- * is valid or not based on classes and methods on the secondary data flow
+ * A condition that checks additional data flow to see whether a source or sink is valid
+ * or not based on classes and methods on the secondary data flow
*
* @author Steven Arzt
*
*/
public class SignatureFlowCondition extends SourceSinkCondition {
+ private final Logger logger = LoggerFactory.getLogger(getClass());
private final Set classNamesOnPath;
private final Set signaturesOnPath;
@@ -37,25 +54,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 excludedClassNames class names of primary sinks that should be
- * filtered without context, e.g.
- * ByteArrayOutputStream for OutputStream
+ * @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 +102,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();
}
@@ -179,8 +199,7 @@ public Set getExcludedClassNames() {
}
/**
- * Ensures that the set of Soot methods on the data flow path has been
- * initialized
+ * Ensures that the set of Soot methods on the data flow path has been initialized
*/
private void ensureSootMethodsOnPath() {
if (methodsOnPath == null) {
@@ -196,8 +215,7 @@ private void ensureSootMethodsOnPath() {
}
/**
- * Ensures that the set of Soot classeson the data flow path has been
- * initialized
+ * Ensures that the set of Soot classeson the data flow path has been initialized
*/
private void ensureSootClassesOnPath() {
if (classesOnPath == null)
@@ -225,29 +243,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 +315,82 @@ 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 {
+ logger.warn(String.format("Unsupported constant type %s: %s", v.getType(), v));
+ 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;
+ } else {
+ logger.warn(String.format(
+ "Non-constant used at parameter %d at statement %s in %s, cannot be evaluated", idx,
+ s.toString(), s.getContainingBody().getMethod().getSignature()));
+ continue nextStmt;
+ }
+ }
+ // all matched
+ return true;
+ }
+ return false;
}
/**
@@ -315,7 +443,7 @@ public boolean equals(Object obj) {
@Override
public String toString() {
return "AdditionalFlowCondition: " + "classNamesOnPath=" + classNamesOnPath + ", signaturesOnPath="
- + signaturesOnPath + ", excludedClasses=" + excludedClassNames;
+ + signaturesOnPath + ", excludedClasses=" + excludedClassNames + ", valuesOnPath=" + valuesOnPath;
}
@Override
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/AccessPathTuple.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/AccessPathTuple.java
index 9c4ef866f..c0841d93b 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/AccessPathTuple.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/AccessPathTuple.java
@@ -14,8 +14,8 @@
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.data.AccessPath;
import soot.jimple.infoflow.data.AccessPath.ArrayTaintType;
-import soot.jimple.infoflow.typing.TypeUtils;
import soot.jimple.infoflow.data.AccessPathFragment;
+import soot.jimple.infoflow.typing.TypeUtils;
/**
* Helper to save an AccessPath with the information about sink and sources.
@@ -32,6 +32,7 @@ public class AccessPathTuple {
private String description;
private int hashCode = 0;
+ private boolean triggerAdditionalFlow;
private static AccessPathTuple SOURCE_TUPLE;
private static AccessPathTuple SINK_TUPLE;
@@ -307,4 +308,12 @@ public String toString() {
return sb.toString();
}
+ public void setTriggerAdditionalFlow(boolean triggerAdditionalFlow) {
+ this.triggerAdditionalFlow = triggerAdditionalFlow;
+ }
+
+ public boolean isTriggerAdditionalFlow() {
+ return triggerAdditionalFlow;
+ }
+
}
diff --git a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/IAdditionalFlowTriggerInformation.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/IAdditionalFlowTriggerInformation.java
new file mode 100644
index 000000000..9acef7bd7
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/IAdditionalFlowTriggerInformation.java
@@ -0,0 +1,20 @@
+package soot.jimple.infoflow.sourcesSinks.definitions;
+
+import java.util.Set;
+
+import soot.Local;
+import soot.jimple.Stmt;
+
+/**
+ * Contains information about for what local variables to trigger additional
+ * flows
+ */
+public interface IAdditionalFlowTriggerInformation {
+ /**
+ * Returns a set of local variables for which to trigger additional flows
+ *
+ * @param stmt the statement
+ * @return the set of local variables
+ */
+ public Set getTriggeredAdditionalFlows(Stmt stmt);
+}
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..8e984ecd5 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/MethodSourceSinkDefinition.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/definitions/MethodSourceSinkDefinition.java
@@ -6,6 +6,12 @@
import java.util.HashSet;
import java.util.Set;
+import soot.Local;
+import soot.Value;
+import soot.jimple.AssignStmt;
+import soot.jimple.InstanceInvokeExpr;
+import soot.jimple.InvokeExpr;
+import soot.jimple.Stmt;
import soot.jimple.infoflow.data.SootMethodAndClass;
/**
@@ -16,7 +22,7 @@
*
*/
public class MethodSourceSinkDefinition extends AbstractSourceSinkDefinition
- implements IAccessPathBasedSourceSinkDefinition {
+ implements IAccessPathBasedSourceSinkDefinition, IAdditionalFlowTriggerInformation {
private static MethodSourceSinkDefinition BASE_OBJ_SOURCE;
private static MethodSourceSinkDefinition BASE_OBJ_SINK;
@@ -324,6 +330,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;
}
@@ -512,6 +519,59 @@ public Set getAllAccessPaths() {
return aps;
}
+ @Override
+ public Set getTriggeredAdditionalFlows(Stmt stmt) {
+ Set triggered = null;
+ InvokeExpr inv = stmt.getInvokeExpr();
+ if (inv instanceof InstanceInvokeExpr) {
+ boolean triggeredBase = true; // true by default
+ if (baseObjects != null) {
+ triggeredBase = false;
+ for (AccessPathTuple a : baseObjects) {
+ if (a.isTriggerAdditionalFlow()) {
+ triggeredBase = true;
+ break;
+ }
+ }
+ }
+
+ if (triggeredBase) {
+ triggered = new HashSet<>();
+ Value base = ((InstanceInvokeExpr) inv).getBase();
+ triggered.add((Local) base);
+ }
+ }
+ if (parameters != null) {
+ for (int i = 0; i < parameters.length; i++) {
+ Value param = inv.getArg(i);
+ if (parameters[i] != null && param instanceof Local) {
+ for (AccessPathTuple a : parameters[i]) {
+ if (a.isTriggerAdditionalFlow()) {
+ if (triggered == null)
+ triggered = new HashSet<>();
+ triggered.add((Local) param);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (returnValues != null && stmt instanceof AssignStmt) {
+ AssignStmt assign = (AssignStmt) stmt;
+
+ for (AccessPathTuple a : returnValues) {
+ if (a.isTriggerAdditionalFlow()) {
+ if (triggered == null)
+ triggered = new HashSet<>();
+ Value ret = assign.getLeftOp();
+ triggered.add((Local) ret);
+ break;
+ }
+ }
+ }
+ return triggered;
+ }
+
@SuppressWarnings("unchecked")
@Override
public MethodSourceSinkDefinition filter(Collection accessPaths) {
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..6c609079d 100644
--- a/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/BaseSourceSinkManager.java
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/BaseSourceSinkManager.java
@@ -69,6 +69,7 @@
public abstract class BaseSourceSinkManager
implements IReversibleSourceSinkManager, IOneSourceAtATimeManager, IConditionalFlowManager {
+
private final static String GLOBAL_SIG = "--GLOBAL--";
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -110,7 +111,7 @@ public static enum SourceType {
protected MultiMap sinkFields;
protected MultiMap sinkStatements;
- protected Set conditionalSinks = new HashSet<>();
+ protected Map conditionalSinks = new HashMap<>();
protected MultiMap conditionalSinkToExcludedClasses = new HashMultiMap<>();
protected Set secondarySinkMethods = new HashSet<>();
protected Set secondarySinkClasses = new HashSet<>();
@@ -161,6 +162,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.
@@ -840,7 +843,13 @@ private void initializeConditions(SootMethod m, ISourceSinkDefinition def) {
if (m == null || def.getConditions() == null || def.getConditions().isEmpty())
return;
- conditionalSinks.add(m);
+ conditionalSinks.compute(m, (key, existing) -> {
+ if (existing == null)
+ existing = new ConditionalSinkInfo(def);
+ else
+ existing.add(def);
+ return existing;
+ });
for (SourceSinkCondition cond : def.getConditions()) {
conditionalSinkToExcludedClasses.putAll(m, cond.getExcludedClasses());
secondarySinkMethods.addAll(cond.getReferencedMethods());
@@ -1083,10 +1092,11 @@ public void excludeMethod(SootMethod toExclude) {
@Override
public boolean isSecondarySink(Stmt stmt) {
- if (!stmt.containsInvokeExpr() || !(stmt.getInvokeExpr() instanceof InstanceInvokeExpr))
+ InvokeExpr inv = stmt.getInvokeExprUnsafe();
+ if (inv == null)
return false;
- SootMethod callee = stmt.getInvokeExpr().getMethod();
+ SootMethod callee = inv.getMethod();
SootClass dc = callee.getDeclaringClass();
if (secondarySinkMethods.contains(callee) || secondarySinkClasses.contains(dc))
return true;
@@ -1135,23 +1145,49 @@ private boolean isExcludedInCondition(SootMethod matchedSink, SootClass baseClas
}
@Override
- public boolean isConditionalSink(Stmt stmt, SootClass baseClass) {
+ public ConditionalSinkInfo getConditionalSinkInfo(Stmt stmt, SootClass baseClass) {
// River only supports InstanceInvokeExprs
if (!stmt.containsInvokeExpr() || !(stmt.getInvokeExpr() instanceof InstanceInvokeExpr))
- return false;
+ return null;
// Check if we have a direct hit
SootMethod callee = stmt.getInvokeExpr().getMethod();
- if (conditionalSinks.contains(callee))
- return !isExcludedInCondition(callee, baseClass);
+ ConditionalSinkInfo info = conditionalSinks.get(callee);
+ if (info != null && !isExcludedInCondition(callee, baseClass)) {
+ return info;
+ }
// Check if the current method inherits from a conditional sink
for (SootClass sc : parentClassesAndInterfaces.getUnchecked(callee.getDeclaringClass())) {
SootMethod superMethod = sc.getMethodUnsafe(callee.getSubSignature());
- if (conditionalSinks.contains(superMethod))
- return !isExcludedInCondition(superMethod, baseClass);
+ info = conditionalSinks.get(superMethod);
+ if (info != null && !isExcludedInCondition(superMethod, baseClass)) {
+ return info;
+ }
}
- return false;
+ return null;
}
+
+ @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/ConditionalSinkInfo.java b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/ConditionalSinkInfo.java
new file mode 100644
index 000000000..43ba7e7e7
--- /dev/null
+++ b/soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/ConditionalSinkInfo.java
@@ -0,0 +1,47 @@
+package soot.jimple.infoflow.sourcesSinks.manager;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import soot.Local;
+import soot.jimple.Stmt;
+import soot.jimple.infoflow.sourcesSinks.definitions.IAdditionalFlowTriggerInformation;
+import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinition;
+
+public final class ConditionalSinkInfo implements IAdditionalFlowTriggerInformation {
+ private List triggerInformation = new ArrayList<>();
+
+ public ConditionalSinkInfo(ISourceSinkDefinition def) {
+ add(def);
+ }
+
+ public void add(ISourceSinkDefinition def) {
+ if (def instanceof IAdditionalFlowTriggerInformation) {
+ triggerInformation.add((IAdditionalFlowTriggerInformation) def);
+ }
+ }
+
+ @Override
+ public Set getTriggeredAdditionalFlows(Stmt stmt) {
+ Set l = null;
+ boolean createdSet = false;
+ for (IAdditionalFlowTriggerInformation t : triggerInformation) {
+ Set tr = t.getTriggeredAdditionalFlows(stmt);
+ if (tr != null && !tr.isEmpty()) {
+ if (l == null)
+ l = tr;
+ else {
+ if (!createdSet) {
+ l = new HashSet<>(l);
+ createdSet = true;
+ }
+ l.addAll(tr);
+ }
+ }
+ }
+ return l;
+ }
+
+}
\ No newline at end of file
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());
}
}