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

pascal.taie.analysis.pta.plugin.taint.TFGBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Tai-e: A Static Analysis Framework for Java
 *
 * Copyright (C) 2022 Tian Tan 
 * Copyright (C) 2022 Yue Li 
 *
 * This file is part of Tai-e.
 *
 * Tai-e is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * Tai-e is distributed in the hope that it will be useful,but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
 * Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Tai-e. If not, see .
 */

package pascal.taie.analysis.pta.plugin.taint;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pascal.taie.analysis.graph.flowgraph.ArrayIndexNode;
import pascal.taie.analysis.graph.flowgraph.FlowEdge;
import pascal.taie.analysis.graph.flowgraph.InstanceFieldNode;
import pascal.taie.analysis.graph.flowgraph.InstanceNode;
import pascal.taie.analysis.graph.flowgraph.Node;
import pascal.taie.analysis.graph.flowgraph.ObjectFlowGraph;
import pascal.taie.analysis.graph.flowgraph.VarNode;
import pascal.taie.analysis.pta.PointerAnalysisResult;
import pascal.taie.analysis.pta.core.heap.Obj;
import pascal.taie.analysis.pta.plugin.util.InvokeUtils;
import pascal.taie.ir.exp.Var;
import pascal.taie.language.classes.JField;
import pascal.taie.language.classes.JMethod;
import pascal.taie.util.collection.Maps;
import pascal.taie.util.collection.Sets;
import pascal.taie.util.graph.Reachability;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

/**
 * Taint flow graph builder.
 */
class TFGBuilder {

    private static final Logger logger = LogManager.getLogger(TFGBuilder.class);

    private final PointerAnalysisResult pta;

    private final ObjectFlowGraph ofg;

    private final Set taintFlows;

    private final TaintManager taintManager;

    /**
     * Whether only track taint flow in application code.
     */
    private final boolean onlyApp = true;

    /**
     * Whether only track taint flow that reaches any sink.
     */
    private final boolean onlyReachSink = true;

    /**
     * Map from a node to set of taint objects pointed to by the node.
     */
    private Map> node2TaintSet;

    TFGBuilder(PointerAnalysisResult pta,
               Set taintFlows,
               TaintManager taintManager) {
        this.pta = pta;
        this.ofg = pta.getObjectFlowGraph();
        this.taintFlows = taintFlows;
        this.taintManager = taintManager;
    }

    /**
     * Builds a complete taint flow graph.
     */
    private TaintFlowGraph buildComplete() {
        // builds taint flow graph
        node2TaintSet = Maps.newMap();
        TaintFlowGraph tfg = new TaintFlowGraph(
                collectSourceNodes(), collectSinkNode());
        Set visitedNodes = Sets.newSet();
        Deque workList = new ArrayDeque<>(
                tfg.getSourceNodes());
        while (!workList.isEmpty()) {
            Node node = workList.poll();
            if (visitedNodes.add(node)) {
                getOutEdges(node).forEach(edge -> {
                    Node target = edge.target();
                    if (!onlyApp || isApp(target)) {
                        tfg.addEdge(edge);
                        if (!visitedNodes.contains(target)) {
                            workList.add(target);
                        }
                    }
                });
            }
        }
        node2TaintSet = null;
        return tfg;
    }

    private Map collectSourceNodes() {
        Map sourceNode2SourcePoint = Maps.newMap();
        for (Obj taintObj : taintManager.getTaintObjs()) {
            SourcePoint p = taintManager.getSourcePoint(taintObj);
            if (p instanceof CallSourcePoint csp) {
                IndexRef indexRef = csp.indexRef();
                Var var = InvokeUtils.getVar(csp.sourceCall(), indexRef.index());
                getNodes(var, indexRef).forEach(
                        node ->  sourceNode2SourcePoint.put(node, p));
            } else if (p instanceof ParamSourcePoint psp) {
                IndexRef indexRef = psp.indexRef();
                Var var = psp.sourceMethod().getIR().getParam(indexRef.index());
                getNodes(var, indexRef).forEach(
                        node ->  sourceNode2SourcePoint.put(node, p));
            } else if (p instanceof FieldSourcePoint fsp) {
                Var lhs = fsp.loadField().getLValue();
                Node sourceNode = ofg.getVarNode(lhs);
                if (sourceNode != null) {
                    sourceNode2SourcePoint.put(sourceNode, p);
                }
            }
        }
        logger.info("Source nodes:");
        sourceNode2SourcePoint.keySet().forEach(logger::info);
        return sourceNode2SourcePoint;
    }

    private Map collectSinkNode() {
        Map sinkNode2SinkPoint = Maps.newMap();
        taintFlows.forEach(taintFlow -> {
            SinkPoint sinkPoint = taintFlow.sinkPoint();
            IndexRef indexRef = sinkPoint.indexRef();
            Var var = InvokeUtils.getVar(sinkPoint.sinkCall(), indexRef.index());
            getNodes(var, indexRef).forEach(
                    node -> sinkNode2SinkPoint.put(node, sinkPoint));
        });
        logger.info("Sink nodes:");
        sinkNode2SinkPoint.keySet().forEach(logger::info);
        return sinkNode2SinkPoint;
    }

    private Stream getNodes(Var baseVar, IndexRef indexRef) {
        return switch (indexRef.kind()) {
            case VAR -> {
                Node node = ofg.getVarNode(baseVar);
                yield node != null ? Stream.of(node) : Stream.empty();
            }
            case ARRAY -> pta.getPointsToSet(baseVar)
                    .stream()
                    .map(ofg::getArrayIndexNode)
                    .filter(Objects::nonNull);
            case FIELD -> {
                JField field = indexRef.field();
                yield pta.getPointsToSet(baseVar)
                        .stream()
                        .map(o -> ofg.getInstanceFieldNode(o, field))
                        .filter(Objects::nonNull);
            }
        };
    }

    private List getOutEdges(Node source) {
        Set sourceTaintSet = getTaintSet(source);
        List edges = new ArrayList<>();
        // collect OFG edges
        ofg.getOutEdgesOf(source).forEach(edge -> {
            switch (edge.kind()) {
                case LOCAL_ASSIGN, INSTANCE_STORE, ARRAY_STORE,
                        THIS_PASSING, PARAMETER_PASSING, OTHER -> {
                    edges.add(edge);
                }
                case CAST, INSTANCE_LOAD, ARRAY_LOAD, RETURN -> {
                    // check whether target node also contains the same
                    // taint objects as source node to filter spurious edges
                    Set targetTaintSet = getTaintSet(edge.target());
                    if (!Collections.disjoint(sourceTaintSet, targetTaintSet)) {
                        edges.add(edge);
                    }
                }
            }
        });
        return edges;
    }

    private Set getTaintSet(Node node) {
        Set taintSet = node2TaintSet.get(node);
        if (taintSet == null) {
            taintSet = getPointsToSet(node)
                    .stream()
                    .filter(taintManager::isTaint)
                    .collect(Sets::newHybridSet, Set::add, Set::addAll);
            if (taintSet.isEmpty()) {
                taintSet = Set.of();
            }
            node2TaintSet.put(node, taintSet);
        }
        return taintSet;
    }

    private Set getPointsToSet(Node node) {
        if (node instanceof VarNode varNode) {
            return pta.getPointsToSet(varNode.getVar());
        } else if (node instanceof InstanceFieldNode ifNode) {
            return pta.getPointsToSet(ifNode.getBase(), ifNode.getField());
        } else if (node instanceof ArrayIndexNode aiNode) {
            return pta.getPointsToSet(aiNode.getBase());
        } else {
            return Set.of();
        }
    }

    TaintFlowGraph build() {
        TaintFlowGraph complete = buildComplete();
        TaintFlowGraph tfg = new TaintFlowGraph(
                complete.getSourceNode2SourcePoint(),
                complete.getSinkNode2SinkPoint());
        Set nodesReachSink = null;
        if (onlyReachSink) {
            nodesReachSink = Sets.newHybridSet();
            Reachability reachability = new Reachability<>(complete);
            for (Node sink : complete.getSinkNodes()) {
                nodesReachSink.addAll(reachability.nodesCanReach(sink));
            }
        }
        Set visitedNodes = Sets.newSet();
        Deque workList = new ArrayDeque<>(complete.getSourceNodes());
        while (!workList.isEmpty()) {
            Node node = workList.poll();
            if (visitedNodes.add(node)) {
                for (FlowEdge edge : complete.getOutEdgesOf(node)) {
                    Node target = edge.target();
                    if (!onlyReachSink || nodesReachSink.contains(target)) {
                        tfg.addEdge(edge);
                        if (!visitedNodes.contains(target)) {
                            workList.add(target);
                        }
                    }
                }
            }
        }
        return tfg;
    }

    private static boolean isApp(Node node) {
        if (node instanceof VarNode varNode) {
            return varNode.getVar().getMethod().isApplication();
        } else if (node instanceof InstanceNode iNode) {
            return iNode.getBase().getContainerMethod()
                    .stream()
                    .anyMatch(JMethod::isApplication);
        } else {
            return false;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy