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

org.scandroid.flow.OutflowAnalysis Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
/*
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html.
 *
 * This file is a derivative of code released under the terms listed below.
 *
 */
/*
 * Copyright (c) 2009-2012,
 *
 * 

Adam Fuchs Avik Chaudhuri Steve Suh * *

Galois, Inc. (Aaron Tomb , Rogan Creswick , Adam * Foltzer ) * *

All rights reserved. * *

Redistribution and use in source and binary forms, with or without modification, are permitted * provided that the following conditions are met: * *

1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * *

2. Redistributions in binary form must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other materials provided with * the distribution. * *

3. The names of the contributors may not be used to endorse or promote products derived from * this software without specific prior written permission. * *

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.scandroid.flow; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.dataflow.IFDS.ICFGSupergraph; import com.ibm.wala.dataflow.IFDS.TabulationResult; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.CallGraph; import com.ibm.wala.ipa.callgraph.impl.Everywhere; import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; import com.ibm.wala.ipa.callgraph.propagation.PointerKey; import com.ibm.wala.ipa.cfg.BasicBlockInContext; import com.ibm.wala.ipa.cha.ClassHierarchy; import com.ibm.wala.ssa.SSAInstruction; import com.ibm.wala.ssa.SSAInstruction.Visitor; import com.ibm.wala.ssa.SSAInvokeInstruction; import com.ibm.wala.ssa.SSAReturnInstruction; import com.ibm.wala.ssa.analysis.IExplodedBasicBlock; import com.ibm.wala.types.MethodReference; import com.ibm.wala.util.collections.HashMapFactory; import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.collections.IteratorUtil; import com.ibm.wala.util.debug.UnimplementedError; import com.ibm.wala.util.intset.IntSet; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.scandroid.domain.DomainElement; import org.scandroid.domain.IFDSTaintDomain; import org.scandroid.domain.InstanceKeyElement; import org.scandroid.domain.LocalElement; import org.scandroid.domain.ReturnElement; import org.scandroid.flow.types.FlowType; import org.scandroid.flow.types.ParameterFlow; import org.scandroid.flow.types.ReturnFlow; import org.scandroid.spec.CallArgSinkSpec; import org.scandroid.spec.EntryArgSinkSpec; import org.scandroid.spec.EntryRetSinkSpec; import org.scandroid.spec.ISpecs; import org.scandroid.spec.SinkSpec; import org.scandroid.spec.StaticFieldSinkSpec; import org.scandroid.util.CGAnalysisContext; /** * @author acfoltzer */ public class OutflowAnalysis { private final CGAnalysisContext ctx; private final CallGraph cg; private final ClassHierarchy cha; private final PointerAnalysis pa; private final ICFGSupergraph graph; private final ISpecs specs; public OutflowAnalysis(CGAnalysisContext ctx, ISpecs specs) { this.ctx = ctx; this.cg = ctx.cg; this.cha = ctx.getClassHierarchy(); this.pa = ctx.pa; this.graph = (ICFGSupergraph) ctx.graph; this.specs = specs; } private static void addEdge( Map, Set>> graph, FlowType source, FlowType dest) { Set> dests = graph.computeIfAbsent(source, k -> new HashSet<>()); dests.add(dest); } @SuppressWarnings({"unused", "unchecked"}) private void processArgSinks( TabulationResult, CGNode, DomainElement> flowResult, IFDSTaintDomain domain, Map, Set>> flowGraph, List sinkSpecs) { List> targetList = new ArrayList<>(); for (SinkSpec sinkSpec : sinkSpecs) { Collection tempList = sinkSpec.getNamePattern().getPossibleTargets(cha); targetList.add(tempList); } // look for all uses of query function and taint the results with the // Uri used in those functions for (BasicBlockInContext block : graph) { Iterator invokeInstrs = IteratorUtil.filter(block.iterator(), SSAInvokeInstruction.class); while (invokeInstrs.hasNext()) { SSAInvokeInstruction invInst = invokeInstrs.next(); for (IMethod target : cha.getPossibleTargets(invInst.getDeclaredTarget())) { for (int i = 0; i < targetList.size(); i++) { if (!targetList.get(i).contains(target)) { continue; } int[] argNums = sinkSpecs.get(i).getArgNums(); if (null == argNums) { int staticIndex = 0; if (target.isStatic()) { staticIndex = 1; } int targetParamCount = target.getNumberOfParameters() - staticIndex; argNums = SinkSpec.getNewArgNums(targetParamCount); } CGNode node = block.getNode(); IntSet resultSet = flowResult.getResult(block); for (int argNum : argNums) { // The set of flow types we're looking for: Set> taintTypeSet = HashSetFactory.make(); LocalElement le = new LocalElement(invInst.getUse(argNum)); Set elements = domain.getPossibleElements(le); if (elements != null) { for (DomainElement de : elements) { if (resultSet.contains(domain.getMappedIndex(de))) { taintTypeSet.add(de.taintSource); } } } LocalPointerKey lpkey = new LocalPointerKey(node, invInst.getUse(argNum)); for (InstanceKey ik : pa.getPointsToSet(lpkey)) { for (DomainElement de : domain.getPossibleElements(new InstanceKeyElement(ik))) { if (resultSet.contains(domain.getMappedIndex(de))) { taintTypeSet.add(de.taintSource); } } } for (FlowType dest : sinkSpecs.get(i).getFlowType(block)) { for (FlowType source : taintTypeSet) { // flow taint into uriIK addEdge(flowGraph, source, dest); } } } } } } } } @SuppressWarnings({"unused", "unchecked"}) private void processEntryArgs( TabulationResult, CGNode, DomainElement> flowResult, IFDSTaintDomain domain, Map, Set>> flowGraph, SinkSpec ss) { int[] newArgNums; for (IMethod im : ss.getNamePattern().getPossibleTargets(cha)) { // look for a tainted reply CGNode node = cg.getNode(im, Everywhere.EVERYWHERE); if (node == null) { continue; } BasicBlockInContext[] entriesForProcedure = graph.getEntriesForProcedure(node); if (entriesForProcedure == null || 0 == entriesForProcedure.length) { continue; } BasicBlockInContext entryBlock = entriesForProcedure[0]; newArgNums = ss.getArgNums(); if (null == newArgNums) { int staticIndex = 1; if (im.isStatic()) { staticIndex = 0; } int targetParamCount = im.getNumberOfParameters() - staticIndex; newArgNums = SinkSpec.getNewArgNums(targetParamCount); } // for (BasicBlockInContext block: // graph.getExitsForProcedure(node) ) { // IntIterator itr = flowResult.getResult(block).intIterator(); // while (itr.hasNext()) { // int i = itr.next(); // // // // } // } for (int newArgNum : newArgNums) { // see if anything flowed into the args as sinks: for (DomainElement de : domain.getPossibleElements(new LocalElement(node.getIR().getParameter(newArgNum)))) { for (BasicBlockInContext block : graph.getExitsForProcedure(node)) { int mappedIndex = domain.getMappedIndex(de); if (flowResult.getResult(block).contains(mappedIndex)) { addEdge(flowGraph, de.taintSource, new ParameterFlow<>(entryBlock, newArgNum, false)); } } int mappedIndex = domain.getMappedIndex(de); if (flowResult.getResult(entryBlock).contains(mappedIndex)) { addEdge(flowGraph, de.taintSource, new ParameterFlow<>(entryBlock, newArgNum, false)); } } for (InstanceKey ik : pa.getPointsToSet(new LocalPointerKey(node, node.getIR().getParameter(newArgNum)))) { for (DomainElement de : domain.getPossibleElements(new InstanceKeyElement(ik))) { if (flowResult.getResult(entryBlock).contains(domain.getMappedIndex(de))) { addEdge(flowGraph, de.taintSource, new ParameterFlow<>(entryBlock, newArgNum, false)); } } } } } } @SuppressWarnings({"unused", "unchecked"}) private void processEntryRets( TabulationResult, CGNode, DomainElement> flowResult, IFDSTaintDomain domain, Map, Set>> flowGraph, SinkSpec ss) { for (IMethod im : ss.getNamePattern().getPossibleTargets(cha)) { // look for a tainted reply CGNode node = cg.getNode(im, Everywhere.EVERYWHERE); if (node == null) { continue; } BasicBlockInContext[] exitsForProcedure = graph.getExitsForProcedure(node); if (exitsForProcedure == null || 0 == exitsForProcedure.length) { continue; } final Set possibleElements = domain.getPossibleElements(new ReturnElement()); for (DomainElement de : possibleElements) { for (BasicBlockInContext block : exitsForProcedure) { if (flowResult.getResult(block).contains(domain.getMappedIndex(de))) { addEdge(flowGraph, de.taintSource, new ReturnFlow<>(block, false)); } // Iterator> it = // graph.getPredNodes(block); // while (it.hasNext()) { // BasicBlockInContext realBlock = it.next(); // if (realBlock.isExitBlock()) { // // // addEdge(flowGraph,de.taintSource, new // ReturnFlow(realBlock, false)); // } // if(flowResult.getResult(realBlock).contains(domain.getMappedIndex(de))) // { // logger.debug("adding edge from {} to ReturnFlow", // de.taintSource); // addEdge(flowGraph,de.taintSource, new // ReturnFlow(realBlock, false)); // } else { // logger.debug("no edge from block {} for {}", realBlock, // de); // } } } for (BasicBlockInContext block : exitsForProcedure) { Iterator> it = graph.getPredNodes(block); while (it.hasNext()) { BasicBlockInContext realBlock = it.next(); final SSAInstruction inst = realBlock.getLastInstruction(); if (null != inst && inst instanceof SSAReturnInstruction) { PointerKey pk = new LocalPointerKey(node, inst.getUse(0)); for (InstanceKey ik : pa.getPointsToSet(pk)) { for (DomainElement ikElement : domain.getPossibleElements(new InstanceKeyElement(ik))) { if (flowResult.getResult(realBlock).contains(domain.getMappedIndex(ikElement))) { addEdge(flowGraph, ikElement.taintSource, new ReturnFlow<>(realBlock, false)); } } } } } } } } public Map, Set>> analyze( TabulationResult, CGNode, DomainElement> flowResult, IFDSTaintDomain domain) { return analyze(flowResult, domain, specs); } public Map, Set>> analyze( TabulationResult, CGNode, DomainElement> flowResult, IFDSTaintDomain domain, ISpecs s) { Map, Set>> taintFlow = HashMapFactory.make(); SinkSpec[] ss = s.getSinkSpecs(); for (SinkSpec element : ss) { if (element instanceof EntryArgSinkSpec) processSinkSpec(flowResult, domain, taintFlow, element); else if (element instanceof CallArgSinkSpec) processSinkSpec(flowResult, domain, taintFlow, element); else if (element instanceof EntryRetSinkSpec) processSinkSpec(flowResult, domain, taintFlow, element); else if (element instanceof StaticFieldSinkSpec) processSinkSpec(flowResult, domain, taintFlow, element); else throw new UnsupportedOperationException("SinkSpec not yet Implemented"); } /* TODO: re-enable this soon! */ /* * for(Entry> e: taintFlow.entrySet()) { * WalaGraphToJGraphT walaJgraphT = new WalaGraphToJGraphT(flowResult, * domain, e.getKey(), graph, cg); logger.debug("Source: " + * e.getKey()); for(FlowType target:e.getValue()) { * //logger.debug("SourceNode: "+ * e.getKey().getRelevantNode() + * "\nSinkNode: "+target.getRelevantNode()); * walaJgraphT.calcPath(e.getKey().getRelevantNode(), * target.getRelevantNode()); Iterator edgeI = * walaJgraphT.getPath().getEdgeList().iterator(); if (edgeI.hasNext()) * int counter = 1; while * (edgeI.hasNext()) { DefaultEdge edge = edgeI.next(); * logger.debug("\t\t#"+counter+": " + * walaJgraphT.getJGraphT().getEdgeSource * (edge).getMethod().getSignature() + " ==> " + * walaJgraphT.getJGraphT() * .getEdgeTarget(edge).getMethod().getSignature()); } * * } } */ return taintFlow; } private void processSinkSpec( TabulationResult, CGNode, DomainElement> flowResult, IFDSTaintDomain domain, Map, Set>> flowGraph, SinkSpec ss) { Set sinkPoints = calculateSinkPoints(ss); if (!(ss instanceof StaticFieldSinkSpec)) {} for (ISinkPoint sinkPoint : sinkPoints) { for (FlowType source : sinkPoint.findSources(ctx, flowResult, domain)) { addEdge(flowGraph, source, sinkPoint.getFlow()); } } } private Set calculateSinkPoints(SinkSpec sinkSpec) { if (sinkSpec instanceof EntryArgSinkSpec) { return calculateSinkPoints((EntryArgSinkSpec) sinkSpec); } if (sinkSpec instanceof CallArgSinkSpec) { return calculateSinkPoints((CallArgSinkSpec) sinkSpec); } if (sinkSpec instanceof EntryRetSinkSpec) { return calculateSinkPoints((EntryRetSinkSpec) sinkSpec); } if (sinkSpec instanceof StaticFieldSinkSpec) { return calculateSinkPoints((StaticFieldSinkSpec) sinkSpec); } throw new UnimplementedError(); } private Set calculateSinkPoints(EntryArgSinkSpec sinkSpec) { Set points = HashSetFactory.make(); Collection methods = sinkSpec.getNamePattern().getPossibleTargets(cha); if (null == methods) {} for (IMethod method : methods) { for (CGNode node : cg.getNodes(method.getReference())) { BasicBlockInContext entryBlock = graph.getICFG().getEntry(node); BasicBlockInContext exitBlock = graph.getICFG().getExit(node); for (int argNum : sinkSpec.getArgNums()) { final int ssaVal = node.getIR().getParameter(argNum); final ParameterFlow sinkFlow = new ParameterFlow<>(entryBlock, argNum, false); final LocalSinkPoint sinkPoint = new LocalSinkPoint(exitBlock, ssaVal, sinkFlow); points.add(sinkPoint); } } } return points; } private Set calculateSinkPoints(final CallArgSinkSpec sinkSpec) { final Set points = HashSetFactory.make(); Collection methods = sinkSpec.getNamePattern().getPossibleTargets(cha); if (null == methods) {} Set callees = HashSetFactory.make(); final Set calleeRefs = HashSetFactory.make(); for (IMethod method : methods) { callees.addAll(cg.getNodes(method.getReference())); calleeRefs.add(method.getReference()); } // for each possible callee for (CGNode callee : callees) { Iterator callers = cg.getPredNodes(callee); // for each possible caller of that callee while (callers.hasNext()) { final CGNode caller = callers.next(); // look for invoke instructions caller .getIR() .visitAllInstructions( new Visitor() { @Override public void visitInvoke(SSAInvokeInstruction invokeInst) { // if the invoke instruction targets a possible callee if (calleeRefs.contains(invokeInst.getDeclaredTarget())) { // look up the instruction's block in context // (surely there's a more straightforward way to do // this!) final SSAInstruction[] insts = graph.getICFG().getCFG(caller).getInstructions(); int invokeIndex = -1; for (int i = 0; i < insts.length; i++) { if (insts[i] instanceof SSAInvokeInstruction) { SSAInvokeInstruction invokeInst2 = (SSAInvokeInstruction) insts[i]; if (invokeInst .getDeclaredTarget() .equals(invokeInst2.getDeclaredTarget())) { invokeIndex = i; break; } } } if (invokeIndex == -1) {} final IExplodedBasicBlock block = graph.getICFG().getCFG(caller).getBlockForInstruction(invokeIndex); BasicBlockInContext callBlock = new BasicBlockInContext<>(caller, block); for (int argNum : sinkSpec.getArgNums()) { // and add a sink point for each arg num final int ssaVal = invokeInst.getUse(argNum); final ParameterFlow sinkFlow = new ParameterFlow<>(callBlock, argNum, false); final LocalSinkPoint sinkPoint = new LocalSinkPoint(callBlock, ssaVal, sinkFlow); points.add(sinkPoint); } } } }); } } return points; } private Set calculateSinkPoints(EntryRetSinkSpec sinkSpec) { Set points = HashSetFactory.make(); Collection methods = sinkSpec.getNamePattern().getPossibleTargets(cha); if (null == methods) {} // for all possible returning methods for (IMethod method : methods) { // for all possible CGNodes of that method for (CGNode node : cg.getNodes(method.getReference())) { // get the unique (null) exit block BasicBlockInContext nullExitBlock = graph.getICFG().getExit(node); // and for each predecessor to the exit block Iterator> exitBlocks = graph.getPredNodes(nullExitBlock); while (exitBlocks.hasNext()) { // if that predecessor is a return instruction BasicBlockInContext exitBlock = exitBlocks.next(); final SSAInstruction inst = exitBlock.getDelegate().getInstruction(); if (inst instanceof SSAReturnInstruction) { // add a sink point for the instruction SSAReturnInstruction returnInst = (SSAReturnInstruction) inst; if (!returnInst.returnsVoid()) { final int ssaVal = returnInst.getResult(); final ReturnFlow sinkFlow = new ReturnFlow<>(exitBlock, false); final LocalSinkPoint sinkPoint = new LocalSinkPoint(exitBlock, ssaVal, sinkFlow); points.add(sinkPoint); } } } } } return points; } private Set calculateSinkPoints(StaticFieldSinkSpec sinkSpec) { Set points = HashSetFactory.make(); ICFGSupergraph graph = (ICFGSupergraph) ctx.graph; for (CGNode node : ctx.cg.getNodes(sinkSpec.getMethod().getReference())) { points.add(new StaticFieldSinkPoint(sinkSpec, graph.getICFG().getExit(node))); } return points; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy