edu.psu.cse.siis.ic3.ProtobufResultProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ic3 Show documentation
Show all versions of ic3 Show documentation
The IC3 tool for inferring Inter-Component Communication in Android
The newest version!
/*
* Copyright (C) 2015 The Pennsylvania State University and the University of Wisconsin
* Systems and Internet Infrastructure Security Laboratory
*
* Author: Damien Octeau
*
* 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 edu.psu.cse.siis.ic3;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.Scene;
import soot.SootMethod;
import soot.Type;
import soot.Unit;
import soot.jimple.InvokeExpr;
import soot.jimple.Stmt;
import com.google.protobuf.TextFormat;
import edu.psu.cse.siis.coal.AnalysisParameters;
import edu.psu.cse.siis.coal.Constants;
import edu.psu.cse.siis.coal.Model;
import edu.psu.cse.siis.coal.PropagationTimers;
import edu.psu.cse.siis.coal.Result;
import edu.psu.cse.siis.coal.Results;
import edu.psu.cse.siis.coal.arguments.Argument;
import edu.psu.cse.siis.coal.field.values.FieldValue;
import edu.psu.cse.siis.coal.field.values.ScalarFieldValue;
import edu.psu.cse.siis.coal.field.values.TopFieldValue;
import edu.psu.cse.siis.coal.values.BasePropagationValue;
import edu.psu.cse.siis.coal.values.BottomPropagationValue;
import edu.psu.cse.siis.coal.values.PathValue;
import edu.psu.cse.siis.coal.values.PropagationValue;
import edu.psu.cse.siis.coal.values.TopPropagationValue;
import edu.psu.cse.siis.ic3.Ic3Data.Application.Component;
import edu.psu.cse.siis.ic3.Ic3Data.Application.Component.ComponentKind;
import edu.psu.cse.siis.ic3.Ic3Data.Application.Component.ExitPoint;
import edu.psu.cse.siis.ic3.Ic3Data.Application.Component.ExitPoint.Intent;
import edu.psu.cse.siis.ic3.Ic3Data.Application.Component.ExitPoint.Uri;
import edu.psu.cse.siis.ic3.Ic3Data.Application.Component.Extra;
import edu.psu.cse.siis.ic3.Ic3Data.Application.Component.Instruction;
import edu.psu.cse.siis.ic3.Ic3Data.Attribute;
import edu.psu.cse.siis.ic3.Ic3Data.AttributeKind;
import edu.psu.cse.siis.ic3.manifest.ManifestComponent;
import edu.psu.cse.siis.ic3.manifest.ManifestData;
import edu.psu.cse.siis.ic3.manifest.ManifestIntentFilter;
import edu.psu.cse.siis.ic3.manifest.ManifestPullParser;
public class ProtobufResultProcessor {
private final Logger logger = LoggerFactory.getLogger(getClass());
private static final String ENTRY_POINT_INTENT = "";
private final int[] preciseNonLinking = { 0, 0, 0, 0 };
private final int[] preciseLinking = { 0, 0, 0, 0 };
private final int[] imprecise = { 0, 0, 0, 0, 0 };
private final int[] top = { 0, 0, 0 };
private final int[] bottom = { 0, 0, 0 };
private final int[] nonexistent = { 0, 0, 0 };
private final int[] preciseFieldValueCount = { 0, 0, 0 };
private final int[] partiallyPreciseFieldValueCount = { 0, 0, 0 };
private final int[] impreciseFieldValueCount = { 0, 0, 0 };
private int intentWithData = 0;
private int providerArgument = 0;
public void processResult(String appName, Ic3Data.Application.Builder ic3Builder,
String protobufDestination, boolean binary,
Map componentNameToBuilderMap,
int analysisClassesCount, Writer writer) throws IOException {
for (Result result : Results.getResults()) {
((Ic3Result) result).dump();
analyzeResult(result);
writeResultToProtobuf(result, ic3Builder, componentNameToBuilderMap);
}
ic3Builder.setAnalysisEnd(System.currentTimeMillis() / 1000);
String extension = binary ? "dat" : "txt";
String path =
String.format("%s/%s_%s.%s", protobufDestination, ic3Builder.getName(),
ic3Builder.getVersion(), extension);
System.out.println("PATH: " + path);
if (binary) {
FileOutputStream fileOutputStream = new FileOutputStream(path);
ic3Builder.build().writeTo(fileOutputStream);
fileOutputStream.close();
} else {
FileWriter fileWriter = new FileWriter(path);
TextFormat.print(ic3Builder, fileWriter);
fileWriter.close();
}
Timers.v().totalTimer.end();
String statistics =
appName + " " + analysisClassesCount + " " + PropagationTimers.v().reachableMethods + " "
+ preciseNonLinking[0] + " " + preciseNonLinking[3] + " " + preciseNonLinking[1] + " "
+ preciseNonLinking[2] + " " + preciseLinking[0] + " " + preciseLinking[3] + " "
+ preciseLinking[1] + " " + preciseLinking[2] + " " + imprecise[0] + " " + imprecise[3]
+ " " + imprecise[1] + " " + imprecise[2] + " " + bottom[0] + " " + bottom[1] + " "
+ bottom[2] + " " + top[0] + " " + top[1] + " " + top[2] + " " + nonexistent[0] + " "
+ nonexistent[1] + " " + nonexistent[2] + " " + providerArgument + " " + imprecise[4]
+ " " + preciseFieldValueCount[0] + " " + preciseFieldValueCount[1] + " "
+ preciseFieldValueCount[2] + " " + partiallyPreciseFieldValueCount[0] + " "
+ partiallyPreciseFieldValueCount[1] + " " + partiallyPreciseFieldValueCount[2] + " "
+ impreciseFieldValueCount[0] + " " + impreciseFieldValueCount[1] + " "
+ impreciseFieldValueCount[2] + " " + PropagationTimers.v().modelParsing.getTime()
+ " " + Timers.v().mainGeneration.getTime() + " "
+ Timers.v().entryPointMapping.getTime() + " " + Timers.v().classLoading.getTime()
+ " " + PropagationTimers.v().problemGeneration.getTime() + " "
+ PropagationTimers.v().ideSolution.getTime() + " "
+ PropagationTimers.v().valueComposition.getTime() + " "
+ PropagationTimers.v().resultGeneration.getTime() + " "
+ (PropagationTimers.v().soot.getTime() - PropagationTimers.v().totalTimer.getTime())
+ " " + (Timers.v().misc.getTime() + PropagationTimers.v().misc.getTime()) + " "
+ Timers.v().totalTimer.getTime() + "\n";
if (logger.isInfoEnabled()) {
logger.info(statistics);
}
if (writer != null) {
writer.write(statistics);
writer.close();
}
}
@SuppressWarnings("unchecked")
private void writeResultToProtobuf(Result result, Ic3Data.Application.Builder ic3Builder,
Map componentNameToBuilderMap) {
Map> componentToExtrasMap = new HashMap<>();
Map dynamicReceivers = new HashMap<>();
Map> entryPointMap = ((Ic3Result) result).getEntryPointMap();
for (Map.Entry> entry : result.getResults().entrySet()) {
Unit unit = entry.getKey();
Argument[] arguments = Model.v().getArgumentsForQuery((Stmt) unit);
if (arguments != null) {
SootMethod method = AnalysisParameters.v().getIcfg().getMethodOf(unit);
Instruction.Builder instructionBuilder = unitToInstructionBuilder(method, unit);
Map valueMap = new HashMap<>(arguments.length);
Map argnumToValueMap = entry.getValue();
for (Argument argument : arguments) {
valueMap.put(argument.getProperty("valueType"),
argnumToValueMap.get(argument.getArgnum()[0]));
}
if (valueMap.containsKey("activity")) {
insertProtobufExitPoint(instructionBuilder,
(BasePropagationValue) valueMap.get("activity"), ComponentKind.ACTIVITY, null, null,
entryPointMap.get(method), componentNameToBuilderMap);
} else if (valueMap.containsKey("service")) {
insertProtobufExitPoint(instructionBuilder,
(BasePropagationValue) valueMap.get("service"), ComponentKind.SERVICE, null, null,
entryPointMap.get(method), componentNameToBuilderMap);
} else if (valueMap.containsKey("receiver")) {
insertProtobufExitPoint(instructionBuilder,
(BasePropagationValue) valueMap.get("receiver"), ComponentKind.RECEIVER,
(Set) valueMap.get("permission"), null, entryPointMap.get(method),
componentNameToBuilderMap);
} else if (valueMap.containsKey("intentFilter")) {
insertDynamicReceiver(dynamicReceivers, (Set) valueMap.get("permission"),
(Set) valueMap.get("receiverType"),
(BasePropagationValue) valueMap.get("intentFilter"), method, unit);
} else if (valueMap.containsKey("provider")) {
insertProtobufExitPoint(instructionBuilder,
(BasePropagationValue) valueMap.get("provider"), ComponentKind.PROVIDER, null, null,
entryPointMap.get(method), componentNameToBuilderMap);
} else if (valueMap.containsKey("authority")) {
insertProtobufExitPoint(instructionBuilder,
getUriValueForAuthorities((Set) valueMap.get("authority")),
ComponentKind.PROVIDER, null, null, entryPointMap.get(method),
componentNameToBuilderMap);
} else if (valueMap.containsKey("pendingIntent")) {
BasePropagationValue baseCollectingValue =
(BasePropagationValue) valueMap.get("pendingIntent");
String targetType =
baseCollectingValue instanceof PropagationValue ? (String) ((PropagationValue) baseCollectingValue)
.getValuesForField("targetType").iterator().next().getValue()
: null;
Set permissions = (Set) valueMap.get("permission");
if (targetType != null) {
insertProtobufExitPoint(instructionBuilder, baseCollectingValue,
stringToComponentKind(targetType), permissions, null, entryPointMap.get(method),
componentNameToBuilderMap);
} else {
for (ComponentKind target : Arrays.asList(ComponentKind.ACTIVITY,
ComponentKind.RECEIVER, ComponentKind.SERVICE)) {
insertProtobufExitPoint(instructionBuilder, baseCollectingValue, target, null, null,
entryPointMap.get(method), componentNameToBuilderMap);
}
}
} else if (valueMap.containsKey("componentExtra")) {
Set extras = (Set) valueMap.get("componentExtra");
if (extras != null) {
for (String component : entryPointMap.get(method)) {
Set existingExtras = componentToExtrasMap.get(component);
if (existingExtras == null) {
existingExtras = new HashSet<>();
componentToExtrasMap.put(component, existingExtras);
}
for (String extra : extras) {
Extra.Builder extraBuilder = Extra.newBuilder();
extraBuilder.setExtra(extra);
extraBuilder.setInstruction(instructionBuilder);
existingExtras.add(extraBuilder.build());
}
}
}
}
}
}
for (Map.Entry> entry : componentToExtrasMap.entrySet()) {
componentNameToBuilderMap.get(entry.getKey()).addAllExtras(entry.getValue());
}
for (Component.Builder componentBuilder : componentNameToBuilderMap.values()) {
ic3Builder.addComponents(componentBuilder);
}
for (ManifestComponent manifestComponent : dynamicReceivers.values()) {
Component.Builder componentBuilder =
ManifestPullParser.makeProtobufComponentBuilder(manifestComponent,
ComponentKind.DYNAMIC_RECEIVER);
componentBuilder.setRegistrationInstruction(unitToInstructionBuilder(
manifestComponent.getRegistrationMethod(), manifestComponent.getRegistrationUnit()));
ic3Builder.addComponents(componentBuilder);
}
}
private Instruction.Builder unitToInstructionBuilder(SootMethod method, Unit unit) {
Instruction.Builder builder = Instruction.newBuilder();
builder.setClassName(method.getDeclaringClass().getName());
builder.setMethod(method.getSignature());
builder.setStatement(unit.toString());
builder.setId(getIdForUnit(unit, method));
return builder;
}
private void insertProtobufExitPoint(Instruction.Builder instructionBuilder,
BasePropagationValue intentValue, ComponentKind componentKind, Set intentPermissions,
Integer missingIntents, Set exitPointComponents,
Map componentNameToBuilderMap) {
for (String exitPointComponent : exitPointComponents) {
ExitPoint.Builder exitPointBuilder = ExitPoint.newBuilder();
exitPointBuilder.setInstruction(instructionBuilder).setKind(componentKind);
PropagationValue collectingValue = null;
if (intentValue == null || intentValue instanceof TopPropagationValue
|| intentValue instanceof BottomPropagationValue) {
missingIntents = 0;
} else if (intentValue instanceof PropagationValue) {
collectingValue = (PropagationValue) intentValue;
if (collectingValue.getPathValues() == null || collectingValue.getPathValues().size() == 0) {
missingIntents = 0;
}
} else {
throw new RuntimeException("Unknown CollectingValue type: " + intentValue.getClass());
}
if (missingIntents != null) {
exitPointBuilder.setMissing(missingIntents);
} else {
Set pathValues = collectingValue.getPathValues();
if (pathValues != null) {
for (PathValue pathValue : pathValues) {
if (componentKind.equals(ComponentKind.PROVIDER)) {
exitPointBuilder.addUris(makeProtobufUriBuilder(pathValue));
} else {
if (intentPermissions != null && intentPermissions.size() != 0) {
for (String intentPermission : intentPermissions) {
exitPointBuilder.addIntents(makeProtobufIntentBuilder(pathValue).setPermission(
intentPermission));
}
} else {
exitPointBuilder.addIntents(makeProtobufIntentBuilder(pathValue));
}
}
}
}
}
Component.Builder componentBuilder = componentNameToBuilderMap.get(exitPointComponent);
componentBuilder.addExitPoints(exitPointBuilder);
}
}
private Intent.Builder makeProtobufIntentBuilder(PathValue intentValue) {
Intent.Builder intentBuilder = Intent.newBuilder();
insertSingleValuedIntentAttribute(intentValue, "action", AttributeKind.ACTION, intentBuilder);
Set categories = intentValue.getSetStringFieldValue("categories");
if (categories != null) {
if (categories.contains(null)) {
categories.remove(null);
categories.add(Constants.NULL_STRING);
}
intentBuilder.addAttributes(Attribute.newBuilder().setKind(AttributeKind.CATEGORY)
.addAllValue(categories));
}
Set flags = intentValue.getSetFieldValue("flags", Integer.class);
if (flags != null) {
intentBuilder.addAttributes(Attribute.newBuilder().setKind(AttributeKind.FLAG)
.addAllIntValue(flags));
}
// String mimeType = intentValue.getSingleStringFieldValue("dataType");
// if (mimeType != null) {
// String[] typeParts = mimeType.split("/");
// String type;
// String subtype;
// if (typeParts.length == 2) {
// type = typeParts[0];
// subtype = typeParts[1];
// } else {
// type = Constants.ANY_STRING;
// subtype = Constants.ANY_STRING;
// }
// intentBuilder
// .addAttributes(Attribute.newBuilder().setKind(AttributeKind.TYPE).addValue(type));
// intentBuilder.addAttributes(Attribute.newBuilder().setKind(AttributeKind.SUBTYPE)
// .addValue(subtype));
// }
insertSingleValuedIntentAttribute(intentValue, "dataType", AttributeKind.TYPE, intentBuilder);
Set extras = intentValue.getSetStringFieldValue("extras");
if (extras != null) {
if (extras.contains(null)) {
extras.remove(null);
extras.add(Constants.NULL_STRING);
}
intentBuilder.addAttributes(Attribute.newBuilder().setKind(AttributeKind.EXTRA)
.addAllValue(extras));
}
insertSingleValuedIntentAttribute(intentValue, "clazz", AttributeKind.CLASS, intentBuilder);
insertSingleValuedIntentAttribute(intentValue, "package", AttributeKind.PACKAGE, intentBuilder);
insertSingleValuedIntentAttribute(intentValue, "scheme", AttributeKind.SCHEME, intentBuilder);
insertSingleValuedIntentAttribute(intentValue, "ssp", AttributeKind.SSP, intentBuilder);
insertSingleValuedIntentAttribute(intentValue, "uri", AttributeKind.URI, intentBuilder);
insertSingleValuedIntentAttribute(intentValue, "path", AttributeKind.PATH, intentBuilder);
insertSingleValuedIntentAttribute(intentValue, "query", AttributeKind.QUERY, intentBuilder);
insertSingleValuedIntentAttribute(intentValue, "authority", AttributeKind.AUTHORITY,
intentBuilder);
return intentBuilder;
}
private void insertSingleValuedIntentAttribute(PathValue pathValue, String attribute,
AttributeKind kind, Intent.Builder intentBuilder) {
String attributeValue = pathValue.getScalarStringFieldValue(attribute);
if (attributeValue != null) {
intentBuilder.addAttributes(Attribute.newBuilder().setKind(kind).addValue(attributeValue));
}
}
private Uri.Builder makeProtobufUriBuilder(PathValue uriValue) {
Uri.Builder uriBuilder = Uri.newBuilder();
insertSingleValuedUriAttribute(uriValue, "scheme", AttributeKind.SCHEME, uriBuilder);
insertSingleValuedUriAttribute(uriValue, "ssp", AttributeKind.SSP, uriBuilder);
insertSingleValuedUriAttribute(uriValue, "uri", AttributeKind.URI, uriBuilder);
insertSingleValuedUriAttribute(uriValue, "path", AttributeKind.PATH, uriBuilder);
insertSingleValuedUriAttribute(uriValue, "query", AttributeKind.QUERY, uriBuilder);
insertSingleValuedUriAttribute(uriValue, "authority", AttributeKind.AUTHORITY, uriBuilder);
return uriBuilder;
}
private void insertSingleValuedUriAttribute(PathValue pathValue, String attribute,
AttributeKind kind, Uri.Builder uriBuilder) {
String attributeValue = pathValue.getScalarStringFieldValue(attribute);
if (attributeValue != null) {
uriBuilder.addAttributes(Attribute.newBuilder().setKind(kind).addValue(attributeValue));
}
}
private ComponentKind stringToComponentKind(String componentKind) {
switch (componentKind) {
case "a":
return ComponentKind.ACTIVITY;
case "s":
return ComponentKind.SERVICE;
case "r":
return ComponentKind.RECEIVER;
default:
throw new RuntimeException("Unknown component kind: " + componentKind);
}
}
private void insertDynamicReceiver(Map dynamicReceivers,
Set permissions, Set receiverTypes, BasePropagationValue intentFilters,
SootMethod method, Unit unit) {
if (permissions == null) {
permissions = Collections.singleton(null);
}
for (String receiverType : receiverTypes) {
for (String permission : permissions) {
insertDynamicReceiverHelper(dynamicReceivers, permission, receiverType, intentFilters,
method, unit);
}
}
}
private void insertDynamicReceiverHelper(Map dynamicReceivers,
String permission, String receiverType, BasePropagationValue intentFilters,
SootMethod method, Unit unit) {
Integer missingIntentFilters;
Set manifestIntentFilters;
if (intentFilters == null || intentFilters instanceof TopPropagationValue
|| intentFilters instanceof BottomPropagationValue) {
missingIntentFilters = 0;
manifestIntentFilters = null;
} else if (intentFilters instanceof PropagationValue) {
missingIntentFilters = null;
PropagationValue collectingValue = (PropagationValue) intentFilters;
manifestIntentFilters = new HashSet<>();
for (PathValue branchValue : collectingValue.getPathValues()) {
Integer filterPriority = null;
FieldValue priorityFieldValue = branchValue.getFieldValue("priority");
if (priorityFieldValue != null) {
filterPriority = (Integer) priorityFieldValue.getValue();
}
manifestIntentFilters.add(new ManifestIntentFilter(branchValue
.getSetStringFieldValue("actions"), branchValue.getSetStringFieldValue("categories"),
false, makeManifestData(branchValue), filterPriority));
}
} else {
throw new RuntimeException("Unknown intent filter type: " + intentFilters.getClass());
}
ManifestComponent manifestComponent = dynamicReceivers.get(receiverType);
if (manifestComponent == null) {
manifestComponent =
new ManifestComponent(
edu.psu.cse.siis.ic3.db.Constants.ComponentShortType.DYNAMIC_RECEIVER, receiverType,
true, true, permission, null, missingIntentFilters, method, unit);
dynamicReceivers.put(receiverType, manifestComponent);
}
manifestComponent.addIntentFilters(manifestIntentFilters);
}
private List makeManifestData(PathValue branchValue) {
Set mimeTypes = branchValue.getSetStringFieldValue("dataType");
Set authorities =
branchValue.getSetFieldValue("authorities", DataAuthority.class);
Set paths = branchValue.getSetStringFieldValue("paths");
Set schemes = branchValue.getSetStringFieldValue("schemes");
if (mimeTypes == null && authorities == null && paths == null && schemes == null) {
return null;
}
if (mimeTypes == null) {
mimeTypes = Collections.singleton(null);
}
if (authorities == null) {
authorities = Collections.singleton(new DataAuthority(null, null));
}
if (paths == null) {
paths = Collections.singleton(null);
}
if (schemes == null) {
schemes = Collections.singleton(null);
}
List result = new ArrayList<>();
for (String mimeType : mimeTypes) {
for (DataAuthority dataAuthority : authorities) {
for (String dataPath : paths) {
for (String scheme : schemes) {
result.add(new ManifestData(scheme, dataAuthority.getHost(), dataAuthority.getPort(),
dataPath, mimeType));
}
}
}
}
return result;
}
private BasePropagationValue getUriValueForAuthorities(Set authorities) {
if (authorities == null) {
return null;
}
PropagationValue collectingValue = new PropagationValue();
for (String authority : authorities) {
PathValue branchValue = new PathValue();
ScalarFieldValue schemeFieldValue = new ScalarFieldValue("content");
branchValue.addFieldEntry("scheme", schemeFieldValue);
ScalarFieldValue authorityFieldValue = new ScalarFieldValue(authority);
branchValue.addFieldEntry("authority", authorityFieldValue);
collectingValue.addPathValue(branchValue);
}
return collectingValue;
}
private int getIdForUnit(Unit unit, SootMethod method) {
int id = 0;
for (Unit currentUnit : method.getActiveBody().getUnits()) {
if (currentUnit == unit) {
return id;
}
++id;
}
return -1;
}
@SuppressWarnings("unchecked")
private void analyzeResult(Result result) {
Set nonLinkingFieldNames = new HashSet<>();
nonLinkingFieldNames.add("extras");
nonLinkingFieldNames.add("flags");
nonLinkingFieldNames.add("fragment");
nonLinkingFieldNames.add("query");
for (Map.Entry> entry0 : result.getResults().entrySet()) {
Collection