@Override public boolean isExclusive(Stmt stmt, Abstraction taintedPath) { if (isExclusiveInternal(stmt, taintedPath.getAccessPath())) { wrapperHits.incrementAndGet(); return true; } else { wrapperMisses.incrementAndGet(); return false; } }
@Override public Set<Abstraction> getTaintsForMethod(Stmt stmt, Abstraction d1, Abstraction taintedPath) { // Compute the tainted access paths Set<AccessPath> aps = getTaintsForMethodInternal(stmt, taintedPath.getAccessPath()); if (aps == null || aps.isEmpty()) return null; // Convert the access paths into full abstractions Set<Abstraction> res = new HashSet<Abstraction>(aps.size()); for (AccessPath ap : aps) if (ap == taintedPath.getAccessPath()) res.add(taintedPath); else res.add(taintedPath.deriveNewAbstraction(ap, stmt)); return res; }
@Override public Collection<Abstraction> propagateCallToReturnFlow(Abstraction d1, Abstraction source, Stmt stmt, ByReferenceBoolean killSource, ByReferenceBoolean killAll) { // Compute the taint wrapper taints Collection<Abstraction> wrapperTaints = computeWrapperTaints(d1, stmt, source); if (wrapperTaints != null) { // If the taint wrapper generated an abstraction for // the incoming access path, we assume it to be handled // and do not pass on the incoming abstraction on our own for (Abstraction wrapperAbs : wrapperTaints) if (wrapperAbs.getAccessPath().equals(source.getAccessPath())) { if (wrapperAbs != source) killSource.value = true; break; } } return wrapperTaints; }
@Override public void computeAliasTaints(Abstraction d1, Stmt src, Value targetValue, Set<Abstraction> taintSet, SootMethod method, Abstraction newAbs) { computeAliasTaintsInternal(d1, method, newAbs, Collections.<SootField>emptyList(), Collections.<Type>emptyList(), newAbs.getAccessPath().getTaintSubFields(), src); }
/** * Checks whether the given base value matches the base of the given taint * abstraction and ends there. So a will match a, but not a.x. Not that this * function will still match a to a.*. * * @param baseValue The value to check * @param source The taint abstraction to check * @return True if the given value has the same base value as the given taint * abstraction and no further elements, otherwise false */ public static boolean baseMatchesStrict(final Value baseValue, Abstraction source) { if (!baseMatches(baseValue, source)) return false; if (baseValue instanceof Local) return source.getAccessPath().isLocal(); else if (baseValue instanceof InstanceFieldRef || baseValue instanceof StaticFieldRef) return source.getAccessPath().getFieldCount() == 1; throw new RuntimeException("Unexpected left side"); }
@Override public Collection<Abstraction> propagateReturnFlow(Collection<Abstraction> callerD1s, Abstraction source, Stmt stmt, Stmt retSite, Stmt callSite, ByReferenceBoolean killAll) { // We only handle taints on static variables if (!source.getAccessPath().isStaticFieldRef()) return null; // Static field tracking can be disabled if (getManager().getConfig().getStaticFieldTrackingMode() == StaticFieldTrackingMode.None && source.getAccessPath().isStaticFieldRef()) { killAll.value = true; return null; } // Simply pass on the taint return Collections.singleton(source.deriveNewAbstraction(source.getAccessPath(), stmt)); }
public Pair<ResultSourceInfo, ResultSinkInfo> addResult(SourceSinkDefinition sinkDefinition, AccessPath sink, Stmt sinkStmt, SourceSinkDefinition sourceDefinition, AccessPath source, Stmt sourceStmt, Object userData, List<Abstraction> propagationPath) { // Get the statements and the access paths from the abstractions List<Stmt> stmtPath = null; List<AccessPath> apPath = null; if (propagationPath != null) { stmtPath = new ArrayList<>(propagationPath.size()); apPath = new ArrayList<>(propagationPath.size()); for (Abstraction pathAbs : propagationPath) { if (pathAbs.getCurrentStmt() != null) { stmtPath.add(pathAbs.getCurrentStmt()); apPath.add(pathAbs.getAccessPath()); } } } // Add the result return addResult(sinkDefinition, sink, sinkStmt, sourceDefinition, source, sourceStmt, userData, stmtPath, apPath); }
@Override public Collection<Abstraction> propagateCallToReturnFlow(Abstraction d1, Abstraction source, Stmt stmt, ByReferenceBoolean killSource, ByReferenceBoolean killAll) { // Do not propagate abstractions for locals that get overwritten if (stmt instanceof AssignStmt) { // a = foo() with a tainted AssignStmt assignStmt = (AssignStmt) stmt; if (!source.getAccessPath().isStaticFieldRef() && assignStmt.getLeftOp() instanceof Local && getAliasing().mayAlias(assignStmt.getLeftOp(), source.getAccessPath().getPlainValue())) killSource.value = true; } return null; }
@Override public void run() { Stack<Pair<Stmt, Set<Abstraction>>> initialStack = new Stack<Pair<Stmt, Set<Abstraction>>>(); initialStack.push(new Pair<Stmt, Set<Abstraction>>(null, Collections.newSetFromMap(new IdentityHashMap<Abstraction, Boolean>()))); for (SourceContextAndPath context : getPaths(lastTaskId++, abs.getAbstraction(), initialStack)) { results.addResult(abs.getSinkDefinition(), abs.getAbstraction().getAccessPath(), abs.getSinkStmt(), context.getDefinition(), context.getAccessPath(), context.getStmt(), context.getUserData(), context.getAbstractionPath()); } }
@Override protected Runnable getTaintPathTask(AbstractionAtSink abs) { SourceContextAndPath scap = new SummarySourceContextAndPath(manager, abs.getAbstraction().getAccessPath(), abs.getSinkStmt(), AliasUtils.canAccessPathHaveAliases(abs.getAbstraction().getAccessPath()), abs.getAbstraction().getAccessPath(), new ArrayList<SootMethod>(), context); scap = scap.extendPath(abs.getAbstraction()); if (scap != null) { if (pathCache.put(abs.getAbstraction(), scap)) if (!checkForSource(abs.getAbstraction(), scap)) return new SourceFindingTask(abs.getAbstraction()); } return null; }
@Override public Collection<Abstraction> propagateNormalFlow(Abstraction d1, Abstraction source, Stmt stmt, Stmt destStmt, ByReferenceBoolean killSource, ByReferenceBoolean killAll) { // Check for a typecast on the right side of an assignment if (!source.getAccessPath().isStaticFieldRef() && stmt instanceof DefinitionStmt) { DefinitionStmt defStmt = (DefinitionStmt) stmt; if (defStmt.getRightOp() instanceof CastExpr) { CastExpr ce = (CastExpr) defStmt.getRightOp(); if (ce.getOp() == source.getAccessPath().getPlainValue()) { // If the typecast is not compatible with the current type, we // have to kill the taint if (!getManager().getTypeUtils().checkCast(source.getAccessPath(), ce.getCastType())) { killAll.value = true; } } } } return null; }
@Override public Collection<Abstraction> propagateCallToReturnFlow(Abstraction d1, Abstraction source, Stmt stmt, ByReferenceBoolean killSource, ByReferenceBoolean killAll) { // Static field tracking can be disabled if (getManager().getConfig().getStaticFieldTrackingMode() == StaticFieldTrackingMode.None && source.getAccessPath().isStaticFieldRef()) { killAll.value = true; return null; } // nothing to do here return null; }
/** * Checks whether the given value is used in the given statement * @param stmt The statement to check * @param abs The value to check * @return True if the given value is used in the given statement, otherwise * false */ private boolean isValueUsedInStmt(Stmt stmt, Abstraction abs) { if (!stmt.containsInvokeExpr()) return false; InvokeExpr iexpr = stmt.getInvokeExpr(); // If this value is a parameter, we take it for (int i = 0; i < iexpr.getArgCount(); i++) if (abs.getAccessPath().getPlainValue() == iexpr.getArg(i)) return true; // If this is the base local, we take it return iexpr instanceof InstanceInvokeExpr && ((InstanceInvokeExpr) iexpr).getBase() == abs.getAccessPath().getPlainValue(); }
public Abstraction deriveInactiveAbstraction(Stmt activationUnit) { if (!flowSensitiveAliasing) { assert this.isAbstractionActive(); return this; } // If this abstraction is already inactive, we keep it if (!this.isAbstractionActive()) return this; Abstraction a = deriveNewAbstractionMutable(accessPath, null); if (a == null) return null; a.postdominators = null; a.activationUnit = activationUnit; a.dependsOnCutAP |= a.getAccessPath().isCutOffApproximation(); return a; }
@Override public Collection<Abstraction> propagateReturnFlow(Collection<Abstraction> callerD1s, Abstraction source, Stmt stmt, Stmt retSite, Stmt callSite, ByReferenceBoolean killAll) { // If we throw an exception with a tainted operand, we need to // handle this specially if (stmt instanceof ThrowStmt && retSite instanceof DefinitionStmt) { DefinitionStmt defRetStmt = (DefinitionStmt) retSite; if (defRetStmt.getRightOp() instanceof CaughtExceptionRef) { ThrowStmt throwStmt = (ThrowStmt) stmt; if (getAliasing().mayAlias(throwStmt.getOp(), source.getAccessPath().getPlainValue())) return Collections.singleton(source.deriveNewAbstractionOnThrow(throwStmt)); } } return null; }
@Override public Collection<Abstraction> propagateReturnFlow(Collection<Abstraction> callerD1s, Abstraction source, Stmt stmt, Stmt retSite, Stmt callSite, ByReferenceBoolean killAll) { // Check whether this return is treated as a sink if (stmt instanceof ReturnStmt) { final ReturnStmt returnStmt = (ReturnStmt) stmt; boolean matches = source.getAccessPath().isLocal() || source.getAccessPath().getTaintSubFields(); if (matches && source.isAbstractionActive() && getManager().getSourceSinkManager() != null && getAliasing().mayAlias(source.getAccessPath().getPlainValue(), returnStmt.getOp())) { SinkInfo sinkInfo = getManager().getSourceSinkManager().getSinkInfo(returnStmt, getManager(), source.getAccessPath()); if (sinkInfo != null && !getResults().addResult(new AbstractionAtSink(sinkInfo.getDefinition(), source, returnStmt))) killState = true; } } // If we are in the kill state, we stop the analysis if (killAll != null) killAll.value |= killState; return null; }
protected Abstraction deriveNewAbstractionMutable(AccessPath p, Stmt currentStmt) { // An abstraction needs an access path if (p == null) return null; if (this.accessPath.equals(p) && this.currentStmt == currentStmt) { Abstraction abs = clone(); abs.currentStmt = currentStmt; return abs; } Abstraction abs = new Abstraction(p, this); abs.predecessor = this; abs.currentStmt = currentStmt; abs.propagationPathLength = propagationPathLength + 1; if (!abs.getAccessPath().isEmpty()) abs.postdominators = null; if (!abs.isAbstractionActive()) abs.dependsOnCutAP = abs.dependsOnCutAP || p.isCutOffApproximation(); abs.sourceContext = null; return abs; }
@Override protected Runnable getTaintPathTask(final AbstractionAtSink abs) { SourceContextAndPath scap = new SourceContextAndPath(abs.getSinkDefinition(), abs.getAbstraction().getAccessPath(), abs.getSinkStmt()); scap = scap.extendPath(abs.getAbstraction(), pathConfig); if (pathCache.put(abs.getAbstraction(), scap)) if (!checkForSource(abs.getAbstraction(), scap)) return new SourceFindingTask(abs.getAbstraction()); return null; }
@Override protected Runnable getTaintPathTask(final AbstractionAtSink abs) { SourceContextAndPath scap = new SourceContextAndPath(abs.getSinkDefinition(), abs.getAbstraction().getAccessPath(), abs.getSinkStmt()); scap = scap.extendPath(abs.getAbstraction(), pathConfig); if (pathCache.put(abs.getAbstraction(), scap)) if (!checkForSource(abs.getAbstraction(), scap)) return new SourceFindingTask(abs.getAbstraction()); return null; }
@Override public Collection<Abstraction> propagateCallFlow(Abstraction d1, Abstraction source, Stmt stmt, SootMethod dest, ByReferenceBoolean killAll) { // Normally, we don't inspect source methods if (!getManager().getConfig().getInspectSources() && getManager().getSourceSinkManager() != null) { final SourceInfo sourceInfo = getManager().getSourceSinkManager().getSourceInfo(stmt, getManager()); if (sourceInfo != null) killAll.value = true; } // By default, we don't inspect sinks either if (!getManager().getConfig().getInspectSinks() && getManager().getSourceSinkManager() != null) { final boolean isSink = getManager().getSourceSinkManager().getSinkInfo(stmt, getManager(), source.getAccessPath()) != null; if (isSink) killAll.value = true; } return null; }