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

com.sap.psr.vulas.monitor.touch.TouchPointCollector Maven / Gradle / Ivy

There is a newer version: 3.1.15
Show newest version
/**
 * This file is part of Eclipse Steady.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.
 */
package com.sap.psr.vulas.monitor.touch;

import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.sap.psr.vulas.ConstructId;
import com.sap.psr.vulas.FileAnalysisException;
import com.sap.psr.vulas.backend.BackendConnector;
import com.sap.psr.vulas.core.util.CoreConfiguration;
import com.sap.psr.vulas.goals.AbstractGoal;
import com.sap.psr.vulas.java.JarAnalyzer;
import com.sap.psr.vulas.java.JavaId;
import com.sap.psr.vulas.monitor.ClassVisitor;
import com.sap.psr.vulas.monitor.ExecutionMonitor;
import com.sap.psr.vulas.monitor.Loader;
import com.sap.psr.vulas.monitor.LoaderHierarchy;
import com.sap.psr.vulas.monitor.trace.StackTraceUtil;
import com.sap.psr.vulas.shared.util.FileUtil;

import javassist.CtBehavior;

/**
 * 

TouchPointCollector class.

* */ public class TouchPointCollector { // STATIC MEMBERS private static Log log = null; private static final Log getLog() { if(TouchPointCollector.log==null) TouchPointCollector.log = LogFactory.getLog(TouchPointCollector.class); return TouchPointCollector.log; } private static TouchPointCollector instance = null; private static LoaderHierarchy loaderHierarchy = null; //private static boolean PAUSE_COLLECTION = false; // INSTANCE MEMBERS private Set touchPoints = new HashSet(); private Map jarAnalyzerCache = new HashMap(); private TouchPointCollector() { this.loaderHierarchy = new LoaderHierarchy(); } /** *

Getter for the field instance.

* * @return a {@link com.sap.psr.vulas.monitor.touch.TouchPointCollector} object. */ public synchronized static TouchPointCollector getInstance() { if(TouchPointCollector.instance==null) { // Disable trace collection during the instantiation process. As we use a couple of OSS components // ourselves, we may end up in an endless loop and StackOverflow exceptions otherwise ExecutionMonitor.setPaused(true);//TouchPointCollector.PAUSE_COLLECTION = true; TouchPointCollector.instance = new TouchPointCollector(); // Trigger the creation of the execution monitor singleton ExecutionMonitor.getInstance(); // Create instances of StackTraceUtil and ConstructIdUtil, which are both called in the instrumented code new StackTraceUtil(); ConstructIdUtil.getInstance(); BackendConnector.getInstance(); ClassVisitor.removePackageContext("a.b.c"); TouchPointCollector.getLog().info("Completed instantiation of touch point collector"); // Now that the instance has been created, we enable trace collection again ExecutionMonitor.setPaused(false); //TouchPointCollector.PAUSE_COLLECTION = false; } return TouchPointCollector.instance; } /** * Adds the given touch point to the list of touch points collected during the tests. This method is called by the * callback method {@link TouchPointCollector#callback(String, String, ClassLoader, URL, boolean, StackTraceElement[], String, String, String, Map)}. * * @param _tp a {@link com.sap.psr.vulas.monitor.touch.TouchPointCollector.TouchPoint} object. */ public void addTouchPoint(TouchPoint _tp) { this.touchPoints.add(_tp); } /** *

Getter for the field touchPoints.

* * @return a {@link java.util.Set} object. */ public Set getTouchPoints() { return this.touchPoints; } /** *

getJarAnalyzerByPath.

* * @param _jar_path a {@link java.lang.String} object. * @return a {@link com.sap.psr.vulas.java.JarAnalyzer} object. */ public JarAnalyzer getJarAnalyzerByPath(String _jar_path){ if(!this.jarAnalyzerCache.containsKey(_jar_path)){ try { final JarAnalyzer ja = new JarAnalyzer(); ja.analyze(Paths.get(_jar_path).toFile()); this.jarAnalyzerCache.put(_jar_path, ja); } catch(FileAnalysisException e) { TouchPointCollector.getLog().error("Error while reading JAR file from URL [" + _jar_path + "]: " + e.getMessage()); } } return this.jarAnalyzerCache.get(_jar_path); } /** *

callback.

* * @param _callee_type a {@link java.lang.String} object. * @param _callee_qname a {@link java.lang.String} object. * @param _class_loader a {@link java.lang.ClassLoader} object. * @param _callee_url a {@link java.net.URL} object. * @param callee_in_app a boolean. * @param _stacktrace an array of {@link java.lang.StackTraceElement} objects. * @param _app_groupid a {@link java.lang.String} object. * @param _app_artifactid a {@link java.lang.String} object. * @param _app_version a {@link java.lang.String} object. * @param _callee_params a {@link java.util.Map} object. */ public static void callback(String _callee_type, String _callee_qname, ClassLoader _class_loader, URL _callee_url, boolean callee_in_app, StackTraceElement[] _stacktrace, String _app_groupid, String _app_artifactid, String _app_version, Map _callee_params){ if(!ExecutionMonitor.isPaused()) { final TouchPointCollector tpi = TouchPointCollector.getInstance(); // Return right away if the max number of touch points has been collected already if(CoreConfiguration.isMaxItemsCollected(tpi.getTouchPoints().size())) return; final ConstructIdUtil cidu = ConstructIdUtil.getInstance(); // Extract caller from stacktrace final Loader l = (_class_loader == null ? null : loaderHierarchy.add(_class_loader)); final ConstructId caller = new StackTraceUtil(loaderHierarchy, l).getPredecessorConstruct(_stacktrace); if(caller!=null) { // Get the direction of the touch point call (if any) TouchPointCollector.Direction tp_direction = null; if(cidu.isAppConstruct(caller) && !callee_in_app) tp_direction = TouchPointCollector.Direction.A2L; else if(cidu.isLibConstruct(caller) && callee_in_app) tp_direction = TouchPointCollector.Direction.L2A; if(tp_direction!=null) { final java.net.URL caller_url = ((com.sap.psr.vulas.java.JavaId)caller).getJarUrl(); // Build from method args final ConstructId callee = ConstructIdUtil.getInstance().getConstructidFromQName(_callee_qname, _callee_type); // Caller and callee should be methods, constructors or clinits if(!ConstructIdUtil.isOfInstrumentableType(caller) || !ConstructIdUtil.isOfInstrumentableType(callee)) { TouchPointCollector.getLog().warn("Expected , method or constructor for caller and callee, but got " + caller + " and " + callee); } // Create and collect the touch point else { final String callee_jar_path = (_callee_url == null ? null : FileUtil.getJARFilePath(_callee_url.toString())); JarAnalyzer callee_ja = null; if(callee_jar_path!=null ) callee_ja = tpi.getJarAnalyzerByPath(callee_jar_path); final String caller_jar_path = (caller_url == null ? null : FileUtil.getJARFilePath(caller_url.toString())); JarAnalyzer caller_ja = null; if(caller_jar_path!=null ) caller_ja = tpi.getJarAnalyzerByPath(caller_jar_path); final TouchPoint tp = new TouchPoint(tp_direction, caller, caller_ja, callee, _callee_params, callee_ja); tpi.addTouchPoint(tp); } } } } } /** * The instrumentation code created by {@link TouchPointInstrumentor#instrument(StringBuffer, JavaId, CtBehavior, ClassVisitor)} will * call this callback method if it is possible to determine the caller (through stack trace analysis). * * @param _exe a {@link com.sap.psr.vulas.goals.AbstractGoal} object. * @param _batch_size a int. */ /*public static void callback(Direction _direction, String _callee_type, String _callee_qname, URL _callee_url, ConstructId _caller, URL _caller_url, String _app_groupid, String _app_artifactid, String _app_version, Map _callee_params){ if(!TouchPointCollector.PAUSE_COLLECTION) { // Build from method args final ConstructId callee = ConstructIdUtil.getInstance().getConstructidFromQName(_callee_qname, _callee_type); // Caller and callee should be methods, constructors or clinits if(!ConstructIdUtil.isOfInstrumentableType(_caller) || !ConstructIdUtil.isOfInstrumentableType(callee)) { TouchPointCollector.getLog().warn("Expected > touchPointByArchiveId = new HashMap>(); // Loop and group by archive final Iterator iter = this.touchPoints.iterator(); while(iter.hasNext()){ TouchPoint ase = iter.next(); if(ase.getJarAnalyzerOfOss()!=null) { String archiveId = ase.getJarAnalyzerOfOss().getSHA1(); if(!touchPointByArchiveId.containsKey(archiveId)){ touchPointByArchiveId.put(archiveId, new LinkedList()); } touchPointByArchiveId.get(archiveId).add(ase); } else { TouchPointCollector.getLog().warn("No JAR analyzer found for touch point " + ase); } } // Upload touch points for each archive for (Map.Entry> entry : touchPointByArchiveId.entrySet()) { TouchPointCollector.getLog().info("Uploading [" + entry.getValue().size() + "] touch points for archive [" + entry.getKey() + "]"); // build attacksurface json JsonArray myArray = new JsonArray(); for(TouchPoint ase : entry.getValue()) { myArray.add(ase.toJSON()); } // Upload touch points for archiveid try { BackendConnector.getInstance().uploadTouchPoints(CoreConfiguration.buildGoalContextFromGlobalConfiguration(), CoreConfiguration.getAppContext(), entry.getKey(), myArray.toString()); } catch (ConfigurationException e) { TouchPointCollector.getLog().error(e.getMessage(), e); } catch (Exception e) { TouchPointCollector.getLog().error("Error during upload: " + e.getMessage(), e); } } } public static enum Direction { A2L, L2A }; private static class TouchPoint { private Direction direction = null; private ConstructId caller = null; private ConstructId callee = null; private Map calleeArgs = null; private JarAnalyzer callerJa = null; private JarAnalyzer calleeJa = null; private TouchPoint(Direction _direction, ConstructId _caller, JarAnalyzer _caller_ja, ConstructId _callee, Map _callee_args, JarAnalyzer _callee_ja) { this.direction = _direction; this.caller = _caller; this.callee = _callee; this.calleeArgs = _callee_args; this.callerJa = _caller_ja; this.calleeJa = _callee_ja; } /** * Returns the {@link JarAnalyzer} of the OSS that is part of the {@link TouchPoint}. Depending on the direction of the touch point, * this can be the analyzer of the caller or callee. * @return */ public JarAnalyzer getJarAnalyzerOfOss(){ if(this.direction.equals(Direction.A2L)) return calleeJa; else return callerJa; } public JsonObject toJSON(){ final JsonObject rootObj = new JsonObject(); rootObj.addProperty("direction", this.direction.toString()); rootObj.add("from", this.caller.toGSON()); rootObj.add("to", this.callee.toGSON()); // Add the archive SHA1 of the OSS (not needed for the application archive, if any) if(this.getJarAnalyzerOfOss()!=null) rootObj.addProperty("archiveId", this.getJarAnalyzerOfOss().getSHA1()); // Callee arguments /*if(this.calleeArgs != null && this.calleeArgs.size()>0){ final JsonArray myArray = new JsonArray(); for(Entry entry : this.calleeArgs.entrySet()){ if (entry.getKey().contains("arg_value_")) { String argNumber = entry.getKey().substring(entry.getKey().lastIndexOf('_')+1); JsonObject jo = new JsonObject(); jo.addProperty(this.calleeArgs.get("arg_type_"+argNumber), entry.getValue().toString()); myArray.add(jo); } } rootObj.add("endPointArguments", myArray); }*/ rootObj.addProperty("source", "X2C"); return rootObj; } @Override public String toString() { return "[" + this.caller.getQualifiedName() + " --> " + this.callee.getQualifiedName() + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((callee == null) ? 0 : callee.hashCode()); result = prime * result + ((calleeJa == null) ? 0 : calleeJa.hashCode()); result = prime * result + ((caller == null) ? 0 : caller.hashCode()); result = prime * result + ((callerJa == null) ? 0 : callerJa.hashCode()); result = prime * result + ((direction == null) ? 0 : direction.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TouchPoint other = (TouchPoint) obj; if (callee == null) { if (other.callee != null) return false; } else if (!callee.equals(other.callee)) return false; if (calleeJa == null) { if (other.calleeJa != null) return false; } else if (!calleeJa.equals(other.calleeJa)) return false; if (caller == null) { if (other.caller != null) return false; } else if (!caller.equals(other.caller)) return false; if (callerJa == null) { if (other.callerJa != null) return false; } else if (!callerJa.equals(other.callerJa)) return false; if (direction != other.direction) return false; return true; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy