org.scandroid.flow.functions.IFDSTaintFlowFunctionProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.ibm.wala.scandroid Show documentation
Show all versions of com.ibm.wala.scandroid Show documentation
T. J. Watson Libraries for Analysis
/*
* 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
*
* 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.functions;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.dataflow.IFDS.IFlowFunction;
import com.ibm.wala.dataflow.IFDS.IFlowFunctionMap;
import com.ibm.wala.dataflow.IFDS.ISupergraph;
import com.ibm.wala.dataflow.IFDS.IUnaryFlowFunction;
import com.ibm.wala.ipa.callgraph.CGNode;
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.callgraph.propagation.StaticFieldKey;
import com.ibm.wala.ipa.cfg.BasicBlockInContext;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
import com.ibm.wala.ssa.SSAArrayStoreInstruction;
import com.ibm.wala.ssa.SSAGetInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.ssa.SSAReturnInstruction;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.intset.BitVectorIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.MutableIntSet;
import com.ibm.wala.util.intset.MutableSparseIntSet;
import com.ibm.wala.util.intset.OrdinalSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.scandroid.domain.CodeElement;
import org.scandroid.domain.DomainElement;
import org.scandroid.domain.FieldElement;
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;
/**
* @deprecated Replaced by TaintTransferFunctions.
*/
@Deprecated
public class IFDSTaintFlowFunctionProvider
implements IFlowFunctionMap> {
private final IFDSTaintDomain domain;
private final ISupergraph, CGNode> graph;
private final PointerAnalysis pa;
public IFDSTaintFlowFunctionProvider(
IFDSTaintDomain domain,
ISupergraph, CGNode> graph,
PointerAnalysis pa) {
this.domain = domain;
this.graph = graph;
this.pa = pa;
}
// instruction has a valid def set
private static boolean inFlow(SSAInstruction instruction) {
return (instruction instanceof SSAArrayLoadInstruction)
|| (instruction instanceof SSAGetInstruction);
}
// instruction's def is getUse(0)
private static boolean outFlow(SSAInstruction instruction) {
return (instruction instanceof SSAArrayStoreInstruction)
|| (instruction instanceof SSAPutInstruction)
|| (instruction instanceof SSAInvokeInstruction);
}
// instruction is a return instruction
private static boolean returnFlow(SSAInstruction instruction) {
return (instruction instanceof SSAReturnInstruction);
}
private static class UseDefSetPair {
public Set uses = HashSetFactory.make();
public Set defs = HashSetFactory.make();
}
private class DefUse implements IUnaryFlowFunction {
private final List useToDefList = new ArrayList<>();
private final BasicBlockInContext bb;
public DefUse(final BasicBlockInContext inBlock) {
this.bb = inBlock;
for (SSAInstruction instruction : bb) {
handleInstruction(instruction);
}
}
private void handleInstruction(SSAInstruction instruction) {
// System.out.println("handle instruction: "+instruction);
UseDefSetPair p = new UseDefSetPair();
boolean thisToResult = false;
if (instruction instanceof SSAInvokeInstruction) {
thisToResult = handleInvokeInstruction(instruction, p);
}
if (thisToResult) {
useToDefList.add(p);
p = new UseDefSetPair();
}
IClassHierarchy ch = bb.getNode().getClassHierarchy();
if (inFlow(instruction)) {
handleInflowInstruction(instruction, p, ch);
} else if (outFlow(instruction)) {
handleOutflowInstruction(instruction, p, ch);
} else if (returnFlow(instruction)) {
handleReturnFlowInstruction(instruction, p);
} else {
for (int i = 0; i < instruction.getNumberOfUses(); i++) {
p.uses.addAll(CodeElement.valueElements(instruction.getUse(i)));
}
for (int j = 0; j < instruction.getNumberOfDefs(); j++) {
p.defs.addAll(CodeElement.valueElements(instruction.getDef(j)));
}
}
useToDefList.add(p);
}
private void handleReturnFlowInstruction(SSAInstruction instruction, UseDefSetPair p) {
SSAReturnInstruction retInst = (SSAReturnInstruction) instruction;
if (retInst.getNumberOfUses() > 0) {
/* TODO: why not add instance keys, too? */
for (int i = 0; i < instruction.getNumberOfUses(); i++) {
// p.uses.add(new LocalElement(instruction.getUse(i)));
p.uses.addAll(CodeElement.valueElements(instruction.getUse(i)));
}
p.defs.add(new ReturnElement());
}
}
private boolean handleInvokeInstruction(SSAInstruction instruction, UseDefSetPair p) {
boolean thisToResult;
SSAInvokeInstruction invInst = (SSAInvokeInstruction) instruction;
if (!invInst.isSpecial() && !invInst.isStatic() && instruction.getNumberOfDefs() > 0) {
// System.out.println("adding receiver flow in "+this+" for "+invInst);
// System.out.println("\tadding local element "+invInst.getReceiver());
// getReceiver() == getUse(0) == param[0] == this
p.uses.addAll(CodeElement.valueElements(invInst.getReceiver()));
for (int i = 0; i < invInst.getNumberOfDefs(); i++) {
// System.out.println("\tadding def local element "+invInst.getDef(i));
// return valuenumber of invoke instruction
p.defs.addAll(CodeElement.valueElements(invInst.getDef(i)));
}
}
thisToResult = true;
return thisToResult;
}
private void handleInflowInstruction(
SSAInstruction instruction, UseDefSetPair p, IClassHierarchy ch) {
if (instruction instanceof SSAGetInstruction) {
handleInflowGetInstruction(instruction, p, ch);
} else if (instruction instanceof SSAArrayLoadInstruction) {
handleInflowArrayLoadInstruction(instruction, p);
}
}
private void handleOutflowInstruction(
SSAInstruction instruction, UseDefSetPair p, IClassHierarchy ch) {
if (instruction instanceof SSAPutInstruction) {
handleOutflowPutInstruction(instruction, p, ch);
} else if (instruction instanceof SSAArrayStoreInstruction) {
handleOutflowArrayStoreInstruction(instruction, p);
} else if (instruction instanceof SSAInvokeInstruction) {
handleOutflowInvokeInstruction(instruction, p);
}
}
private void handleOutflowInvokeInstruction(SSAInstruction instruction, UseDefSetPair p) {
MethodReference targetMethod =
((SSAInvokeInstruction) instruction).getCallSite().getDeclaredTarget();
if (methodExcluded(targetMethod)) {
// TODO make all parameters flow into all other
// parameters, which could happen in the static case as well.
if (!((SSAInvokeInstruction) instruction).isStatic()) {
// These loops cause all parameters flow into the
// 'this' param (due to instruction.getUse(0))
for (int i = 1; i < instruction.getNumberOfUses(); i++) {
p.uses.addAll(CodeElement.valueElements(instruction.getUse(i)));
}
if (instruction.getNumberOfUses() > 0) {
p.defs.addAll(CodeElement.valueElements(instruction.getUse(0)));
}
}
}
}
private void handleOutflowArrayStoreInstruction(SSAInstruction instruction, UseDefSetPair p) {
p.uses.addAll(CodeElement.valueElements(instruction.getUse(2)));
p.defs.addAll(CodeElement.valueElements(instruction.getUse(0)));
}
private void handleOutflowPutInstruction(
SSAInstruction instruction, UseDefSetPair p, IClassHierarchy ch) {
SSAPutInstruction pi = (SSAPutInstruction) instruction;
PointerKey pk;
Set elements = HashSetFactory.make();
if (pi.isStatic()) {
p.uses.addAll(CodeElement.valueElements(instruction.getUse(0)));
FieldReference declaredField = pi.getDeclaredField();
IField staticField = getStaticIField(ch, declaredField);
if (staticField == null) {
pk = null;
} else {
pk = new StaticFieldKey(staticField);
}
} else {
p.uses.addAll(CodeElement.valueElements(instruction.getUse(1)));
// this value number seems to be the object referenced in this instruction (?)
int valueNumber = instruction.getUse(0);
pk = new LocalPointerKey(bb.getNode(), valueNumber);
// MyLogger.log(LogLevel.DEBUG, " instruction: "+instruction);
// add the object that holds the field that was modified
// to the list of things tainted by this flow:
p.defs.addAll(CodeElement.valueElements(valueNumber));
}
// now add the field keys to the defs list so that they
// are also tainted:
if (pk != null) {
OrdinalSet m = pa.getPointsToSet(pk);
if (m != null) {
for (InstanceKey instanceKey : m) {
elements.add(new FieldElement(instanceKey, pi.getDeclaredField()));
elements.add(new InstanceKeyElement(instanceKey));
}
}
p.defs.addAll(elements);
}
}
private void handleInflowArrayLoadInstruction(SSAInstruction instruction, UseDefSetPair p) {
p.uses.addAll(CodeElement.valueElements(instruction.getUse(0)));
p.defs.addAll(CodeElement.valueElements(instruction.getDef()));
}
private void handleInflowGetInstruction(
SSAInstruction instruction, UseDefSetPair p, IClassHierarchy ch) {
SSAGetInstruction gi = (SSAGetInstruction) instruction;
PointerKey pk;
FieldReference declaredField = gi.getDeclaredField();
if (gi.isStatic()) {
IField staticField = getStaticIField(ch, declaredField);
if (staticField == null) {
pk = null;
} else {
pk = new StaticFieldKey(staticField);
}
} else {
int valueNumber = instruction.getUse(0);
pk = new LocalPointerKey(bb.getNode(), valueNumber);
}
if (pk != null) {
Set elements = HashSetFactory.make();
OrdinalSet m = pa.getPointsToSet(pk);
if (m != null) {
for (InstanceKey instanceKey : m) {
elements.add(new FieldElement(instanceKey, declaredField));
elements.add(new InstanceKeyElement(instanceKey));
}
}
p.uses.addAll(elements);
// getinstruction only has 1 def
p.defs.add(new LocalElement(instruction.getDef(0)));
}
}
/**
* Determines if the provide method is in the exclusions by checking the supergraph.
*
* @return True if the method can not be found in the supergraph.
*/
private boolean methodExcluded(MethodReference method) {
Collection iMethods = pa.getClassHierarchy().getPossibleTargets(method);
return iMethods.isEmpty();
}
private IField getStaticIField(IClassHierarchy ch, FieldReference declaredField) {
TypeReference staticTypeRef = declaredField.getDeclaringClass();
IClass staticClass = ch.lookupClass(staticTypeRef);
// referring to a static field which we don't have loaded in the class hierarchy
// possibly ignored in the exclusions file or just not included in the scope
if (staticClass == null) return null;
IField staticField = staticClass.getField(declaredField.getName());
return staticField;
}
private void addTargets(CodeElement d1, MutableIntSet set, FlowType taintType) {
// System.out.println(this.toString()+".addTargets("+d1+"...)");
for (UseDefSetPair p : useToDefList) {
if (p.uses.contains(d1)) {
// System.out.println("\t\tfound pair that uses "+d1);
for (CodeElement i : p.defs) {
// System.out.println("\t\tadding outflow "+i);
set.add(domain.getMappedIndex(new DomainElement(i, taintType)));
}
}
}
}
@Override
@SuppressWarnings("unchecked")
public IntSet getTargets(int d1) {
// System.out.println(this.toString()+".getTargets("+d1+") "+bb);
// BitVectorIntSet set = new BitVectorIntSet();
MutableSparseIntSet set = MutableSparseIntSet.makeEmpty();
set.add(d1);
DomainElement de = domain.getMappedObject(d1);
if (de != null) {
addTargets(de.codeElement, set, de.taintSource);
}
return set;
}
}
@Override
public IUnaryFlowFunction getCallFlowFunction(
BasicBlockInContext src, BasicBlockInContext dest, BasicBlockInContext ret) {
assert graph.isCall(src);
final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction();
// String signature = dest.getMethod().getSignature();
// if ( dest.getMethod().isWalaSynthetic() ) {
// System.out.println("Synthetic: "+signature);
// } else {
// System.err.println(signature);
// }
// if ( LoaderUtils.fromLoader(src.getNode(), ClassLoaderReference.Application)
// && LoaderUtils.fromLoader(dest.getNode(), ClassLoaderReference.Primordial)) {
// System.out.println("Call to system: "+signature);
// }
// if (! dest.getMethod().isWalaSynthetic()
// && LoaderUtils.fromLoader(dest.getNode(), ClassLoaderReference.Primordial)) {
//
// MyLogger.log(DEBUG,"Primordial and No Summary! (getCallFlowFunction) - " +
// dest.getMethod().getReference());
// }
final Map parameterMap = HashMapFactory.make();
for (int i = 0; i < instruction.getNumberOfPositionalParameters(); i++) {
Set elements = CodeElement.valueElements(instruction.getUse(i));
for (CodeElement e : elements) {
parameterMap.put(e, new LocalElement(i + 1));
}
}
return d1 -> {
BitVectorIntSet set = new BitVectorIntSet();
if (d1 == 0 || !(domain.getMappedObject(d1).codeElement instanceof LocalElement)) {
set.add(d1);
}
DomainElement de = domain.getMappedObject(d1);
if (de != null && parameterMap.containsKey(de.codeElement))
set.add(
domain.getMappedIndex(
new DomainElement(parameterMap.get(de.codeElement), de.taintSource)));
return set;
};
}
@Override
public IUnaryFlowFunction getCallNoneToReturnFlowFunction(
BasicBlockInContext src, BasicBlockInContext dest) {
// I Believe this method is called only if there are no callees of src in the supergraph
// if supergraph included all primordials, this method can still be called if it calls a
// method that wasn't included in the scope
// Assertions.UNREACHABLE();
// TODO: Look up summary for this method, or warn if it doesn't exist.
assert src.getNode().equals(dest.getNode());
// final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction();
// System.out.println("call to return(no callee) method inside call graph: " +
// src.getNode()+"--" + instruction.getDeclaredTarget());
// System.out.println("call to system: " + instruction.getDeclaredTarget());
return new DefUse(dest);
}
@Override
public IUnaryFlowFunction getCallToReturnFlowFunction(
BasicBlockInContext src, BasicBlockInContext dest) {
assert src.getNode().equals(dest.getNode());
// final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction();
// System.out.println("call to return method inside call graph: " +
// instruction.getDeclaredTarget());
return new DefUse(dest);
}
@Override
public IUnaryFlowFunction getNormalFlowFunction(
BasicBlockInContext src, BasicBlockInContext dest) {
assert src.getNode().equals(dest.getNode());
// System.out.println("getNormalFlowFuntion");
// System.out.println("\tSrc " + src.getLastInstruction());
// System.out.println("\tDest " + dest.getLastInstruction());
return new DefUse(dest);
}
public class ReturnDefUse extends DefUse {
CodeElement callSet;
Set receivers = new HashSet<>();
public ReturnDefUse(BasicBlockInContext dest, BasicBlockInContext call) {
super(dest);
// TODO: look into exception handling through getDef(1)
if (call.getLastInstruction() instanceof SSAInvokeInstruction) {
SSAInvokeInstruction invInst = (SSAInvokeInstruction) call.getLastInstruction();
if (!invInst.isSpecial()) { // && !invInst.isStatic()) {
// for (int i = 0; i < invInst.getNumberOfReturnValues(); i++) {
//
// }
if (invInst.hasDef()) {
callSet = new LocalElement(invInst.getReturnValue(0));
if (!invInst.isStatic()) {
// used to be invInst.getReceiver(), but I believe that was incorrect.
receivers.addAll(CodeElement.valueElements(invInst.getReceiver()));
// receivers.addAll(CodeElement.valueElements(pa, call.getNode(),
// invInst.getReturnValue(0)));
}
}
}
} else {
callSet = null;
}
// // TODO: look into exception handling through getDef(1)
// if(call.getLastInstruction().getNumberOfDefs() == 1)
// {
// //System.out.println("\treturn defines something: "+call.getLastInstruction());
// callSet = new LocalElement(call.getLastInstruction().getDef(0));
// if(call.getLastInstruction() instanceof SSAInvokeInstruction)
// {
// SSAInvokeInstruction invInst = (SSAInvokeInstruction) call.getLastInstruction();
// if(!invInst.isSpecial() && !invInst.isStatic()) {
// receivers.addAll(CodeElement.valueElements(pa, call.getNode(),
// invInst.getReceiver()));
// }
// }
// }
// else
// callSet = null;
}
@Override
public IntSet getTargets(int d1) {
if (d1 != 0 && domain.getMappedObject(d1).codeElement instanceof ReturnElement) {
BitVectorIntSet set = new BitVectorIntSet();
if (callSet != null) {
// System.out.println("callset: " + callSet);
set.add(
domain.getMappedIndex(
new DomainElement(callSet, domain.getMappedObject(d1).taintSource)));
}
return set;
} else if (d1 != 0 && domain.getMappedObject(d1).codeElement instanceof LocalElement) {
return new BitVectorIntSet();
} else if (d1 != 0 && receivers.contains(domain.getMappedObject(d1).codeElement)) {
BitVectorIntSet set = new BitVectorIntSet();
if (callSet != null)
set.add(
domain.getMappedIndex(
new DomainElement(callSet, domain.getMappedObject(d1).taintSource)));
set.addAll(super.getTargets(d1));
return set;
} else {
return super.getTargets(d1);
}
}
}
@Override
public IFlowFunction getReturnFlowFunction(
BasicBlockInContext call, BasicBlockInContext src, BasicBlockInContext dest) {
assert (graph.isCall(call) && graph.isReturn(dest) && call.getNode().equals(dest.getNode()));
// final SSAInvokeInstruction instruction = (SSAInvokeInstruction) call.getLastInstruction();
// System.out.println("Return from call to method inside call graph: " +
// instruction.getDeclaredTarget());
return new ReturnDefUse(dest, call);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy