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

soot.jimple.infoflow.sourcesSinks.manager.BaseSourceSinkManager Maven / Gradle / Ivy

There is a newer version: 2.9.0
Show newest version
package soot.jimple.infoflow.sourcesSinks.manager;

import static soot.SootClass.DANGLING;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import heros.solver.IDESolver;
import heros.solver.Pair;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.VoidType;
import soot.jimple.AssignStmt;
import soot.jimple.DefinitionStmt;
import soot.jimple.FieldRef;
import soot.jimple.IdentityStmt;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.ParameterRef;
import soot.jimple.ReturnStmt;
import soot.jimple.Stmt;
import soot.jimple.infoflow.InfoflowConfiguration;
import soot.jimple.infoflow.InfoflowConfiguration.CallbackSourceMode;
import soot.jimple.infoflow.InfoflowConfiguration.SourceSinkConfiguration;
import soot.jimple.infoflow.InfoflowManager;
import soot.jimple.infoflow.callbacks.CallbackDefinition;
import soot.jimple.infoflow.data.AccessPath;
import soot.jimple.infoflow.data.AccessPath.ArrayTaintType;
import soot.jimple.infoflow.data.SootMethodAndClass;
import soot.jimple.infoflow.solver.cfg.IInfoflowCFG;
import soot.jimple.infoflow.sourcesSinks.definitions.AccessPathTuple;
import soot.jimple.infoflow.sourcesSinks.definitions.FieldSourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.MethodSourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.MethodSourceSinkDefinition.CallType;
import soot.jimple.infoflow.sourcesSinks.definitions.StatementSourceSinkDefinition;
import soot.jimple.infoflow.util.SystemClassHandler;
import soot.jimple.infoflow.values.IValueProvider;
import soot.jimple.infoflow.values.SimpleConstantValueProvider;
import soot.jimple.toolkits.ide.icfg.BiDiInterproceduralCFG;
import soot.util.HashMultiMap;
import soot.util.MultiMap;

public abstract class BaseSourceSinkManager implements ISourceSinkManager, IOneSourceAtATimeManager {
	private final static String GLOBAL_SIG = "--GLOBAL--";

	private final Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * Types of sources supported by this SourceSinkManager
	 *
	 * @author Steven Arzt
	 */
	public static enum SourceType {
		/**
		 * Not a source
		 */
		NoSource,
		/**
		 * The data is obtained via a method call
		 */
		MethodCall,
		/**
		 * The data is retrieved through a callback parameter
		 */
		Callback,
		/**
		 * The data is read from a UI element
		 */
		UISource
	}

	protected MultiMap sourceDefs;
	protected MultiMap sinkDefs;

	protected Map sourceMethods;
	protected Map sourceStatements;
	protected Map sinkMethods;
	protected Map sinkReturnMethods;
	protected Map callbackMethods;
	protected Map sourceFields;
	protected Map sinkFields;
	protected Map sinkStatements;

	protected final SourceSinkConfiguration sourceSinkConfig;

	protected final Set excludedMethods = new HashSet<>();

	protected boolean oneSourceAtATime = false;
	protected SourceType osaatType = SourceType.MethodCall;
	protected Iterator osaatIterator = null;
	protected SootMethod currentSource = null;
	protected IValueProvider valueProvider = new SimpleConstantValueProvider();

	protected final LoadingCache> interfacesOf = IDESolver.DEFAULT_CACHE_BUILDER
			.build(new CacheLoader>() {

				@Override
				public Collection load(SootClass sc) throws Exception {
					Set set = new HashSet(sc.getInterfaceCount());
					for (SootClass i : sc.getInterfaces()) {
						set.add(i);
						set.addAll(interfacesOf.getUnchecked(i));
					}
					if (sc.hasSuperclass())
						set.addAll(interfacesOf.getUnchecked(sc.getSuperclass()));
					return set;
				}

			});

	/**
	 * Creates a new instance of the {@link BaseSourceSinkManager} class with either
	 * strong or weak matching.
	 *
	 * @param sources The list of source methods
	 * @param sinks   The list of sink methods
	 * @param config  The configuration of the data flow analyzer
	 */
	public BaseSourceSinkManager(Set sources,
			Set sinks, InfoflowConfiguration config) {
		this(sources, sinks, Collections.emptySet(), config);
	}

	/**
	 * Creates a new instance of the {@link BaseSourceSinkManager} class with strong
	 * matching, i.e. the methods in the code must exactly match those in the list.
	 *
	 * @param sources         The list of source methods
	 * @param sinks           The list of sink methods
	 * @param callbackMethods The list of callback methods whose parameters are
	 *                        sources through which the application receives data
	 *                        from the operating system
	 * @param weakMatching    True for weak matching: If an entry in the list has no
	 *                        return type, it matches arbitrary return types if the
	 *                        rest of the method signature is compatible. False for
	 *                        strong matching: The method signature in the code
	 *                        exactly match the one in the list.
	 * @param config          The configuration of the data flow analyzer
	 */
	public BaseSourceSinkManager(Set sources,
			Set sinks, Set callbackMethods,
			InfoflowConfiguration config) {
		this.sourceSinkConfig = config.getSourceSinkConfig();

		this.sourceDefs = new HashMultiMap<>();
		for (ISourceSinkDefinition am : sources)
			this.sourceDefs.put(getSignature(am), am);

		this.sinkDefs = new HashMultiMap<>();
		for (ISourceSinkDefinition am : sinks)
			this.sinkDefs.put(getSignature(am), am);

		this.callbackMethods = new HashMap<>();
		for (CallbackDefinition cb : callbackMethods)
			this.callbackMethods.put(cb.getTargetMethod(), cb);

		logger.info(String.format("Created a SourceSinkManager with %d sources, %d sinks, and %d callback methods.",
				this.sourceDefs.size(), this.sinkDefs.size(), this.callbackMethods.size()));
	}

	/**
	 * Gets the field or method signature of the given source/sink definition
	 *
	 * @param am The source/sink definition for which to get a Soot signature
	 * @return The Soot signature associated with the given source/sink definition
	 */
	private String getSignature(ISourceSinkDefinition am) {
		if (am instanceof MethodSourceSinkDefinition) {
			MethodSourceSinkDefinition methodSource = (MethodSourceSinkDefinition) am;
			return methodSource.getMethod().getSignature();
		} else if (am instanceof FieldSourceSinkDefinition) {
			FieldSourceSinkDefinition fieldSource = (FieldSourceSinkDefinition) am;
			return fieldSource.getFieldSignature();
		} else if (am instanceof StatementSourceSinkDefinition)
			return GLOBAL_SIG;
		else
			throw new RuntimeException(
					String.format("Invalid type of source/sink definition: %s", am.getClass().getName()));
	}

	/**
	 * Gets the sink definition for the given call site and tainted access path
	 *
	 * @param sCallSite The call site
	 * @param manager   The manager object providing access to the configuration and
	 *                  the interprocedural control flow graph
	 * @param ap        The incoming tainted access path
	 * @return The sink definition of the method that is called at the given call
	 *         site if such a definition exists, otherwise null
	 */
	protected ISourceSinkDefinition getSinkDefinition(Stmt sCallSite, InfoflowManager manager, AccessPath ap) {
		// Do we have a statement-specific definition?
		{
			ISourceSinkDefinition def = sinkStatements.get(sCallSite);
			if (def != null)
				return def;
		}

		if (sCallSite.containsInvokeExpr()) {
			// Check whether the taint is even visible inside the callee
			final SootMethod callee = sCallSite.getInvokeExpr().getMethod();
			if (!SystemClassHandler.v().isTaintVisible(ap, callee))
				return null;

			// Do we have a direct hit?
			{
				ISourceSinkDefinition def = this.sinkMethods.get(sCallSite.getInvokeExpr().getMethod());
				if (def != null)
					return def;
			}

			final String subSig = callee.getSubSignature();

			// Check whether we have any of the interfaces on the list
			for (SootClass i : interfacesOf.getUnchecked(sCallSite.getInvokeExpr().getMethod().getDeclaringClass())) {
				if (i.declaresMethod(subSig)) {
					ISourceSinkDefinition def = this.sinkMethods.get(i.getMethod(subSig));
					if (def != null)
						return def;
				}
			}

			// Ask the CFG in case we don't know any better
			for (SootMethod sm : manager.getICFG().getCalleesOfCallAt(sCallSite)) {
				ISourceSinkDefinition def = this.sinkMethods.get(sm);
				if (def != null)
					return def;
			}

			// If the target method is in a phantom class, we scan the hierarchy
			// upwards to see whether we have a sink definition for a parent
			// class
			if (callee.getDeclaringClass().isPhantom()) {
				ISourceSinkDefinition def = findDefinitionInHierarchy(callee, this.sinkMethods);
				if (def != null)
					return def;
			}
			return null;

		} else if (sCallSite instanceof AssignStmt) {
			// Check if the target is a sink field
			AssignStmt assignStmt = (AssignStmt) sCallSite;
			if (assignStmt.getLeftOp() instanceof FieldRef) {
				FieldRef fieldRef = (FieldRef) assignStmt.getLeftOp();
				ISourceSinkDefinition def = sinkFields.get(fieldRef.getField());
				if (def != null)
					return def;
			}
		} else if (sCallSite instanceof ReturnStmt) {
			return sinkReturnMethods.get(manager.getICFG().getMethodOf(sCallSite));
		}

		return null;
	}

	/**
	 * Scans the hierarchy of the class containing the given method to find any
	 * implementations of the same method further up in the hierarchy for which
	 * there is a SourceSinkDefinition in the given map
	 *
	 * @param callee The method for which to look for a SourceSinkDefinition
	 * @param map    A map from methods to their corresponding SourceSinkDefinitions
	 * @return A SourceSinKDefinition for an implementation of the given method
	 *         somewhere up in the class hiearchy if it exists, otherwise null.
	 */
	private static ISourceSinkDefinition findDefinitionInHierarchy(SootMethod callee,
			Map map) {
		final String subSig = callee.getSubSignature();
		SootClass curClass = callee.getDeclaringClass();
		while (curClass != null) {
			// Does the current class declare the requested method?
			SootMethod curMethod = curClass.getMethodUnsafe(subSig);
			if (curMethod != null) {
				ISourceSinkDefinition def = map.get(curMethod);
				if (def != null) {
					// Patch the map to contain a direct link
					map.put(callee, def);
					return def;
				}
			}

			// Try the next class up the hierarchy
			if (curClass.hasSuperclass() && curClass.isPhantom())
				curClass = curClass.getSuperclass();
			else
				curClass = null;
		}

		return null;
	}

	@Override
	public SinkInfo getSinkInfo(Stmt sCallSite, InfoflowManager manager, AccessPath ap) {
		ISourceSinkDefinition def = getSinkDefinition(sCallSite, manager, ap);
		return def == null ? null : new SinkInfo(def);
	}

	@Override
	public SourceInfo getSourceInfo(Stmt sCallSite, InfoflowManager manager) {
		// Do not look for sources in excluded methods
		if (excludedMethods.contains(manager.getICFG().getMethodOf(sCallSite)))
			return null;

		ISourceSinkDefinition def = getSource(sCallSite, manager.getICFG());
		return createSourceInfo(sCallSite, manager, def);
	}

	protected SourceInfo createSourceInfo(Stmt sCallSite, InfoflowManager manager, ISourceSinkDefinition def) {
		// Do we have data at all?
		if (def == null)
			return null;

		// If we don't have an invocation, we just taint the left side of the
		// assignment
		if (!sCallSite.containsInvokeExpr()) {
			if (sCallSite instanceof DefinitionStmt) {
				DefinitionStmt defStmt = (DefinitionStmt) sCallSite;
				return new SourceInfo(def, manager.getAccessPathFactory().createAccessPath(defStmt.getLeftOp(), null,
						null, null, true, false, true, ArrayTaintType.ContentsAndLength, false));
			}
			return null;
		}

		// If this is a method call and we have a return value, we taint it.
		// Otherwise, if we have an instance invocation, we taint the base
		// object
		final InvokeExpr iexpr = sCallSite.getInvokeExpr();
		if (sCallSite instanceof DefinitionStmt && iexpr.getMethod().getReturnType() != null) {
			DefinitionStmt defStmt = (DefinitionStmt) sCallSite;
			// no immutable aliases, we overwrite the return values as a whole
			return new SourceInfo(def, manager.getAccessPathFactory().createAccessPath(defStmt.getLeftOp(), null, null,
					null, true, false, true, ArrayTaintType.ContentsAndLength, false));
		} else if (iexpr instanceof InstanceInvokeExpr && iexpr.getMethod().getReturnType() == VoidType.v()) {
			InstanceInvokeExpr iinv = (InstanceInvokeExpr) sCallSite.getInvokeExpr();
			return new SourceInfo(def, manager.getAccessPathFactory().createAccessPath(iinv.getBase(), true));
		} else
			return null;
	}

	/**
	 * Checks whether the given method is registered as a source method. If so,
	 * returns the corresponding definition, otherwise null.
	 *
	 * @param method The method to check
	 * @return The respective source definition if the given method is a source
	 *         method, otherwise null
	 */
	protected ISourceSinkDefinition getSourceMethod(SootMethod method) {
		if (oneSourceAtATime && (osaatType != SourceType.MethodCall || currentSource != method))
			return null;
		return this.sourceMethods.get(method);
	}

	/**
	 * Checks whether the given method is registered as a source method
	 *
	 * @param method The method to check
	 * @return True if the given method is a source method, otherwise false
	 */
	protected ISourceSinkDefinition getSourceDefinition(SootMethod method) {
		if (oneSourceAtATime) {
			if (osaatType == SourceType.MethodCall && currentSource == method)
				return this.sourceMethods.get(method);
			else
				return null;
		} else
			return this.sourceMethods.get(method);
	}

	/**
	 * Checks whether the given method is registered as a callback method. If so,
	 * the corresponding source definition is returned, otherwise null is returned.
	 *
	 * @param method The method to check
	 * @return The source definition object if the given method is a callback
	 *         method, otherwise null
	 */
	protected CallbackDefinition getCallbackDefinition(SootMethod method) {
		if (oneSourceAtATime) {
			if (osaatType == SourceType.Callback && currentSource == method)
				return this.callbackMethods.get(method);
			else
				return null;
		} else
			return this.callbackMethods.get(method);
	}

	/**
	 * Checks whether the given statement is a source, i.e. introduces new
	 * information into the application. If so, the source definition is returned,
	 * otherwise null
	 *
	 * @param sCallSite The statement to check for a source
	 * @param cfg       An interprocedural CFG containing the statement
	 * @return The definition of the discovered source if the given statement is a
	 *         source, null otherwise
	 */
	protected ISourceSinkDefinition getSource(Stmt sCallSite, IInfoflowCFG cfg) {
		assert cfg != null;
		assert cfg instanceof BiDiInterproceduralCFG;

		// Do we have a statement-specific definition?
		{
			ISourceSinkDefinition def = sourceStatements.get(sCallSite);
			if (def != null)
				return def;
		}

		ISourceSinkDefinition def = null;
		if ((!oneSourceAtATime || osaatType == SourceType.MethodCall) && sCallSite.containsInvokeExpr()) {
			// This might be a normal source method
			final SootMethod callee = sCallSite.getInvokeExpr().getMethod();
			def = getSourceDefinition(callee);
			if (def != null)
				return def;

			// Check whether we have any of the interfaces on the list
			final String subSig = callee.getSubSignature();
			for (SootClass i : interfacesOf.getUnchecked(callee.getDeclaringClass())) {
				SootMethod m = i.getMethodUnsafe(subSig);
				if (m != null) {
					def = getSourceDefinition(m);
					if (def != null)
						return def;
				}
			}

			// Ask the CFG in case we don't know any better
			for (SootMethod sm : cfg.getCalleesOfCallAt(sCallSite)) {
				def = getSourceDefinition(sm);
				if (def != null)
					return def;
			}

			// If the target method is in a phantom class, we scan the hierarchy
			// upwards
			// to see whether we have a sink definition for a parent class
			if (callee.getDeclaringClass().isPhantom()) {
				def = findDefinitionInHierarchy(callee, this.sourceMethods);
				if (def != null)
					return def;
			}
		}

		// This call might read out sensitive data from the UI
		if ((!oneSourceAtATime || osaatType == SourceType.UISource)) {
			def = getUISourceDefinition(sCallSite, cfg);
			if (def != null)
				return def;
		}

		// This statement might access a sensitive parameter in a callback
		// method
		def = checkCallbackParamSource(sCallSite, cfg);
		if (def != null)
			return def;

		// This statement may read sensitive data from a field
		def = checkFieldSource(sCallSite, cfg);
		if (def != null)
			return def;

		return null;
	}

	/**
	 * Checks whether the given statement accesses a field that has been marked as a
	 * source
	 *
	 * @param stmt The statement to check
	 * @param cfg  The interprocedural control flow graph
	 * @return The source and sink definition that corresponds to the detected field
	 *         source if the given statement is a source, otherwise null
	 */
	private ISourceSinkDefinition checkFieldSource(Stmt stmt, IInfoflowCFG cfg) {
		if (stmt instanceof AssignStmt) {
			AssignStmt assignStmt = (AssignStmt) stmt;
			if (assignStmt.getRightOp() instanceof FieldRef) {
				FieldRef fieldRef = (FieldRef) assignStmt.getRightOp();
				return sourceFields.get(fieldRef.getField());
			}
		}
		return null;
	}

	/**
	 * Checks whether the given statement obtains data from a callback source
	 *
	 * @param sCallSite The statement to check
	 * @param cfg       The interprocedural control flow graph
	 * @return The source and sink definition that corresponds to the detected
	 *         callback source if the given statement is a source, otherwise null
	 */
	protected ISourceSinkDefinition checkCallbackParamSource(Stmt sCallSite, IInfoflowCFG cfg) {
		// Do we handle callback sources at all?
		if (sourceSinkConfig.getCallbackSourceMode() == CallbackSourceMode.NoParametersAsSources)
			return null;
		if (oneSourceAtATime && osaatType != SourceType.Callback)
			return null;

		// Callback sources can only be parameter references
		if (!(sCallSite instanceof IdentityStmt))
			return null;
		IdentityStmt is = (IdentityStmt) sCallSite;
		if (!(is.getRightOp() instanceof ParameterRef))
			return null;
		ParameterRef paramRef = (ParameterRef) is.getRightOp();

		// We do not consider the parameters of lifecycle methods as
		// sources by default
		SootMethod parentMethod = cfg.getMethodOf(sCallSite);
		if (parentMethod == null)
			return null;
		if (!sourceSinkConfig.getEnableLifecycleSources() && isEntryPointMethod(parentMethod))
			return null;

		// Obtain the callback definition for the method in which this parameter
		// access occurs
		CallbackDefinition def = getCallbackDefinition(parentMethod);
		if (def == null)
			return null;

		// Do we match all callbacks?
		if (sourceSinkConfig.getCallbackSourceMode() == CallbackSourceMode.AllParametersAsSources)
			return MethodSourceSinkDefinition.createParameterSource(paramRef.getIndex(), CallType.Callback);

		// Do we only match registered callback methods?
		ISourceSinkDefinition sourceSinkDef = this.sourceMethods.get(def.getParentMethod());
		if (sourceSinkDef instanceof MethodSourceSinkDefinition) {
			MethodSourceSinkDefinition methodDef = (MethodSourceSinkDefinition) sourceSinkDef;
			if (sourceSinkConfig.getCallbackSourceMode() == CallbackSourceMode.SourceListOnly
					&& sourceSinkDef != null) {
				// Check the parameter index
				Set[] methodParamDefs = methodDef.getParameters();
				if (methodParamDefs != null && methodParamDefs.length > paramRef.getIndex()) {
					Set apTuples = methodDef.getParameters()[paramRef.getIndex()];
					if (apTuples != null && !apTuples.isEmpty()) {
						for (AccessPathTuple curTuple : apTuples)
							if (curTuple.getSourceSinkType().isSource())
								return sourceSinkDef;
					}
				}
			}
		}

		return null;
	}

	/**
	 * Checks whether the given method is an entry point, i.e., a lifecycle method
	 * 
	 * @param method the method
	 * @return true if the method is an entry point
	 */
	protected abstract boolean isEntryPointMethod(SootMethod method);

	/**
	 * Checks whether the given call site indicates a UI source, e.g. a password
	 * input. If so, creates an {@link ISourceSinkDefinition} for it
	 *
	 * @param sCallSite The call site that may potentially read data from a
	 *                  sensitive UI control
	 * @param cfg       The bidirectional control flow graph
	 * @return The generated {@link ISourceSinkDefinition} if the given call site
	 *         reads data from a UI source, null otherwise
	 */
	protected ISourceSinkDefinition getUISourceDefinition(Stmt sCallSite, IInfoflowCFG cfg) {
		return null;
	}

	@Override
	public void initialize() {
		// Get the Soot method or field for the source signatures we have
		if (sourceDefs != null) {
			sourceMethods = new HashMap<>();
			sourceFields = new HashMap<>();
			sourceStatements = new HashMap<>();
			for (Pair entry : sourceDefs) {
				ISourceSinkDefinition sourceSinkDef = entry.getO2();
				if (sourceSinkDef instanceof MethodSourceSinkDefinition) {
					SootMethodAndClass method = ((MethodSourceSinkDefinition) sourceSinkDef).getMethod();
					String returnType = method.getReturnType();

					// We need special handling for methods for which no return type has been
					// specified, i.e., the signature is incomplete
					if (returnType == null || returnType.isEmpty()) {
						String className = method.getClassName();

						String subSignatureWithoutReturnType = (((MethodSourceSinkDefinition) sourceSinkDef).getMethod()
								.getSubSignature());
						SootMethod sootMethod = grabMethodWithoutReturn(className, subSignatureWithoutReturnType);
						if (sootMethod != null)
							sourceMethods.put(sootMethod, sourceSinkDef);
					} else {
						SootMethod sm = Scene.v().grabMethod(entry.getO1());
						if (sm != null)
							sourceMethods.put(sm, sourceSinkDef);
					}

				} else if (sourceSinkDef instanceof FieldSourceSinkDefinition) {
					SootField sf = Scene.v().grabField(entry.getO1());
					if (sf != null)
						sourceFields.put(sf, sourceSinkDef);
				} else if (sourceSinkDef instanceof StatementSourceSinkDefinition) {
					StatementSourceSinkDefinition sssd = (StatementSourceSinkDefinition) sourceSinkDef;
					sourceStatements.put(sssd.getStmt(), sssd);
				}
			}
			sourceDefs = null;

		}

		// Get the Soot method or field for the sink signatures we have
		if (sinkDefs != null) {
			sinkMethods = new HashMap<>();
			sinkFields = new HashMap<>();
			sinkReturnMethods = new HashMap<>();
			sinkStatements = new HashMap<>();
			for (Pair entry : sinkDefs) {
				ISourceSinkDefinition sourceSinkDef = entry.getO2();
				if (sourceSinkDef instanceof MethodSourceSinkDefinition) {
					MethodSourceSinkDefinition methodSourceSinkDef = ((MethodSourceSinkDefinition) sourceSinkDef);
					if (methodSourceSinkDef.getCallType() == CallType.Return) {
						SootMethodAndClass method = methodSourceSinkDef.getMethod();
						SootMethod m = Scene.v().grabMethod(method.getSignature());
						if (m != null)
							sinkReturnMethods.put(m, methodSourceSinkDef);
					} else {
						SootMethodAndClass method = methodSourceSinkDef.getMethod();
						String returnType = method.getReturnType();
						boolean isMethodWithoutReturnType = returnType == null || returnType.isEmpty();
						if (isMethodWithoutReturnType) {
							String className = method.getClassName();
							String subSignatureWithoutReturnType = (((MethodSourceSinkDefinition) sourceSinkDef)
									.getMethod().getSubSignature());
							SootMethod sootMethod = grabMethodWithoutReturn(className, subSignatureWithoutReturnType);
							if (sootMethod != null)
								sinkMethods.put(sootMethod, sourceSinkDef);
						} else {
							SootMethod sm = Scene.v().grabMethod(entry.getO1());
							if (sm != null)
								sinkMethods.put(sm, entry.getO2());
						}
					}

				} else if (sourceSinkDef instanceof FieldSourceSinkDefinition) {
					SootField sf = Scene.v().grabField(entry.getO1());
					if (sf != null)
						sinkFields.put(sf, sourceSinkDef);
				} else if (sourceSinkDef instanceof StatementSourceSinkDefinition) {
					StatementSourceSinkDefinition sssd = (StatementSourceSinkDefinition) sourceSinkDef;
					sinkStatements.put(sssd.getStmt(), sssd);
				}
			}
			sinkDefs = null;
		}
	}

	/**
	 * Gets a soot method defined by class name and its sub signature from the
	 * loaded methods in the Scene object
	 *
	 * @param sootClassName The class name of the method
	 * @param subSignature  The sub signature of the method which is the method name
	 *                      and its parameters
	 * @return The soot method of the given class and sub signature or null
	 */
	private SootMethod grabMethodWithoutReturn(String sootClassName, String subSignature) {
		SootClass sootClass = Scene.v().getSootClassUnsafe(sootClassName);
		if (sootClass == null)
			return null;

		List sootMethods = null;
		if (sootClass.resolvingLevel() != DANGLING) {
			sootMethods = sootClass.getMethods();

			for (SootMethod s : sootMethods) {
				String[] tempSignature = s.getSubSignature().split(" ");

				if (tempSignature.length == 2) {
					if (tempSignature[1].equals(subSignature))
						return s;
				}

			}
		}

		return null;
	}

	@Override
	public void setOneSourceAtATimeEnabled(boolean enabled) {
		this.oneSourceAtATime = enabled;
	}

	@Override
	public boolean isOneSourceAtATimeEnabled() {
		return this.oneSourceAtATime;
	}

	@Override
	public void resetCurrentSource() {
		this.osaatIterator = this.sourceMethods.keySet().iterator();
		this.osaatType = SourceType.MethodCall;
	}

	@Override
	public void nextSource() {
		if (osaatType == SourceType.MethodCall || osaatType == SourceType.Callback)
			currentSource = this.osaatIterator.next();
	}

	@Override
	public boolean hasNextSource() {
		if (osaatType == SourceType.MethodCall) {
			if (this.osaatIterator.hasNext())
				return true;
			else {
				this.osaatType = SourceType.Callback;
				this.osaatIterator = this.callbackMethods.keySet().iterator();
				return hasNextSource();
			}
		} else if (osaatType == SourceType.Callback) {
			if (this.osaatIterator.hasNext())
				return true;
			else {
				this.osaatType = SourceType.UISource;
				return true;
			}
		} else if (osaatType == SourceType.UISource) {
			osaatType = SourceType.NoSource;
			return false;
		}
		return false;
	}

	/**
	 * Excludes the given method from the source/sink analysis. No sources or sinks
	 * will be detected in excluded methods.
	 *
	 * @param toExclude The method to exclude
	 */
	public void excludeMethod(SootMethod toExclude) {
		this.excludedMethods.add(toExclude);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy