Skip to content

Commit 8dfa211

Browse files
committed
improved sink detection
1 parent 28c5024 commit 8dfa211

1 file changed

Lines changed: 33 additions & 85 deletions

File tree

soot-infoflow/src/soot/jimple/infoflow/sourcesSinks/manager/BaseSourceSinkManager.java

Lines changed: 33 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import java.util.List;
1111
import java.util.Map;
1212
import java.util.Set;
13+
import java.util.concurrent.ExecutionException;
14+
import java.util.stream.Collectors;
1315

1416
import org.slf4j.Logger;
1517
import org.slf4j.LoggerFactory;
@@ -19,6 +21,7 @@
1921

2022
import heros.solver.IDESolver;
2123
import heros.solver.Pair;
24+
import soot.Hierarchy;
2225
import soot.Scene;
2326
import soot.SootClass;
2427
import soot.SootField;
@@ -111,19 +114,35 @@ public static enum SourceType {
111114
protected SootMethod currentSource = null;
112115
protected IValueProvider valueProvider = new SimpleConstantValueProvider();
113116

114-
protected final LoadingCache<SootClass, Collection<SootClass>> interfacesOf = IDESolver.DEFAULT_CACHE_BUILDER
117+
protected final LoadingCache<SootClass, Collection<SootClass>> parentClassesAndInterfaces = IDESolver.DEFAULT_CACHE_BUILDER
115118
.build(new CacheLoader<SootClass, Collection<SootClass>>() {
116119

117120
@Override
118121
public Collection<SootClass> load(SootClass sc) throws Exception {
119-
Set<SootClass> set = new HashSet<SootClass>(sc.getInterfaceCount());
120-
for (SootClass i : sc.getInterfaces()) {
121-
set.add(i);
122-
set.addAll(interfacesOf.getUnchecked(i));
123-
}
124-
if (sc.hasSuperclass())
125-
set.addAll(interfacesOf.getUnchecked(sc.getSuperclass()));
126-
return set;
122+
Hierarchy h = Scene.v().getActiveHierarchy();
123+
124+
// Don't try to find sources or sinks in irrelevant classes
125+
if (sc.isPhantom() || sc.hasTag(SimulatedCodeElementTag.TAG_NAME))
126+
return Collections.emptySet();
127+
128+
// For interfaces, we compute the transitive list of parent interfaces
129+
if (sc.isInterface())
130+
return h.getSuperinterfacesOfIncluding(sc);
131+
132+
// We need to collect all interfaces of all superclasses. First, we take the
133+
// superclasses, and then we call this method recursively on all interfaces
134+
// declared on these classes.
135+
Set<SootClass> res = new HashSet<>();
136+
res.addAll(h.getSuperclassesOfIncluding(sc));
137+
138+
res.addAll(res.stream().flatMap(c -> c.getInterfaces().stream()).flatMap(i -> {
139+
try {
140+
return parentClassesAndInterfaces.get(i).stream();
141+
} catch (ExecutionException e) {
142+
throw new RuntimeException(e);
143+
}
144+
}).collect(Collectors.toSet()));
145+
return res;
127146
}
128147

129148
});
@@ -227,7 +246,8 @@ protected ISourceSinkDefinition getSinkDefinition(Stmt sCallSite, InfoflowManage
227246
final String subSig = callee.getSubSignature();
228247

229248
// Check whether we have any of the interfaces on the list
230-
for (SootClass i : interfacesOf.getUnchecked(sCallSite.getInvokeExpr().getMethod().getDeclaringClass())) {
249+
for (SootClass i : parentClassesAndInterfaces
250+
.getUnchecked(sCallSite.getInvokeExpr().getMethod().getDeclaringClass())) {
231251
if (i.declaresMethod(subSig)) {
232252
ISourceSinkDefinition def = this.sinkMethods.get(i.getMethod(subSig));
233253
if (def != null)
@@ -242,16 +262,7 @@ protected ISourceSinkDefinition getSinkDefinition(Stmt sCallSite, InfoflowManage
242262
return def;
243263
}
244264

245-
// If the target method is in a phantom class, we scan the hierarchy
246-
// upwards to see whether we have a sink definition for a parent
247-
// class
248-
if (callee.getDeclaringClass().isPhantom()) {
249-
ISourceSinkDefinition def = findDefinitionInHierarchy(callee, this.sinkMethods);
250-
if (def != null)
251-
return def;
252-
}
253265
return null;
254-
255266
} else if (sCallSite instanceof AssignStmt) {
256267
// Check if the target is a sink field
257268
AssignStmt assignStmt = (AssignStmt) sCallSite;
@@ -291,7 +302,7 @@ protected ISourceSinkDefinition getInverseSource(Stmt sCallSite, InfoflowManager
291302

292303
// Check whether we have any of the interfaces on the list
293304
final String subSig = callee.getSubSignature();
294-
for (SootClass i : interfacesOf.getUnchecked(callee.getDeclaringClass())) {
305+
for (SootClass i : parentClassesAndInterfaces.getUnchecked(callee.getDeclaringClass())) {
295306
SootMethod m = i.getMethodUnsafe(subSig);
296307
if (m != null) {
297308
def = getSourceDefinition(m);
@@ -306,15 +317,6 @@ protected ISourceSinkDefinition getInverseSource(Stmt sCallSite, InfoflowManager
306317
if (def != null)
307318
return def;
308319
}
309-
310-
// If the target method is in a phantom class, we scan the hierarchy
311-
// upwards
312-
// to see whether we have a sink definition for a parent class
313-
if (callee.getDeclaringClass().isPhantom()) {
314-
def = findDefinitionInHierarchy(callee, this.sourceMethods);
315-
if (def != null)
316-
return def;
317-
}
318320
}
319321

320322
// This call might read out sensitive data from the UI
@@ -336,42 +338,6 @@ protected ISourceSinkDefinition getInverseSource(Stmt sCallSite, InfoflowManager
336338
return null;
337339
}
338340

339-
/**
340-
* Scans the hierarchy of the class containing the given method to find any
341-
* implementations of the same method further up in the hierarchy for which
342-
* there is a SourceSinkDefinition in the given map
343-
*
344-
* @param callee The method for which to look for a SourceSinkDefinition
345-
* @param map A map from methods to their corresponding SourceSinkDefinitions
346-
* @return A SourceSinKDefinition for an implementation of the given method
347-
* somewhere up in the class hiearchy if it exists, otherwise null.
348-
*/
349-
private static ISourceSinkDefinition findDefinitionInHierarchy(SootMethod callee,
350-
Map<SootMethod, ISourceSinkDefinition> map) {
351-
final String subSig = callee.getSubSignature();
352-
SootClass curClass = callee.getDeclaringClass();
353-
while (curClass != null) {
354-
// Does the current class declare the requested method?
355-
SootMethod curMethod = curClass.getMethodUnsafe(subSig);
356-
if (curMethod != null) {
357-
ISourceSinkDefinition def = map.get(curMethod);
358-
if (def != null) {
359-
// Patch the map to contain a direct link
360-
map.put(callee, def);
361-
return def;
362-
}
363-
}
364-
365-
// Try the next class up the hierarchy
366-
if (curClass.hasSuperclass() && (curClass.isPhantom() || callee.hasTag(SimulatedCodeElementTag.TAG_NAME)))
367-
curClass = curClass.getSuperclass();
368-
else
369-
curClass = null;
370-
}
371-
372-
return null;
373-
}
374-
375341
@Override
376342
public SinkInfo getSinkInfo(Stmt sCallSite, InfoflowManager manager, AccessPath ap) {
377343
// Do not look for sinks in excluded methods
@@ -582,7 +548,7 @@ protected ISourceSinkDefinition getSource(Stmt sCallSite, IInfoflowCFG cfg) {
582548

583549
// Check whether we have any of the interfaces on the list
584550
final String subSig = callee.getSubSignature();
585-
for (SootClass i : interfacesOf.getUnchecked(callee.getDeclaringClass())) {
551+
for (SootClass i : parentClassesAndInterfaces.getUnchecked(callee.getDeclaringClass())) {
586552
SootMethod m = i.getMethodUnsafe(subSig);
587553
if (m != null) {
588554
def = getSourceDefinition(m);
@@ -597,15 +563,6 @@ protected ISourceSinkDefinition getSource(Stmt sCallSite, IInfoflowCFG cfg) {
597563
if (def != null)
598564
return def;
599565
}
600-
601-
// If the target method is in a phantom class, we scan the hierarchy
602-
// upwards
603-
// to see whether we have a sink definition for a parent class
604-
if (callee.getDeclaringClass().isPhantom() || callee.hasTag(SimulatedCodeElementTag.TAG_NAME)) {
605-
def = findDefinitionInHierarchy(callee, this.sourceMethods);
606-
if (def != null)
607-
return def;
608-
}
609566
}
610567

611568
// This call might read out sensitive data from the UI
@@ -651,7 +608,7 @@ protected ISourceSinkDefinition getInverseSink(Stmt sCallSite, IInfoflowCFG cfg)
651608
final String subSig = callee.getSubSignature();
652609

653610
// Check whether we have any of the interfaces on the list
654-
for (SootClass i : interfacesOf.getUnchecked(callee.getDeclaringClass())) {
611+
for (SootClass i : parentClassesAndInterfaces.getUnchecked(callee.getDeclaringClass())) {
655612
if (i.declaresMethod(subSig)) {
656613
ISourceSinkDefinition def = this.sinkMethods.get(i.getMethod(subSig));
657614
if (def != null)
@@ -666,16 +623,7 @@ protected ISourceSinkDefinition getInverseSink(Stmt sCallSite, IInfoflowCFG cfg)
666623
return def;
667624
}
668625

669-
// If the target method is in a phantom class, we scan the hierarchy
670-
// upwards to see whether we have a sink definition for a parent
671-
// class
672-
if (callee.getDeclaringClass().isPhantom() || callee.hasTag(SimulatedCodeElementTag.TAG_NAME)) {
673-
ISourceSinkDefinition def = findDefinitionInHierarchy(callee, this.sinkMethods);
674-
if (def != null)
675-
return def;
676-
}
677626
return null;
678-
679627
} else if (sCallSite instanceof AssignStmt) {
680628
// Check if the target is a sink field
681629
AssignStmt assignStmt = (AssignStmt) sCallSite;

0 commit comments

Comments
 (0)