Skip to content

Commit 223804d

Browse files
authored
Merge pull request #558 from timll/fixFullPathBuilder
Refine path building from cache and fix backward full path reconstruction
2 parents 0663c9e + ba822f8 commit 223804d

File tree

12 files changed

+65
-128
lines changed

12 files changed

+65
-128
lines changed

soot-infoflow/src/soot/jimple/infoflow/data/AccessPathFactory.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Arrays;
44
import java.util.Collection;
5+
import java.util.Collections;
56
import java.util.Set;
67

78
import org.slf4j.Logger;
@@ -417,7 +418,7 @@ public AccessPath createAccessPath(Value val, Type valType, AccessPathFragment[]
417418

418419
private void registerBase(Type eiType, AccessPathFragment[] base) {
419420
Set<AccessPathFragment[]> bases = baseRegister.computeIfAbsent(eiType,
420-
t -> new TCustomHashSet<>(new HashingStrategy<AccessPathFragment[]>() {
421+
t -> Collections.synchronizedSet(new TCustomHashSet<>(new HashingStrategy<AccessPathFragment[]>() {
421422

422423
@Override
423424
public int computeHashCode(AccessPathFragment[] arg0) {
@@ -429,7 +430,7 @@ public boolean equals(AccessPathFragment[] arg0, AccessPathFragment[] arg1) {
429430
return Arrays.equals(arg0, arg1);
430431
}
431432

432-
}));
433+
})));
433434
bases.add(base);
434435
}
435436

soot-infoflow/src/soot/jimple/infoflow/data/SourceContextAndPath.java

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package soot.jimple.infoflow.data;
22

3-
import java.util.ArrayList;
4-
import java.util.Collections;
5-
import java.util.Iterator;
6-
import java.util.List;
3+
import java.util.*;
74

85
import heros.solver.Pair;
96
import soot.jimple.Stmt;
@@ -90,19 +87,19 @@ public SourceContextAndPath extendPath(SourceContextAndPath other) {
9087
if (this.path == null || other.path == null || other.path.size() <= this.path.size())
9188
return null;
9289

93-
ArrayList<Abstraction> buf = new ArrayList<>(other.path.size() - this.path.size());
90+
Stack<Abstraction> pathStack = new Stack<>();
9491
Abstraction lastAbs = this.getLastAbstraction();
9592
boolean foundCommonAbs = false;
9693

9794
// Collect all additional abstractions on the cached path
9895
Iterator<Abstraction> pathIt = other.path.reverseIterator();
9996
while (pathIt.hasNext()) {
10097
Abstraction next = pathIt.next();
101-
if (next == lastAbs) {
98+
if (next == lastAbs || (next.neighbors != null && next.neighbors.contains(lastAbs))) {
10299
foundCommonAbs = true;
103100
break;
104101
}
105-
buf.add(next);
102+
pathStack.push(next);
106103
}
107104

108105
// If the paths do not have a common abstraction, there's probably something wrong...
@@ -111,15 +108,15 @@ public SourceContextAndPath extendPath(SourceContextAndPath other) {
111108

112109
// Append the additional abstractions to the new taint propagation path
113110
SourceContextAndPath extendedScap = clone();
114-
for (Abstraction abs : buf)
115-
extendedScap.path.add(abs);
111+
while (!pathStack.isEmpty())
112+
extendedScap.path.add(pathStack.pop());
116113

117114
int newCallStackCapacity = other.getCallStackSize() - this.getCallStackSize();
118115
// Sanity Check: The callStack of other should always be larger than the one of this
119116
if (newCallStackCapacity < 0)
120117
return null;
121118
if (newCallStackCapacity > 0) {
122-
ArrayList<Stmt> callStackBuf = new ArrayList<>(newCallStackCapacity);
119+
Stack<Stmt> callStackBuf = new Stack<>();
123120
Stmt topStmt = this.callStack == null ? null : this.callStack.getLast();
124121

125122
// Collect all additional statements on the call stack...
@@ -128,15 +125,15 @@ public SourceContextAndPath extendPath(SourceContextAndPath other) {
128125
Stmt next = callStackIt.next();
129126
if (next == topStmt)
130127
break;
131-
callStackBuf.add(next);
128+
callStackBuf.push(next);
132129
}
133130

134131
if (callStackBuf.size() > 0) {
135132
if (extendedScap.callStack == null)
136133
extendedScap.callStack = new ExtensibleList<>();
137134
// ...and append them.
138-
for (Stmt stmt : callStackBuf)
139-
extendedScap.callStack.add(stmt);
135+
while (!callStackBuf.isEmpty())
136+
extendedScap.callStack.add(callStackBuf.pop());
140137
}
141138
}
142139

@@ -213,32 +210,15 @@ public SourceContextAndPath extendPath(Abstraction abs, InfoflowConfiguration co
213210
}
214211

215212
// Extend the call stack
216-
switch (config.getDataFlowDirection()) {
217-
case Forwards:
218-
if (abs.getCorrespondingCallSite() != null && abs.getCorrespondingCallSite() != abs.getCurrentStmt()) {
219-
if (scap == null)
220-
scap = this.clone();
221-
if (scap.callStack == null)
222-
scap.callStack = new ExtensibleList<Stmt>();
223-
else if (pathConfig != null && pathConfig.getMaxCallStackSize() > 0
224-
&& scap.callStack.size() >= pathConfig.getMaxCallStackSize())
225-
return null;
226-
scap.callStack.add(abs.getCorrespondingCallSite());
227-
}
228-
break;
229-
case Backwards:
230-
if (abs.getCurrentStmt() != null && abs.getCurrentStmt().containsInvokeExpr()
231-
&& abs.getCorrespondingCallSite() != abs.getCurrentStmt()) {
232-
if (scap == null)
233-
scap = this.clone();
234-
if (scap.callStack == null)
235-
scap.callStack = new ExtensibleList<Stmt>();
236-
else if (pathConfig != null && pathConfig.getMaxCallStackSize() > 0
237-
&& scap.callStack.size() >= pathConfig.getMaxCallStackSize())
238-
return null;
239-
scap.callStack.add(abs.getCurrentStmt());
240-
}
241-
break;
213+
if (abs.getCorrespondingCallSite() != null && abs.getCorrespondingCallSite() != abs.getCurrentStmt()) {
214+
if (scap == null)
215+
scap = this.clone();
216+
if (scap.callStack == null)
217+
scap.callStack = new ExtensibleList<Stmt>();
218+
else if (pathConfig != null && pathConfig.getMaxCallStackSize() > 0
219+
&& scap.callStack.size() >= pathConfig.getMaxCallStackSize())
220+
return null;
221+
scap.callStack.add(abs.getCorrespondingCallSite());
242222
}
243223

244224
this.neighborCounter = abs.getNeighbors() == null ? 0 : abs.getNeighbors().size();

soot-infoflow/src/soot/jimple/infoflow/data/pathBuilders/ContextInsensitivePathBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ private boolean checkForSource(Abstraction abs, SourceContextAndPath scap) {
129129
SourceContext sourceContext = abs.getSourceContext();
130130
results.addResult(scap.getDefinition(), scap.getAccessPath(), scap.getStmt(), sourceContext.getDefinition(),
131131
sourceContext.getAccessPath(), sourceContext.getStmt(), sourceContext.getUserData(),
132-
scap.getAbstractionPath());
132+
scap.getAbstractionPath(), manager);
133133
return true;
134134
}
135135

soot-infoflow/src/soot/jimple/infoflow/data/pathBuilders/ContextInsensitiveSourceFinder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public void run() {
8787
results.addResult(flagAbs.getSinkDefinition(), flagAbs.getAbstraction().getAccessPath(),
8888
flagAbs.getSinkStmt(), abstraction.getSourceContext().getDefinition(),
8989
abstraction.getSourceContext().getAccessPath(), abstraction.getSourceContext().getStmt(),
90-
abstraction.getSourceContext().getUserData(), null);
90+
abstraction.getSourceContext().getUserData(), null, manager);
9191

9292
// Sources may not have predecessors
9393
assert abstraction.getPredecessor() == null;

soot-infoflow/src/soot/jimple/infoflow/data/pathBuilders/ContextSensitivePathBuilder.java

Lines changed: 29 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ public class ContextSensitivePathBuilder extends ConcurrentAbstractionPathBuilde
3333
protected ConcurrentIdentityHashMultiMap<Abstraction, SourceContextAndPath> pathCache = new ConcurrentIdentityHashMultiMap<>();
3434

3535
// Set holds all paths that reach an already cached subpath
36-
protected ConcurrentHashSet<Pair<SourceContextAndPath, SourceContextAndPath>> deferredPaths = new ConcurrentHashSet<>();
36+
protected ConcurrentHashSet<SourceContextAndPath> deferredPaths = new ConcurrentHashSet<>();
37+
// Set holds all paths that reach a source
38+
protected ConcurrentHashSet<SourceContextAndPath> sourceReachingScaps = new ConcurrentHashSet<>();
3739

3840
/**
3941
* Creates a new instance of the {@link ContextSensitivePathBuilder} class
@@ -76,7 +78,7 @@ public SourceFindingTask(Abstraction abstraction) {
7678
@Override
7779
public void run() {
7880
final Set<SourceContextAndPath> paths = pathCache.get(abstraction);
79-
final Abstraction pred = abstraction.getPredecessor();
81+
Abstraction pred = abstraction.getPredecessor();
8082

8183
if (pred != null && paths != null) {
8284
for (SourceContextAndPath scap : paths) {
@@ -94,14 +96,6 @@ public void run() {
9496
}
9597

9698
private void processAndQueue(Abstraction pred, SourceContextAndPath scap) {
97-
// Skip abstractions that don't contain any new information. This might
98-
// be the case when a turn unit was added to the abstraction.
99-
if (pred.getCorrespondingCallSite() == null && pred.getCurrentStmt() == null
100-
&& pred.getTurnUnit() != null) {
101-
processAndQueue(pred.getPredecessor(), scap);
102-
return;
103-
}
104-
10599
ProcessingResult p = processPredecessor(scap, pred);
106100
switch (p.getResult()) {
107101
case NEW:
@@ -112,7 +106,7 @@ private void processAndQueue(Abstraction pred, SourceContextAndPath scap) {
112106
case CACHED:
113107
// In case we already know the subpath, we do append the path after the path
114108
// builder terminated
115-
deferredPaths.add(new Pair<>(scap, p.getScap()));
109+
deferredPaths.add(scap);
116110
break;
117111
case INFEASIBLE_OR_MAX_PATHS_REACHED:
118112
// Nothing to do
@@ -130,7 +124,8 @@ private ProcessingResult processPredecessor(SourceContextAndPath scap, Abstracti
130124
if (extendedScap == null)
131125
return ProcessingResult.INFEASIBLE_OR_MAX_PATHS_REACHED();
132126

133-
checkForSource(pred, extendedScap);
127+
if (checkForSource(pred, extendedScap))
128+
sourceReachingScaps.add(extendedScap);
134129
return pathCache.put(pred, extendedScap) ? ProcessingResult.NEW()
135130
: ProcessingResult.CACHED(extendedScap);
136131
}
@@ -141,44 +136,24 @@ private ProcessingResult processPredecessor(SourceContextAndPath scap, Abstracti
141136
return ProcessingResult.INFEASIBLE_OR_MAX_PATHS_REACHED();
142137

143138
// Check if we are in the right context
144-
switch (manager.getConfig().getDataFlowDirection()) {
145-
case Forwards:
146-
if (pred.getCurrentStmt() != null && pred.getCurrentStmt().containsInvokeExpr()) {
147-
// Pop the top item off the call stack. This gives us the item
148-
// and the new SCAP without the item we popped off.
149-
Pair<SourceContextAndPath, Stmt> pathAndItem = extendedScap.popTopCallStackItem();
150-
if (pathAndItem != null) {
151-
Stmt topCallStackItem = pathAndItem.getO2();
152-
// Make sure that we don't follow an unrealizable path
153-
if (topCallStackItem != pred.getCurrentStmt())
154-
return ProcessingResult.INFEASIBLE_OR_MAX_PATHS_REACHED();
155-
156-
// We have returned from a function
157-
extendedScap = pathAndItem.getO1();
158-
}
159-
}
160-
break;
161-
case Backwards:
162-
if (pred.getCorrespondingCallSite() != null
163-
&& pred.getCorrespondingCallSite() != pred.getCurrentStmt()) {
164-
// Pop the top item off the call stack. This gives us the item
165-
// and the new SCAP without the item we popped off.
166-
Pair<SourceContextAndPath, Stmt> pathAndItem = extendedScap.popTopCallStackItem();
167-
if (pathAndItem != null) {
168-
Stmt topCallStackItem = pathAndItem.getO2();
169-
// Make sure that we don't follow an unrealizable path
170-
if (topCallStackItem != pred.getCorrespondingCallSite())
171-
return ProcessingResult.INFEASIBLE_OR_MAX_PATHS_REACHED();
172-
173-
// We have returned from a function
174-
extendedScap = pathAndItem.getO1();
175-
}
139+
if (pred.getCurrentStmt() != null && pred.getCurrentStmt().containsInvokeExpr()) {
140+
// Pop the top item off the call stack. This gives us the item
141+
// and the new SCAP without the item we popped off.
142+
Pair<SourceContextAndPath, Stmt> pathAndItem = extendedScap.popTopCallStackItem();
143+
if (pathAndItem != null) {
144+
Stmt topCallStackItem = pathAndItem.getO2();
145+
// Make sure that we don't follow an unrealizable path
146+
if (topCallStackItem != pred.getCurrentStmt())
147+
return ProcessingResult.INFEASIBLE_OR_MAX_PATHS_REACHED();
148+
149+
// We have returned from a function
150+
extendedScap = pathAndItem.getO1();
176151
}
177-
break;
178152
}
179153

180154
// Add the new path
181-
checkForSource(pred, extendedScap);
155+
if (checkForSource(pred, extendedScap))
156+
sourceReachingScaps.add(extendedScap);
182157

183158
final int maxPaths = config.getPathConfiguration().getMaxPathsPerAbstraction();
184159
if (maxPaths > 0) {
@@ -291,27 +266,14 @@ public void computeTaintPaths(Set<AbstractionAtSink> res) {
291266
}
292267

293268
/**
294-
* Uses the cached path to extend the current path
295-
*
296-
* @param scap SourceContextAndPath of the current abstraction
297-
* @param cachedScap cached SourceContextAndPath to extend scap
269+
* Tries to fill up deferred paths toward a source.
298270
*/
299-
protected void buildFullPathFromCache(SourceContextAndPath scap, SourceContextAndPath cachedScap) {
300-
// Try to extend scap with cachedScap
301-
Stack<Pair<SourceContextAndPath, SourceContextAndPath>> workStack = new Stack<>();
302-
workStack.push(new Pair<>(scap, cachedScap));
303-
while (!workStack.isEmpty()) {
304-
Pair<SourceContextAndPath, SourceContextAndPath> p = workStack.pop();
305-
scap = p.getO1();
306-
cachedScap = p.getO2();
307-
308-
SourceContextAndPath extendedScap = scap.extendPath(cachedScap);
309-
if (extendedScap != null) {
310-
Abstraction last = extendedScap.getLastAbstraction();
311-
// Try to build the path further using the cache if we didn't reach a source
312-
if (!checkForSource(last, extendedScap))
313-
for (SourceContextAndPath preds : pathCache.get(last.getPredecessor()))
314-
workStack.push(new Pair<>(extendedScap, preds));
271+
protected void buildPathsFromCache() {
272+
for (SourceContextAndPath deferredScap : deferredPaths) {
273+
for (SourceContextAndPath sourceScap : sourceReachingScaps) {
274+
SourceContextAndPath fullScap = deferredScap.extendPath(sourceScap);
275+
if (fullScap != null)
276+
checkForSource(fullScap.getLastAbstraction(), fullScap);
315277
}
316278
}
317279
}
@@ -320,9 +282,7 @@ protected void buildFullPathFromCache(SourceContextAndPath scap, SourceContextAn
320282
* Method that is called when the taint paths have been computed
321283
*/
322284
protected void onTaintPathsComputed() {
323-
for (Pair<SourceContextAndPath, SourceContextAndPath> deferredPair : deferredPaths) {
324-
buildFullPathFromCache(deferredPair.getO1(), deferredPair.getO2());
325-
}
285+
buildPathsFromCache();
326286
}
327287

328288
/**

soot-infoflow/src/soot/jimple/infoflow/data/pathBuilders/RecursivePathBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public void run() {
145145
for (SourceContextAndPath context : getPaths(lastTaskId++, abs.getAbstraction(), initialStack)) {
146146
results.addResult(abs.getSinkDefinition(), abs.getAbstraction().getAccessPath(),
147147
abs.getSinkStmt(), context.getDefinition(), context.getAccessPath(), context.getStmt(),
148-
context.getUserData(), context.getAbstractionPath());
148+
context.getUserData(), context.getAbstractionPath(), manager);
149149
}
150150
}
151151

soot-infoflow/src/soot/jimple/infoflow/problems/rules/backward/BackwardsImplicitFlowRule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ public Collection<Abstraction> propagateCallToReturnFlow(Abstraction d1, Abstrac
243243
for (Unit condUnit : condUnits) {
244244
Abstraction abs = new Abstraction(sink.getDefinition(), AccessPath.getEmptyAccessPath(), stmt,
245245
sink.getUserData(), false, false);
246+
abs.setCorrespondingCallSite(stmt);
246247
abs.setDominator(condUnit);
247248
res.add(abs);
248249
}
@@ -252,6 +253,7 @@ public Collection<Abstraction> propagateCallToReturnFlow(Abstraction d1, Abstrac
252253
.createAccessPath(sm.getActiveBody().getThisLocal(), false);
253254
Abstraction thisTaint = new Abstraction(sink.getDefinition(), thisAp, stmt, sink.getUserData(),
254255
false, false);
256+
thisTaint.setCorrespondingCallSite(stmt);
255257
res.add(thisTaint);
256258
}
257259

soot-infoflow/src/soot/jimple/infoflow/problems/rules/backward/BackwardsSinkPropagationRule.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ private Collection<Abstraction> propagate(Abstraction source, Stmt stmt, ByRefer
5656
// Create the new taint abstraction
5757
Abstraction abs = new Abstraction(sinkInfo.getDefinition(), ap, stmt, sinkInfo.getUserData(), false,
5858
false);
59+
abs.setCorrespondingCallSite(stmt);
5960
abs = abs.deriveNewAbstractionWithTurnUnit(stmt);
6061

6162
res.add(abs);

soot-infoflow/src/soot/jimple/infoflow/results/InfoflowResults.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,6 @@ public void addResult(ISourceSinkDefinition sinkDefinition, AccessPath sink, Stm
153153
new ResultSourceInfo(sourceDefinition, source, sourceStmt, pathAgnosticResults));
154154
}
155155

156-
public Pair<ResultSourceInfo, ResultSinkInfo> addResult(ISourceSinkDefinition sinkDefinition, AccessPath sink,
157-
Stmt sinkStmt, ISourceSinkDefinition sourceDefinition, AccessPath source, Stmt sourceStmt, Object userData,
158-
List<Abstraction> propagationPath) {
159-
return addResult(sinkDefinition, sink, sinkStmt, sourceDefinition, source, sourceStmt, userData,
160-
propagationPath, null);
161-
}
162-
163156
public Pair<ResultSourceInfo, ResultSinkInfo> addResult(ISourceSinkDefinition sinkDefinition, AccessPath sink,
164157
Stmt sinkStmt, ISourceSinkDefinition sourceDefinition, AccessPath source, Stmt sourceStmt, Object userData,
165158
List<Abstraction> propagationPath, InfoflowManager manager) {

soot-infoflow/src/soot/jimple/infoflow/taintWrappers/EasyTaintWrapper.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,6 @@ public Set<AccessPath> getInverseTaintsForMethodInternal(Stmt stmt, Abstraction
354354
if (wrapType == MethodWrapType.KillTaint)
355355
return Collections.emptySet();
356356

357-
// If the base was tainted, one parameter could be responsible for this but we don't know,
358-
// maybe it also was tainted before. So we have to keep it.
359-
taints.add(taintedPath);
360-
361357
if (wrapType == MethodWrapType.CreateTaint && taintedAbs.getDominator() != null
362358
&& taintedAbs.getDominator() != null)
363359
taints.add(AccessPath.getEmptyAccessPath());
@@ -376,6 +372,10 @@ public Set<AccessPath> getInverseTaintsForMethodInternal(Stmt stmt, Abstraction
376372
}
377373
}
378374

375+
// Keep the incoming taint if it is not the lhs
376+
if (!taintedObj)
377+
taints.add(taintedPath);
378+
379379
// if base object is tainted, we need to taint all parameters
380380
if (isSupported && wrapType == MethodWrapType.CreateTaint) {
381381
// If we are inside a conditional, we always taint

0 commit comments

Comments
 (0)