WALA/com.ibm.wala.scandroid/source/org/scandroid/prefixtransfer/UriPrefixTransferGraph.java

441 lines
18 KiB
Java

/*
* 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 <afuchs@cs.umd.edu>
* Avik Chaudhuri <avik@cs.umd.edu>
* Steve Suh <suhsteve@gmail.com>
*
* 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.prefixtransfer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.scandroid.prefixtransfer.StringBuilderUseAnalysis.StringBuilderToStringInstanceKeySite;
import org.scandroid.prefixtransfer.modeledAllocations.ConstantString;
import org.scandroid.prefixtransfer.modeledAllocations.UriAppendString;
import org.scandroid.prefixtransfer.modeledAllocations.UriParseString;
import com.ibm.wala.analysis.reflection.InstanceKeyWithNode;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.propagation.AllocationSiteInNode;
import com.ibm.wala.ipa.callgraph.propagation.ConstantKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.graph.Graph;
import com.ibm.wala.util.intset.OrdinalSet;
import com.ibm.wala.util.intset.OrdinalSetMapping;
public class UriPrefixTransferGraph implements Graph<InstanceKeySite> {
public final Map<InstanceKey, InstanceKeySite> nodeMap = new HashMap<>();
public final Map<InstanceKey, StringBuilderUseAnalysis> sbuaMap =
new HashMap<>();
private final List<InstanceKeySite> nodes = new ArrayList<>();
private final Map<InstanceKeySite,Set<InstanceKeySite>> successors =
new HashMap<>();
private final Map<InstanceKeySite,Set<InstanceKeySite>> predecessors =
new HashMap<>();
public UriPrefixTransferGraph(final PointerAnalysis<InstanceKey> pa) {
final Map<InstanceKeySite, Set<InstanceKey>> unresolvedDependencies =
new HashMap<>();
final OrdinalSetMapping<InstanceKey> mapping = pa.getInstanceKeyMapping();
final Collection<InstanceKey> instanceKeys = pa.getInstanceKeys();
for (final InstanceKey k : instanceKeys) {
handleStringBuilder(k, pa, mapping, unresolvedDependencies);
}
for (final InstanceKey k : instanceKeys) {
handleString(k, pa, mapping, unresolvedDependencies);
}
for (final PointerKey pk : pa.getPointerKeys()) {
if (pk instanceof LocalPointerKey) {
final LocalPointerKey lpk = (LocalPointerKey) pk;
handleUriWitAppendPath(lpk, pa, mapping, unresolvedDependencies);
}
}
for (final InstanceKey ik: instanceKeys) {
if (ik instanceof NormalAllocationInNode) {
final NormalAllocationInNode naik = (NormalAllocationInNode) ik;
handleUriParse(naik, pa, mapping, unresolvedDependencies);
handleUriWitAppendPath(naik, pa, mapping, unresolvedDependencies);
}
}
for (final Entry<InstanceKeySite, Set<InstanceKey>> deps : unresolvedDependencies.entrySet()) {
for (final InstanceKey dep : deps.getValue()) {
final InstanceKeySite depSite = nodeMap.get(dep);
if (depSite != null) {
addEdge(depSite, deps.getKey());
}
}
}
}
private void handleString(final InstanceKey ik, final PointerAnalysis<InstanceKey> pa,
final OrdinalSetMapping<InstanceKey> mapping,
final Map<InstanceKeySite, Set<InstanceKey>> unresolvedDependencies) {
if (isOfType(ik, "Ljava/lang/String")) {
if (ik instanceof ConstantKey) {
final String value = (String) ((ConstantKey<?>) ik).getValue();
final InstanceKeySite node = new ConstantString(mapping.getMappedIndex(ik), value);
addNode(node);
nodeMap.put(ik, node);
} else if (ik instanceof NormalAllocationInNode) {
final NormalAllocationInNode nain = (NormalAllocationInNode) ik;
handleStringBuilderToString(nain, pa, mapping, unresolvedDependencies);
}
}
}
private void handleStringBuilder(final InstanceKey ik, final PointerAnalysis<InstanceKey> pa,
final OrdinalSetMapping<InstanceKey> mapping,
final Map<InstanceKeySite, Set<InstanceKey>> unresolvedDependencies) {
if (isOfType(ik, "Ljava/lang/StringBuilder")) {
if (ik instanceof AllocationSiteInNode) {
final AllocationSiteInNode as = (AllocationSiteInNode) ik;
if (isApplicationCode(as.getSite().getDeclaredType())) {
final StringBuilderUseAnalysis sbua;
try {
sbua = new StringBuilderUseAnalysis(ik, pa);
} catch(Exception e) {
return;
}
sbuaMap.put(ik, sbua); // map ik to sbua in some global map
}
}
}
}
private void handleStringBuilderToString(final NormalAllocationInNode nain, final PointerAnalysis<InstanceKey> pa,
final OrdinalSetMapping<InstanceKey> mapping,
final Map<InstanceKeySite, Set<InstanceKey>> unresolvedDependencies) {
if (hasSignature(nain, "java.lang.StringBuilder.toString()Ljava/lang/String;")) {
final Context context = nain.getNode().getContext();
final CGNode caller = (CGNode) context.get(ContextKey.CALLER);
if (caller != null && isApplicationCode(caller.getMethod())) {
final InstanceKey receiver = (InstanceKey) context.get(ContextKey.RECEIVER);
if (sbuaMap.get(receiver) != null) {
final CallSiteReference csr = (CallSiteReference) context.get(ContextKey.CALLSITE);
final InstanceKeySite node = sbuaMap.get(receiver).getNode(csr, nain);
if (node != null) {
addNode(node);
nodeMap.put(nain, node);
final StringBuilderToStringInstanceKeySite s2si =
(StringBuilderToStringInstanceKeySite) node;
final HashSet<InstanceKey> iks = new HashSet<>();
for (final Integer i: s2si.concatenatedInstanceKeys) {
iks.add(mapping.getMappedObject(i));
}
unresolvedDependencies.put(node, iks);
// TODO: if this string is created inside the toString function of a string builder,
// find the StringBuilderUseAnalysis for that string builder and call getNode(k) to
// get the node for this instance key
// - this may have to be done in another phase
}
}
}
}
}
private void handleUriWitAppendPath(final LocalPointerKey lpk, final PointerAnalysis<InstanceKey> pa,
final OrdinalSetMapping<InstanceKey> mapping,
final Map<InstanceKeySite, Set<InstanceKey>> unresolvedDependencies) {
final Context context = lpk.getNode().getContext();
final CGNode caller = (CGNode) context.get(ContextKey.CALLER);
if (caller != null && isApplicationCode(caller.getMethod())
&& hasSignature(lpk, "android.net.Uri.withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;")) {
final CallSiteReference csr = (CallSiteReference) context.get(ContextKey.CALLSITE);
final SSAInvokeInstruction invoke =
(SSAInvokeInstruction) caller.getIR().getBasicBlocksForCall(csr)[0].getLastInstruction();
final OrdinalSet<InstanceKey> ptsUri =
pa.getPointsToSet(new LocalPointerKey(caller, invoke.getUse(0)));
if (!ptsUri.isEmpty()) {
final InstanceKey uriKey = ptsUri.iterator().next();
final OrdinalSet<InstanceKey> points =
pa.getPointsToSet(new LocalPointerKey(caller, invoke.getUse(1)));
if (!points.isEmpty()) {
final InstanceKey stringKey = points.iterator().next();
final OrdinalSet<InstanceKey> returnSet =
pa.getPointsToSet(new LocalPointerKey(caller, invoke.getReturnValue(0)));
for (final Iterator<InstanceKey> rIK = returnSet.iterator(); rIK.hasNext(); ) {
final InstanceKey returnIK = rIK.next();
final UriAppendString node = new UriAppendString(mapping.getMappedIndex(returnIK),
mapping.getMappedIndex(uriKey), mapping.getMappedIndex(stringKey));
if (!nodeMap.containsKey(returnIK)) {
addNode(node);
nodeMap.put(returnIK, node);
final HashSet<InstanceKey> iks = new HashSet<>();
iks.add(uriKey);
iks.add(stringKey);
unresolvedDependencies.put(node, iks);
}
}
}
}
}
}
private void handleUriWitAppendPath(final NormalAllocationInNode ik, final PointerAnalysis<InstanceKey> pa,
final OrdinalSetMapping<InstanceKey> mapping,
final Map<InstanceKeySite, Set<InstanceKey>> unresolvedDependencies) {
final CGNode allocNode = ik.getNode();
final Context context = allocNode.getContext();
final CGNode caller = (CGNode) context.get(ContextKey.CALLER);
if (hasSignature(allocNode, "android.net.Uri.withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;")) {
//Doesn't seem to be entering this else with the current android jar -- reimplemented above using LocalPointerKey
final CallSiteReference csr = (CallSiteReference) context.get(ContextKey.CALLSITE);
final SSAInvokeInstruction invoke =
(SSAInvokeInstruction) caller.getIR().getBasicBlocksForCall(csr)[0].getLastInstruction();
final OrdinalSet<InstanceKey> ptsUri =
pa.getPointsToSet(new LocalPointerKey(caller, invoke.getUse(0)));
if (!ptsUri.isEmpty()) {
final InstanceKey uriKey = ptsUri.iterator().next();
final OrdinalSet<InstanceKey> points =
pa.getPointsToSet(new LocalPointerKey(caller, invoke.getUse(1)));
if (!points.isEmpty()) {
final InstanceKey stringKey = points.iterator().next();
final UriAppendString node =
new UriAppendString(mapping.getMappedIndex(ik),
mapping.getMappedIndex(uriKey),
mapping.getMappedIndex(stringKey));
addNode(node);
nodeMap.put(ik, node);
final HashSet<InstanceKey> iks = new HashSet<>();
iks.add(uriKey);
iks.add(stringKey);
unresolvedDependencies.put(node, iks);
}
}
}
}
private void handleUriParse(final NormalAllocationInNode ik, final PointerAnalysis<InstanceKey> pa,
final OrdinalSetMapping<InstanceKey> mapping,
final Map<InstanceKeySite, Set<InstanceKey>> unresolvedDependencies) {
final CGNode allocNode = ik.getNode();
final Context context = allocNode.getContext();
final CGNode caller = (CGNode) context.get(ContextKey.CALLER);
if (hasSignature(allocNode, "android.net.Uri.parse(Ljava/lang/String;)Landroid/net/Uri;")) {
final CallSiteReference csr = (CallSiteReference) context.get(ContextKey.CALLSITE);
final SSAInvokeInstruction invoke =
(SSAInvokeInstruction) caller.getIR().getBasicBlocksForCall(csr)[0].getLastInstruction();
final OrdinalSet<InstanceKey> points =
pa.getPointsToSet(new LocalPointerKey(caller, invoke.getUse(0)));
if (!points.isEmpty()) {
final InstanceKey stringKey = points.iterator().next();
final UriParseString node = new UriParseString(
mapping.getMappedIndex(ik),
mapping.getMappedIndex(stringKey));
addNode(node);
nodeMap.put(ik, node);
final HashSet<InstanceKey> iks = new HashSet<>();
iks.add(stringKey);
unresolvedDependencies.put(node, iks);
}
}
}
public void removeNodeAndEdges(InstanceKeySite n) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public void addNode(final InstanceKeySite n) {
predecessors.put(n, new HashSet<InstanceKeySite>());
successors.put(n, new HashSet<InstanceKeySite>());
nodes.add(n);
}
public boolean containsNode(final InstanceKeySite n) {
return nodes.contains(n);
}
public int getNumberOfNodes() {
return nodes.size();
}
public Iterator<InstanceKeySite> iterator() {
return nodes.iterator();
}
public void removeNode(final InstanceKeySite n) {
throw new UnsupportedOperationException();
}
public void addEdge(final InstanceKeySite src, final InstanceKeySite dst) {
Set<InstanceKeySite> predSet = predecessors.get(dst);
if (predSet == null) {
predSet = new HashSet<>();
predecessors.put(dst, predSet);
}
predSet.add(src);
Set<InstanceKeySite> succSet = successors.get(src);
if (succSet == null) {
succSet = new HashSet<>();
successors.put(src, succSet);
}
succSet.add(dst);
}
public int getPredNodeCount(final InstanceKeySite n) {
return predecessors.get(n).size();
}
public Iterator<InstanceKeySite> getPredNodes(InstanceKeySite n) {
return predecessors.get(n).iterator();
}
public int getSuccNodeCount(InstanceKeySite N) {
return successors.get(N).size();
}
public Iterator<InstanceKeySite> getSuccNodes(InstanceKeySite n) {
return successors.get(n).iterator();
}
public boolean hasEdge(InstanceKeySite src, InstanceKeySite dst) {
throw new UnsupportedOperationException();
}
public void removeAllIncidentEdges(InstanceKeySite node)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public void removeEdge(InstanceKeySite src, InstanceKeySite dst)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public void removeIncomingEdges(InstanceKeySite node)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public void removeOutgoingEdges(InstanceKeySite node)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
private static boolean isApplicationCode(final IMethod im) {
return isApplicationCode(im.getReference());
}
private static boolean isApplicationCode(final MethodReference mref) {
return isApplicationCode(mref.getDeclaringClass());
}
private static boolean isApplicationCode(final TypeReference tref) {
return tref.getClassLoader().equals(ClassLoaderReference.Application);
}
private static boolean isOfType(final InstanceKey ik, final String typeName) {
return typeName.equals(ik.getConcreteType().getName().toString());
}
private static boolean hasSignature(final CGNode n, final String signature) {
return hasSignature(n.getMethod(), signature);
}
private static boolean hasSignature(final IMethod im, final String signature) {
return signature.equals(im.getSignature());
}
private static boolean hasSignature(final LocalPointerKey pk, final String signature) {
return hasSignature(pk.getNode(), signature);
}
private static boolean hasSignature(final InstanceKeyWithNode ik, final String signature) {
return hasSignature(ik.getNode(), signature);
}
}