All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.jimple.infoflow.methodSummary.generator.SummaryGenerationTaintWrapper Maven / Gradle / Ivy

package soot.jimple.infoflow.methodSummary.generator;

import java.util.*;

import soot.*;
import soot.jimple.DefinitionStmt;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InvokeExpr;
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.data.SourceContext;
import soot.jimple.infoflow.handlers.PreAnalysisHandler;
import soot.jimple.infoflow.methodSummary.data.sourceSink.ConstraintType;
import soot.jimple.infoflow.methodSummary.data.sourceSink.FlowSource;
import soot.jimple.infoflow.methodSummary.data.summary.GapDefinition;
import soot.jimple.infoflow.methodSummary.data.summary.MethodSummaries;
import soot.jimple.infoflow.methodSummary.data.summary.SourceSinkType;
import soot.jimple.infoflow.methodSummary.generator.SummaryGeneratorConfiguration.TaintCondition;
import soot.jimple.infoflow.methodSummary.generator.gaps.IGapManager;
import soot.jimple.infoflow.methodSummary.util.AliasUtils;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinition;
import soot.jimple.infoflow.taintWrappers.ITaintPropagationWrapper;
import soot.jimple.toolkits.callgraph.Edge;

/**
 * Taint wrapper to be used during summary construction. If we find a call for
 * which we have no callee, we create a gap in our summary. This means that this
 * taint wrapper needs to produce fake sources for the possible outcomes of the
 * code inside the gap.
 * 
 * @author Steven Arzt
 */
public class SummaryGenerationTaintWrapper implements ITaintPropagationWrapper {

	protected InfoflowManager manager;

	protected final MethodSummaries summaries;
	protected final IGapManager gapManager;

	public SummaryGenerationTaintWrapper(MethodSummaries summaries, IGapManager gapManager) {
		this.summaries = summaries;
		this.gapManager = gapManager;
	}

	@Override
	public void initialize(InfoflowManager manager) {
		this.manager = manager;
	}

	@Override
	public Collection getPreAnalysisHandlers() {
		return Collections.emptyList();
	}

	@Override
	public Set getTaintsForMethod(Stmt stmt, Abstraction d1, Abstraction taintedPath) {
		// This must be a method invocation
		if (!stmt.containsInvokeExpr())
			return Collections.singleton(taintedPath);

		// Check whether we need to create a gap
		if (!gapManager.needsGapConstruction(stmt, taintedPath, manager.getICFG()))
			return Collections.singleton(taintedPath);

		// If we have already seen this statement, we just pass on
		if (!taintedPath.isAbstractionActive())
			return Collections.singleton(taintedPath);

		// If this is a call to a system method, we just over-approximate the
		// taint
		if (manager.getICFG().getMethodOf(stmt).getDeclaringClass().getName().equals("java.lang.System"))
			return Collections.singleton(taintedPath);

		// We do not model hashCode() and equals() for performance reasons
		Set res = getTaintsForHashCodeEquals(stmt, taintedPath);
		if (res != null)
			return res;

		// Do create the gap
		GapDefinition gap = gapManager.getOrCreateGapForCall(summaries, stmt);
		if (gap == null)
			return Collections.singleton(taintedPath);

		// Produce a continuation
		res = new HashSet();
		InvokeExpr iexpr = stmt.getInvokeExpr();
		if (iexpr instanceof InstanceInvokeExpr) {
			AccessPath ap = manager.getAccessPathFactory()
					.createAccessPath(((InstanceInvokeExpr) stmt.getInvokeExpr()).getBase(), true);
			res.add(getContinuation(taintedPath, ap, gap, stmt));
		}
		for (Value paramVal : stmt.getInvokeExpr().getArgs())
			if (AccessPath.canContainValue(paramVal)) {
				AccessPath ap = manager.getAccessPathFactory().createAccessPath(paramVal, true);
				if (AliasUtils.canAccessPathHaveAliases(ap))
					res.add(getContinuation(taintedPath, ap, gap, stmt));
			}
		if (stmt instanceof DefinitionStmt) {
			AccessPath ap = manager.getAccessPathFactory().createAccessPath(((DefinitionStmt) stmt).getLeftOp(), true);
			res.add(getContinuation(taintedPath, ap, gap, stmt));
		}

		return res;
	}

	/**
	 * Gets the taints for hashCode() and equals() and other methods with default
	 * taints if the summary generator is configured to not summarizes these methods
	 * 
	 * @param stmt        The statement that might call a method with default taint
	 * @param taintedPath The incoming taint abstraction
	 * @return The taint abstractions with which to continue the data flow analysis,
	 *         or null if this method does not model the call. If the
	 *         callee is handled, but no taint abstractions shall be propagated,
	 *         this method returns an empty set.
	 */
	protected Set getTaintsForHashCodeEquals(Stmt stmt, Abstraction taintedPath) {
		final InvokeExpr iexpr = stmt.getInvokeExpr();
		final SummaryGeneratorConfiguration config = (SummaryGeneratorConfiguration) manager.getConfig();

		// The calls to methods with default taints are always virtual calls
		if (iexpr instanceof InstanceInvokeExpr && !config.getSummarizeHashCodeEquals()) {
			SootMethodRef ref = iexpr.getMethodRef();
			InstanceInvokeExpr iiexpr = (InstanceInvokeExpr) iexpr;
			AccessPath ap = taintedPath.getAccessPath();

			TaintCondition taintCondition = config.getDefaultTaints().get(ref.getSubSignature().toString());
			if (taintCondition != null) {
				final Set taints = new HashSet();

				// We always keep the incoming taint
				taints.add(taintedPath);

				if (stmt instanceof DefinitionStmt) {
					DefinitionStmt defStmt = (DefinitionStmt) stmt;

					// Taint the return value only if the incoming tainted path is part of the
					// invoke expression
					if (ap.getPlainValue() == iiexpr.getBase() || iiexpr.getArgs().contains(ap.getPlainValue())) {

						// If the taint condition is fulfilled, the return value is tainted
						if (taintCondition.equals(TaintCondition.TaintAlways)
								|| (taintCondition.equals(TaintCondition.TaintOnImplicit)
										&& config.getImplicitFlowMode().trackControlFlowDependencies()))
							taints.add(taintedPath.deriveNewAbstraction(
									manager.getAccessPathFactory().createAccessPath(defStmt.getLeftOp(), false), stmt));
					}
				}

				return taints;
			}
		}

		// This is not a special method that we handle
		return null;
	}

	/**
	 * Creates a continuation at a gap. A continuation is a new abstraction without
	 * a predecessor that has the gap definition as its source.
	 * 
	 * @param source     The source abstraction that flowed into the gap
	 * @param accessPath The new acces path that shall be tainted after the gap
	 * @param gap
	 * @param stmt
	 * @return
	 */
	private Abstraction getContinuation(Abstraction source, AccessPath accessPath, GapDefinition gap, Stmt stmt) {
		// Make sure that we don't break anything
		Abstraction newOutAbs = source.clone().deriveNewAbstraction(accessPath, stmt);

		// Create the source information pointing to the gap. This may not be unique
		newOutAbs.setPredecessor(null);

		// If no longer have a predecessor, we must fake a source context
		newOutAbs.setSourceContext(new SourceContext((Collection) null, accessPath, stmt, getFlowSource(accessPath, stmt, gap)));

		return newOutAbs;
	}

	/**
	 * Creates a flow source based on an access path and a gap invocation statement.
	 * The flow source need not necessarily be unique. For a call z=b.foo(a,a), the
	 * flow source for access path "a" can either be parameter 0 or parameter 1.
	 * 
	 * @param accessPath The access path for which to create the flow source
	 * @param stmt       The statement that calls the sink with the given access
	 *                   path
	 * @param gap        definition of the gap from which the data flow originates
	 * @return The set of generated flow sources
	 */
	private Set getFlowSource(AccessPath accessPath, Stmt stmt, GapDefinition gap) {
		Set res = new HashSet();

		// This can be a base object
		if (stmt.getInvokeExpr() instanceof InstanceInvokeExpr)
			if (((InstanceInvokeExpr) stmt.getInvokeExpr()).getBase() == accessPath.getPlainValue())
				res.add(new FlowSource(SourceSinkType.Field, accessPath.getBaseType().toString(), gap, ConstraintType.FALSE));

		// This can be a parameter
		for (int i = 0; i < stmt.getInvokeExpr().getArgCount(); i++)
			if (stmt.getInvokeExpr().getArg(i) == accessPath.getPlainValue())
				res.add(new FlowSource(SourceSinkType.Parameter, i, accessPath.getBaseType().toString(), gap, ConstraintType.FALSE));

		// This can be a return value
		if (stmt instanceof DefinitionStmt)
			if (((DefinitionStmt) stmt).getLeftOp() == accessPath.getPlainValue())
				res.add(new FlowSource(SourceSinkType.Return, accessPath.getBaseType().toString(), gap, ConstraintType.FALSE));

		return res;
	}

	@Override
	public boolean isExclusive(Stmt stmt, Abstraction taintedPath) {
		return gapManager.needsGapConstruction(stmt, taintedPath, manager.getICFG());
	}

	@Override
	public boolean supportsCallee(SootMethod method) {
		// Callees are always theoretically supported
		return true;
	}

	@Override
	public boolean supportsCallee(Stmt callSite) {
		// We only wrap calls that have no callees
		Iterator edgeIt = Scene.v().getCallGraph().edgesOutOf(callSite);
		return !edgeIt.hasNext();
	}

	@Override
	public int getWrapperHits() {
		// Statics reporting is not supported by this taint wrapper
		return -1;
	}

	@Override
	public int getWrapperMisses() {
		// Statics reporting is not supported by this taint wrapper
		return -1;
	}

	@Override
	public Set getAliasesForMethod(Stmt stmt, Abstraction d1, Abstraction taintedPath) {
		// We don't need to process aliases
		return null;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy