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

pascal.taie.analysis.pta.plugin.taint.TaintAnalysis 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.World;
import pascal.taie.analysis.graph.callgraph.CallGraph;
import pascal.taie.analysis.pta.core.cs.context.Context;
import pascal.taie.analysis.pta.core.cs.element.CSCallSite;
import pascal.taie.analysis.pta.core.cs.element.CSManager;
import pascal.taie.analysis.pta.core.cs.element.CSMethod;
import pascal.taie.analysis.pta.core.cs.element.CSVar;
import pascal.taie.analysis.pta.core.solver.Solver;
import pascal.taie.analysis.pta.plugin.CompositePlugin;
import pascal.taie.analysis.pta.pts.PointsToSet;
import pascal.taie.config.AnalysisOptions;
import pascal.taie.config.ConfigException;
import pascal.taie.ir.IR;
import pascal.taie.language.classes.ClassHierarchy;
import pascal.taie.language.classes.JMethod;
import pascal.taie.language.type.TypeSystem;
import pascal.taie.util.AnalysisException;
import pascal.taie.util.Timer;

import javax.annotation.Nullable;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Set;

/**
 * Taint Analysis composites plugins {@link SourceHandler}, {@link TransferHandler}
 * and {@link SanitizerHandler} to handle the logic associated with {@link Source},
 * {@link TaintTransfer}, and {@link Sanitizer} respectively.
 * The analysis finally gathers taint flows from {@link Sink} through {@link SinkHandler}
 * and generates reports.
 * 
* The following diagram illustrates the workflow of the taint analysis: *

 *     ┌───────────────────────────┐   ┌─────────────────────────────┐
 * ┌──►│       initialize()        ├───┤Clean Up                     │
 * │   └─────────────┬─────────────┘   │                             │
 * │      on-the-fly │with PTA         │ 1.Clear composited handlers │
 * │                 ▼                 │ 2.Remove taint objects      │
 * │   ┌───────────────────────────┐   │   from points-to set        │
 * │   │      onPhaseFinish()      │   │ 3.Remove taint transfer     │
 * │Yes│ ┌───────────────────────┐ │   │   edge from pointer flow    │
 * │ ┌─┼─┤In interactive mode and│ │   │   graph                     │
 * └─┼─┼─┤Enter 'r' from console?│ │   │                             │
 *   │ │ └───────────┬───────────┘ │   │Start Up                     │
 *   │ │             │             │   │                             │
 *   │ └─────────────┼─────────────┘   │ 4. Load taint configuration │
 *   │               │No               │ 5. Create Source/Transfer/  │
 *   │               ▼                 │    Sanitizer handlers       │
 *   │ ┌───────────────────────────┐   │ 6. Create taint objects     │
 *   │ │         onFinish()        │   └─────────────────────────────┘
 *   │ └─────────────┬─────────────┘
 *   │               │
 *   │               ▼                 ┌─────────────────────────────┐
 *   │ ┌───────────────────────────┐   │Collect taint analysis result│
 *   └►│     reportTaintFlows()    ├───┤and report taint flows       │
 *     └───────────────────────────┘   └─────────────────────────────┘
 * 
*/ public class TaintAnalysis extends CompositePlugin { private static final Logger logger = LogManager.getLogger(TaintAnalysis.class); private static final String TAINT_FLOW_GRAPH_FILE = "taint-flow-graph.dot"; private Solver solver; private boolean isInteractive; /** * Indicates whether the taint analysis result has been reported. * It is used to ensures that {@link #reportTaintFlows()} executes only once * during a taint analysis. */ private boolean isReported; private HandlerContext context; @Override public void setSolver(Solver solver) { this.solver = solver; isInteractive = solver.getOptions().getBoolean("taint-interactive-mode"); initialize(); } private void initialize() { // clean composited plugins, taint objects and taint transfer edges isReported = false; clearPlugins(); if (context != null) { TaintManager manager = context.manager(); solver.getCSManager().pointers().forEach(p -> { PointsToSet pts = p.getPointsToSet(); if (pts != null) { pts.removeIf(csObj -> manager.isTaint(csObj.getObject())); } p.removeEdgesIf(TaintTransferEdge.class::isInstance); }); } // load taint configuration and create new handlers AnalysisOptions options = solver.getOptions(); TaintConfig config = TaintConfig.EMPTY; if (options.getString("taint-config") != null) { var provider = new YamlTaintConfigProvider( solver.getHierarchy(), solver.getTypeSystem()); provider.setPath(options.getString("taint-config")); config = provider.get(); } // load programmatic taint configuration List taintConfigProviders = (List) solver .getOptions().get("taint-config-providers"); for (String taintConfigProvider : taintConfigProviders) { try { Class clazz = Class.forName(taintConfigProvider); Constructor ctor = clazz.getConstructor( ClassHierarchy.class, TypeSystem.class); var provider = (TaintConfigProvider) ctor.newInstance( solver.getHierarchy(), solver.getTypeSystem()); config = config.mergeWith(provider.get()); } catch (ClassNotFoundException e) { throw new ConfigException( "Taint config class " + taintConfigProvider + " is not found"); } catch (IllegalAccessException | NoSuchMethodException e) { throw new AnalysisException( "Failed to access constructor of " + taintConfigProvider, e); } catch (InvocationTargetException | InstantiationException e) { throw new AnalysisException( "Failed to create plugin instance for " + taintConfigProvider, e); } } logger.info(config); context = new HandlerContext(solver, new TaintManager( solver.getHeapModel()), config); addPlugin(new SourceHandler(context), new TransferHandler(context), new SanitizerHandler(context)); // trigger the creation of taint objects CallGraph cg = solver.getCallGraph(); if (cg != null) { CSManager csManager = solver.getCSManager(); boolean handleStmt = context.config().callSiteMode() || context.config().sources().stream().anyMatch(FieldSource.class::isInstance); cg.reachableMethods().forEach(csMethod -> { JMethod method = csMethod.getMethod(); Context ctxt = csMethod.getContext(); IR ir = csMethod.getMethod().getIR(); if (handleStmt) { ir.forEach(stmt -> onNewStmt(stmt, method)); } this.onNewCSMethod(csMethod); csMethod.getEdges().forEach(this::onNewCallEdge); ir.getParams().forEach(param -> { CSVar csParam = csManager.getCSVar(ctxt, param); onNewPointsToSet(csParam, csParam.getPointsToSet()); }); }); } } @Override public void onPhaseFinish() { if (isInteractive) { while (true) { reportTaintFlows(); System.out.println("Taint Analysis is in interactive mode," + " you can modify the taint configuration and run the analysis again.\n" + "Enter 'r' to run, 'e' to exit: "); String input = readLineFromConsole(); if (input == null) { break; } input = input.strip(); System.out.println("You have entered: '" + input + "'"); if ("r".equals(input)) { initialize(); if (!context.manager().getTaintObjs().isEmpty()) { break; } } else if ("e".equals(input)) { isInteractive = false; break; } } } } /** * A utility method for reading one line from the console using {@code System.in}. * This method does not use buffering to ensure it does not read more than necessary. *
* * @return one line read from the console, * or {@code null} if no line is available */ @Nullable private static String readLineFromConsole() { StringBuilder sb = new StringBuilder(); try { int c; while ((c = System.in.read()) != -1) { if (c == '\r' || c == '\n') { return sb.toString(); } sb.append((char) c); } } catch (Exception e) { logger.error("Error reading from console", e); } return sb.isEmpty() ? null : sb.toString(); } @Override public void onFinish() { reportTaintFlows(); } private void reportTaintFlows() { if (isReported) { return; } isReported = true; Set taintFlows = new SinkHandler(context).collectTaintFlows(); logger.info("Detected {} taint flow(s):", taintFlows.size()); taintFlows.forEach(logger::info); solver.getResult().storeResult(getClass().getName(), taintFlows); TaintManager manager = context.manager(); Timer.runAndCount(() -> new TFGDumper().dump( new TFGBuilder(solver.getResult(), taintFlows, manager).build(), new File(World.get().getOptions().getOutputDir(), TAINT_FLOW_GRAPH_FILE)), "TFGDumper"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy