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

soot.jimple.infoflow.android.source.parsers.xml.XMLSourceSinkParser Maven / Gradle / Ivy

package soot.jimple.infoflow.android.source.parsers.xml;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import javax.xml.parsers.SAXParser;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import soot.jimple.infoflow.InfoflowConfiguration;
import soot.jimple.infoflow.android.data.AndroidMethod;
import soot.jimple.infoflow.data.AbstractMethodAndClass;
import soot.jimple.infoflow.sourcesSinks.definitions.AccessPathTuple;
import soot.jimple.infoflow.sourcesSinks.definitions.FieldSourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.IAccessPathBasedSourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkCategory;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.ISourceSinkDefinitionProvider;
import soot.jimple.infoflow.sourcesSinks.definitions.MethodSourceSinkDefinition;
import soot.jimple.infoflow.sourcesSinks.definitions.MethodSourceSinkDefinition.CallType;
import soot.jimple.infoflow.sourcesSinks.definitions.SourceSinkType;

/**
 * Parses informations from the new Dataformat (XML) with the help of SAX.
 * Returns only a Set of Android Method when calling the function parse. For the
 * AccessPath the class SaxHandler is used.
 * 
 * @author Anna-Katharina Wickert
 * @author Joern Tillmans
 * @author Steven Arzt
 * @author Niklas Vogel
 */

public class XMLSourceSinkParser extends AbstractXMLSourceSinkParser implements ISourceSinkDefinitionProvider {

	private final static Logger logger = LoggerFactory.getLogger(XMLSourceSinkParser.class);

	// XML stuff incl. Verification against XSD
	protected static final String XSD_FILE_PATH = "schema/SourcesAndSinks.xsd";
	protected static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";

	public static XMLSourceSinkParser fromFile(String fileName) throws IOException {
		return fromFile(fileName, null);
	}

	public static XMLSourceSinkParser fromFile(String fileName, ICategoryFilter categoryFilter) throws IOException {
		logger.info(String.format("Loading sources and sinks from %s...", fileName));
		try (InputStream is = getStream(fileName)) {
			verifyXML(is);
		}

		try (InputStream inputStream = getStream(fileName)) {
			return fromStream(inputStream, categoryFilter);
		}
	}

	protected static InputStream getStream(String fileName) throws IOException {
		File f = new File(fileName);
		if (f.exists())
			return new FileInputStream(f);

		return ResourceUtils.getResourceStream(fileName);
	}

	public static XMLSourceSinkParser fromStream(InputStream inputStream) throws IOException {
		return fromStream(inputStream, null);
	}

	public static XMLSourceSinkParser fromStream(InputStream inputStream, ICategoryFilter categoryFilter)
			throws IOException {
		XMLSourceSinkParser pmp = new XMLSourceSinkParser(categoryFilter);
		pmp.parseInputStream(inputStream);
		return pmp;
	}

	/**
	 * Builds the lists of sources and sinks from the data that we have parsed
	 */

	/**
	 * Creates a new instance of the {@link XMLSourceSinkParser} class
	 * 
	 * @param filter A filter for excluding certain categories of sources and sinks
	 */
	protected XMLSourceSinkParser(ICategoryFilter categoryFilter) {
		this.sourcesAndSinks = new HashMap<>();
		this.categoryFilter = categoryFilter;
	}

	/**
	 * Builds the lists of sources and sinks from the data that we have parsed
	 */
	@Override
	protected void buildSourceSinkLists() {
		for (ISourceSinkDefinition def : sourcesAndSinks.values()) {
			ISourceSinkDefinition sourceDef = def.getSourceOnlyDefinition();
			if (sourceDef != null && !sourceDef.isEmpty()) {
				if (sourceDef instanceof MethodSourceSinkDefinition) {
					MethodSourceSinkDefinition methodSrc = (MethodSourceSinkDefinition) sourceDef;
					if (methodSrc.getMethod() instanceof AndroidMethod) {
						AndroidMethod am = (AndroidMethod) methodSrc.getMethod();
						am.setSourceSinkType(am.getSourceSinkType().addType(SourceSinkType.Source));
					}
				}
				sources.add(sourceDef);
			}

			ISourceSinkDefinition sinkDef = def.getSinkOnlyDefinition();
			if (sinkDef != null && !sinkDef.isEmpty()) {
				if (sourceDef instanceof MethodSourceSinkDefinition) {
					MethodSourceSinkDefinition methodSink = (MethodSourceSinkDefinition) sourceDef;
					if (methodSink.getMethod() instanceof AndroidMethod) {
						AndroidMethod am = (AndroidMethod) methodSink.getMethod();
						am.setSourceSinkType(am.getSourceSinkType().addType(SourceSinkType.Sink));
					}
				}
				sinks.add(sinkDef);
			}
		}
		logger.info(String.format("Loaded %d sources and %d sinks from the XML file", sources.size(), sinks.size()));
	}

	/**
	 * Checks whether the given XML is valid against the XSD for the new data
	 * format.
	 * 
	 * @param fileName of the XML
	 * @throws IOException
	 */
	private static void verifyXML(InputStream inp) throws IOException {
		SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA);

		// Read the schema
		StreamSource xsdFile = new StreamSource(
				ResourceUtils.getResourceStream(InfoflowConfiguration.getBaseDirectory() + XSD_FILE_PATH));

		StreamSource xmlFile = new StreamSource(inp);
		try {
			Schema schema = sf.newSchema(xsdFile);
			Validator validator = schema.newValidator();
			try {
				validator.validate(xmlFile);
			} catch (IOException e) {
				throw new IOException("File isn't  valid against the xsd", e);
			}
		} catch (SAXException e) {
			throw new IOException("File isn't  valid against the xsd", e);
		} finally {
			xsdFile.getInputStream().close();
			xmlFile.getInputStream().close();
		}
	}

	/**
	 * Factory method for {@link MethodSourceSinkDefinition} instances
	 * 
	 * @param method    The method that is to be defined as a source or sink
	 * @param baseAPs   The access paths rooted in the base object that shall be
	 *                  considered as sources or sinks
	 * @param paramAPs  The access paths rooted in parameters that shall be
	 *                  considered as sources or sinks. The index in the set
	 *                  corresponds to the index of the formal parameter to which
	 *                  the respective set of access paths belongs.
	 * @param returnAPs The access paths rooted in the return object that shall be
	 *                  considered as sources or sinks
	 * @param callType  The type of call (normal call, callback, etc.)
	 * @return The newly created {@link MethodSourceSinkDefinition} instance
	 */
	@Override
	protected ISourceSinkDefinition createMethodSourceSinkDefinition(AbstractMethodAndClass method,
			Set baseAPs, Set[] paramAPs, Set returnAPs,
			CallType callType, ISourceSinkCategory category) {
		if (method instanceof AndroidMethod) {
			AndroidMethod amethod = (AndroidMethod) method;
			return new MethodSourceSinkDefinition(amethod, baseAPs, paramAPs, returnAPs, callType, category);
		}
		return null;
	}

	/**
	 * Factory method for {@link FieldSourceSinkDefinition} instances
	 * 
	 * @param signature The signature of the target field
	 * @param baseAPs   The access paths that shall be considered as sources or
	 *                  sinks
	 * @return The newly created {@link FieldSourceSinkDefinition} instance
	 */
	@Override
	protected IAccessPathBasedSourceSinkDefinition createFieldSourceSinkDefinition(String signature,
			Set baseAPs, List> paramAPs) {
		return new FieldSourceSinkDefinition(signature, baseAPs);
	}

	/**
	 * Run parse method on given parser
	 * 
	 * @param parser The parser which should be used to parse
	 * @param stream The XML text input stream which should be parsed
	 */
	@Override
	protected void runParse(SAXParser parser, InputStream stream) {
		try {
			parser.parse(stream, new SAXHandler(this.categoryFilter));
		} catch (SAXException | IOException e) {
			e.printStackTrace();
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy