/* Copyright 2014 MITRE Corporation * * 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. */ package org.mitre.provenance.capture.linux; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.mitre.provenance.PLUSException; import org.mitre.provenance.client.LocalProvenanceClient; import org.mitre.provenance.client.ProvenanceClient; import org.mitre.provenance.npe.NonProvenanceEdge; import org.mitre.provenance.plusobject.PLUSEdge; import org.mitre.provenance.plusobject.PLUSInvocation; import org.mitre.provenance.plusobject.PLUSObject; import org.mitre.provenance.plusobject.PLUSString; import org.mitre.provenance.plusobject.PLUSWorkflow; import org.mitre.provenance.plusobject.ProvenanceCollection; /** * Utility program which parses the output of the linux strace utility, and saves the results as a provenance graph. * To use this program, pipe the standard error output of the strace utility directly to this application on the command line, * or run it with an argument of a file which contains an strace dump. * @author dmallen */ public class STraceLogger extends ProvenanceCollection { private static Logger log = Logger.getLogger(STraceLogger.class.getName()); protected BufferedReader br = null; protected Pattern linePattern = Pattern.compile("(.*?)\\((.*)\\)\\s*=\\s*(.*)$"); protected HashMap<String,PLUSObject> mappings = new HashMap<String,PLUSObject>(); protected PLUSInvocation last = null; protected class Syscall { public String function = null; public ArrayList<String> arguments = new ArrayList<String>(); public String result = null; } public STraceLogger(InputStream is) throws IOException { super(); br = new BufferedReader(new InputStreamReader(is)); } protected Syscall parseLine(String line) { Syscall call = new Syscall(); Matcher matcher = linePattern.matcher(line); if(!matcher.matches()) return null; call.function = matcher.group(1); call.arguments = parseArgs(matcher.group(2)); call.result = matcher.group(3); System.out.println(line); System.out.println("FUNCTION " + call.function + " RESULT " + call.result); for(String arg : call.arguments) { System.out.println("ARG: '" + arg + "'"); } System.out.println(); return call; } protected ArrayList<String> parseArgs(String args) { ArrayList<String> list = new ArrayList<String>(); ArrayList<Integer[]> cutPoints = new ArrayList<Integer[]>(); ArrayList<String> stack = new ArrayList<String>(); int start = 0 ; int end = -1; int x=0; while(x < args.length()) { char c = args.charAt(x); if(c == ',' && stack.size() == 0) { end = x; cutPoints.add(new Integer[] { start, end }); start = x + 1; end = start; } else if(c == '[') stack.add("]"); else if(c == '{') stack.add("}"); else if(c == '(') stack.add(")"); else if(stack.size() > 0 && stack.get(stack.size()-1).equals(""+c)) { stack.remove(stack.size()-1); } x++; } // End while end = args.length(); cutPoints.add(new Integer[] { start, end}); for(Integer[]points : cutPoints) { list.add(args.substring(points[0], points[1]).trim()); } return list; } // End parseArgs public void parse() throws IOException, PLUSException { String line = null; while((line = br.readLine()) != null) { Syscall call = parseLine(line); if(call != null) { PLUSInvocation inv = getInvocation(call); addNode(inv); for(String arg : call.arguments) { addEdge(new PLUSEdge(getOrCreate(arg, true), inv, PLUSWorkflow.DEFAULT_WORKFLOW, PLUSEdge.EDGE_TYPE_INPUT_TO)); } addEdge(new PLUSEdge(inv, getOrCreate(call.result, true), PLUSWorkflow.DEFAULT_WORKFLOW, PLUSEdge.EDGE_TYPE_GENERATED)); if(last != null) { addNonProvenanceEdge(new NonProvenanceEdge(last, inv.getId(), NonProvenanceEdge.NPE_TYPE_SEQUENCE_STEP)); } last = inv; } else continue; } // End while br.close(); } // End parse protected PLUSInvocation getInvocation(Syscall call) { PLUSInvocation inv = new PLUSInvocation(); inv.setName(call.function); //for(int x=0; x<call.arguments.size(); x++) { // inv.addInput(""+(x+1), getOrCreate(call.arguments.get(x)).getId()); //} return inv; } protected PLUSObject getOrCreate(String data) { return getOrCreate(data, false); } protected PLUSObject getOrCreate(String data, boolean forceCreate) { if(!forceCreate && mappings.containsKey(data)) return mappings.get(data); PLUSString string = new PLUSString(data, data); addNode(string); mappings.put(data, string); return string; } // End getOrCreate public static void main(String [] args) throws Exception { ProvenanceClient.instance = new LocalProvenanceClient(); STraceLogger slog = null; if(args.length > 0) { slog = new STraceLogger(new FileInputStream(new File(args[0]))); } else { slog = new STraceLogger(System.in); } slog.parse(); log.info("Writing provenance collection: " + slog); ProvenanceClient.instance.report(slog); } // End main } // End STraceLogger