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