/** * Copies the given access path with a new base value, but retains the base type * * @param original The original access path * @param val The new value * @return The new access path with the exchanged value */ public AccessPath copyWithNewValue(AccessPath original, Value val) { return copyWithNewValue(original, val, original.getBaseType(), false); }
public boolean hasCompatibleTypesForCall(AccessPath apBase, SootClass dest) { if (!manager.getConfig().getEnableTypeChecking()) return true; // Cannot invoke a method on a primitive type if (apBase.getBaseType() instanceof PrimType) return false; // Cannot invoke a method on an array if (apBase.getBaseType() instanceof ArrayType) return dest.getName().equals("java.lang.Object"); return checkCast(apBase, dest.getType()); }
/** * Gets whether the given access path can have aliases * * @param ap The access path to check * @return True if the given access path can have aliases, otherwise false */ public static boolean canHaveAliases(AccessPath ap) { // String cannot have aliases if (TypeUtils.isStringType(ap.getBaseType()) && !ap.getCanHaveImmutableAliases()) return false; // We never ever handle primitives as they can never have aliases if (ap.isStaticFieldRef()) { if (ap.getFirstFieldType() instanceof PrimType) return false; } else if (ap.getBaseType() instanceof PrimType) return false; return true; }
/** * Writes the given access path into the given XML stream writer * * @param accessPath The access path to write out * @param writer The stream writer into which to write the data * @throws XMLStreamException Thrown if the XML data cannot be written */ protected void writeAccessPath(AccessPath accessPath, XMLStreamWriter writer) throws XMLStreamException { writer.writeStartElement(XmlConstants.Tags.accessPath); if (accessPath.getPlainValue() != null) writer.writeAttribute(XmlConstants.Attributes.value, accessPath.getPlainValue().toString()); if (accessPath.getBaseType() != null) writer.writeAttribute(XmlConstants.Attributes.type, accessPath.getBaseType().toString()); writer.writeAttribute(XmlConstants.Attributes.taintSubFields, accessPath.getTaintSubFields() ? XmlConstants.Values.TRUE : XmlConstants.Values.FALSE); // Write out the fields if (accessPath.getFieldCount() > 0) { writer.writeStartElement(XmlConstants.Tags.fields); for (int i = 0; i < accessPath.getFieldCount(); i++) { writer.writeStartElement(XmlConstants.Tags.field); writer.writeAttribute(XmlConstants.Attributes.value, accessPath.getFields()[i].toString()); writer.writeAttribute(XmlConstants.Attributes.type, accessPath.getFieldTypes()[i].toString()); writer.writeEndElement(); } writer.writeEndElement(); } writer.writeEndElement(); }
/** * Creates a flow source based on an access path and a gap invocation statement. * The flow source need not necessarily be unique. For a call z=b.foo(a,a), the * flow source for access path "a" can either be parameter 0 or parameter 1. * * @param accessPath * The access path for which to create the flow source * @param stmt * The statement that calls the sink with the given access path * @param The * definition of the gap from which the data flow originates * @return The set of generated flow sources */ private Set<FlowSource> getFlowSource(AccessPath accessPath, Stmt stmt, GapDefinition gap) { Set<FlowSource> res = new HashSet<FlowSource>(); // This can be a base object if (stmt.getInvokeExpr() instanceof InstanceInvokeExpr) if (((InstanceInvokeExpr) stmt.getInvokeExpr()).getBase() == accessPath.getPlainValue()) res.add(new FlowSource(SourceSinkType.Field, accessPath.getBaseType().toString(), gap)); // This can be a parameter for (int i = 0; i < stmt.getInvokeExpr().getArgCount(); i++) if (stmt.getInvokeExpr().getArg(i) == accessPath.getPlainValue()) res.add(new FlowSource(SourceSinkType.Parameter, i, accessPath.getBaseType().toString(), gap)); // This can be a return value if (stmt instanceof DefinitionStmt) if (((DefinitionStmt) stmt).getLeftOp() == accessPath.getPlainValue()) res.add(new FlowSource(SourceSinkType.Return, accessPath.getBaseType().toString(), gap)); return res; }
/** * Appends additional fields to the given access path * * @param original The original access path to which to append the fields * @param apFields The fields to append * @param apFieldTypes The types of the fields to append * @param taintSubFields True if the new access path shall taint all objects * reachable through it, false if it shall only point to * precisely one object * @return The new access path */ public AccessPath appendFields(AccessPath original, SootField[] apFields, Type[] apFieldTypes, boolean taintSubFields) { int offset = original.getFields() == null ? 0 : original.getFields().length; SootField[] fields = new SootField[offset + (apFields == null ? 0 : apFields.length)]; Type[] fieldTypes = new Type[offset + (apFields == null ? 0 : apFields.length)]; if (original.getFields() != null) { System.arraycopy(original.getFields(), 0, fields, 0, original.getFields().length); System.arraycopy(original.getFieldTypes(), 0, fieldTypes, 0, original.getFieldTypes().length); } if (apFields != null && apFields.length > 0) { System.arraycopy(apFields, 0, fields, offset, apFields.length); System.arraycopy(apFieldTypes, 0, fieldTypes, offset, apFieldTypes.length); } return createAccessPath(original.getPlainValue(), fields, original.getBaseType(), fieldTypes, taintSubFields, false, true, original.getArrayTaintType()); }
/** * Creates a sink that models a value assigned to a field reachable through a * parameter value. This variant models a gap inside the method to be summarized * * @param paraIdx The index of the parameter * @param accessPath The access path modeling the field inside the parameter * value * @return The sink object */ public FlowSink createParameterSinkAtGap(int paraIdx, AccessPath accessPath, String gapSignature) { if (accessPath.isLocal()) { if (!(accessPath.getBaseType() instanceof ArrayType)) throw new RuntimeException("Parameter locals cannot directly be sinks"); else return new FlowSink(SourceSinkType.Parameter, paraIdx, accessPath.getBaseType().toString(), accessPath.getTaintSubFields()); } else if (accessPath.getFieldCount() < summaryAPLength) return new FlowSink(SourceSinkType.Parameter, paraIdx, accessPath.getBaseType().toString(), sootFieldsToString(accessPath.getFields()), sootTypesToString(accessPath.getFieldTypes()), accessPath.getTaintSubFields()); else return new FlowSink(SourceSinkType.Parameter, paraIdx, accessPath.getBaseType().toString(), sootFieldsToString(cutAPLength(accessPath.getFields())), sootTypesToString(cutAPLength(accessPath.getFieldTypes())), true); }
/** * Creates a custom. The semantics must be defined by the code that uses the * sink * * @param paraIdx The index of the parameter * @param accessPath The access path modeling the field inside the parameter * value * @param gap The gap in whose parameter the flow ends * @param userData Additional user data to be associated with the sink * @return The sink object */ public FlowSink createCustomSink(int paraIdx, AccessPath accessPath, GapDefinition gap, Object userData) { if (accessPath.isLocal()) { if (gap == null && !accessPath.getTaintSubFields() && !(accessPath.getBaseType() instanceof ArrayType)) throw new RuntimeException("Parameter locals cannot directly be sinks"); else return new FlowSink(SourceSinkType.Custom, paraIdx, accessPath.getBaseType().toString(), accessPath.getTaintSubFields(), gap, userData); } else if (accessPath.getFieldCount() < summaryAPLength) return new FlowSink(SourceSinkType.Custom, paraIdx, accessPath.getBaseType().toString(), sootFieldsToString(accessPath.getFields()), sootTypesToString(accessPath.getFieldTypes()), accessPath.getTaintSubFields(), gap, userData, false); else return new FlowSink(SourceSinkType.Custom, paraIdx, accessPath.getBaseType().toString(), sootFieldsToString(cutAPLength(accessPath.getFields())), sootTypesToString(cutAPLength(accessPath.getFieldTypes())), true, gap, userData, false); }
/** * Creates a sink that models a value assigned to a field reachable through a * parameter value * * @param paraIdx The index of the parameter * @param accessPath The access path modeling the field inside the parameter * value * @param gap The gap in whose parameter the flow ends * @return The sink object */ public FlowSink createParameterSink(int paraIdx, AccessPath accessPath, GapDefinition gap) { if (accessPath.isLocal()) { if (gap == null && !accessPath.getTaintSubFields() && !(accessPath.getBaseType() instanceof ArrayType)) throw new RuntimeException("Parameter locals cannot directly be sinks"); else return new FlowSink(SourceSinkType.Parameter, paraIdx, accessPath.getBaseType().toString(), accessPath.getTaintSubFields(), gap); } else if (accessPath.getFieldCount() < summaryAPLength) return new FlowSink(SourceSinkType.Parameter, paraIdx, accessPath.getBaseType().toString(), sootFieldsToString(accessPath.getFields()), sootTypesToString(accessPath.getFieldTypes()), accessPath.getTaintSubFields(), gap, false); else return new FlowSink(SourceSinkType.Parameter, paraIdx, accessPath.getBaseType().toString(), sootFieldsToString(cutAPLength(accessPath.getFields())), sootTypesToString(cutAPLength(accessPath.getFieldTypes())), true, gap, false); }
/** * value val gets new base, fields are preserved. * * @param original The original access path * @param val The new base value * @param reduceBases True if circular types shall be reduced to bases * @param arrayTaintType The way a tainted array shall be handled * @return This access path with the base replaced by the value given in the val * parameter */ public AccessPath copyWithNewValue(AccessPath original, Value val, Type newType, boolean cutFirstField, boolean reduceBases, ArrayTaintType arrayTaintType) { // If this copy would not add any new information, we can safely use the // old // object if (original.getPlainValue() != null && original.getPlainValue().equals(val) && original.getBaseType().equals(newType) && original.getArrayTaintType() == arrayTaintType) return original; // Create the new access path AccessPath newAP = createAccessPath(val, original.getFields(), newType, original.getFieldTypes(), original.getTaintSubFields(), cutFirstField, reduceBases, arrayTaintType, original.getCanHaveImmutableAliases()); // Again, check whether we can do without the new object if (newAP != null && newAP.equals(original)) return original; else return newAP; }
/** * Creates a new source model based on the given information * * @param type The type of data flow source * @param parameterIdx The index of the method parameter through which the * source value was obtained * @param accessPath The access path describing the exact source object * @param gap The gap from which this flow originated. Null if this * flow did not originate from a gap. * @return The newly created source object */ public FlowSource createSource(SourceSinkType type, int parameterIdx, AccessPath accessPath, GapDefinition gap) { return new FlowSource(type, parameterIdx, accessPath.getBaseType().toString(), sootFieldsToString(cutAPLength(accessPath.getFields())), sootTypesToString(cutAPLength(accessPath.getFieldTypes())), gap); }
/** * Creates a sink that models the value returned by the method or a field * reachable through the return value. * * @param accessPath The access path modeling the returned value * @param gap The gap to whose return value the data flows * @return The sink object */ public FlowSink createReturnSink(AccessPath accessPath, GapDefinition gap) { if (accessPath.isLocal()) return new FlowSink(SourceSinkType.Return, -1, accessPath.getBaseType().toString(), accessPath.getTaintSubFields(), gap); else if (accessPath.getFieldCount() < summaryAPLength) return new FlowSink(SourceSinkType.Return, -1, accessPath.getBaseType().toString(), sootFieldsToString(accessPath.getFields()), sootTypesToString(accessPath.getFieldTypes()), accessPath.getTaintSubFields(), gap, false); else return new FlowSink(SourceSinkType.Return, -1, accessPath.getBaseType().toString(), sootFieldsToString(cutAPLength(accessPath.getFields())), sootTypesToString(cutAPLength(accessPath.getFieldTypes())), true, gap, false); }
/** * Creates a sink that models a value assigned to a field * * @param accessPath The access path modeling the field * @param gap The gap in which this field taint ends * @return The sink object */ public FlowSink createFieldSink(AccessPath accessPath, GapDefinition gap) { if (accessPath.isLocal()) return new FlowSink(SourceSinkType.Field, -1, accessPath.getBaseType().toString(), accessPath.getTaintSubFields(), gap); else if (accessPath.getFieldCount() < summaryAPLength) return new FlowSink(SourceSinkType.Field, -1, accessPath.getBaseType().toString(), sootFieldsToString(accessPath.getFields()), sootTypesToString(accessPath.getFieldTypes()), accessPath.getTaintSubFields(), gap, false); else return new FlowSink(SourceSinkType.Field, -1, accessPath.getBaseType().toString(), sootFieldsToString(cutAPLength(accessPath.getFields())), sootTypesToString(cutAPLength(accessPath.getFieldTypes())), true, gap, false); }
private Abstraction checkAbstraction(Abstraction abs) { if (abs == null) return null; // Primitive types and strings cannot have aliases and thus // never need to be propagated back if (!abs.getAccessPath().isStaticFieldRef()) { if (abs.getAccessPath().getBaseType() instanceof PrimType) return null; if (TypeUtils.isStringType(abs.getAccessPath().getBaseType()) && !abs.getAccessPath().getCanHaveImmutableAliases()) return null; } else { if (abs.getAccessPath().getFirstFieldType() instanceof PrimType) return null; if (TypeUtils.isStringType(abs.getAccessPath().getFirstFieldType()) && !abs.getAccessPath().getCanHaveImmutableAliases()) return null; } return abs; }
if (manager.getTypeUtils().checkCast(source.getAccessPath(), params[2].getType())) { AccessPath ap = manager.getAccessPathFactory().copyWithNewValue(source.getAccessPath(), params[2], source.getAccessPath().getBaseType(), false); Abstraction abs = source.deriveNewAbstraction(ap, call); abs.setCorrespondingCallSite(call); if (manager.getTypeUtils().checkCast(source.getAccessPath(), params[1].getType())) { AccessPath ap = manager.getAccessPathFactory().copyWithNewValue(source.getAccessPath(), params[1], source.getAccessPath().getBaseType(), false, true, ArrayTaintType.Length); Abstraction abs = source.deriveNewAbstraction(ap, call); abs.setCorrespondingCallSite(call);
if (manager.getTypeUtils().checkCast(source.getAccessPath(), params[2].getType())) { AccessPath ap = manager.getAccessPathFactory().copyWithNewValue(source.getAccessPath(), params[2], source.getAccessPath().getBaseType(), false); Abstraction abs = source.deriveNewAbstraction(ap, call); abs.setCorrespondingCallSite(call); if (manager.getTypeUtils().checkCast(source.getAccessPath(), params[1].getType())) { AccessPath ap = manager.getAccessPathFactory().copyWithNewValue(source.getAccessPath(), params[1], source.getAccessPath().getBaseType(), false, true, ArrayTaintType.Length); Abstraction abs = source.deriveNewAbstraction(ap, call); abs.setCorrespondingCallSite(call);
curAP.getBaseType(), cutFieldTypes, curAP.getTaintSubFields(), false, false, curAP.getArrayTaintType());
fieldStartIdx = 1; } else { if (!checkCast(type, accessPath.getBaseType())) return false;
Local baseLocal = (Local) iinv.getBase(); if (baseLocal == apAtCall.getPlainValue()) { return sourceSinkFactory.createGapBaseObjectSink(gd, apAtCall.getBaseType());
Type runtimeType = obj.getAccessPath().getBaseType(); if (isComponentType(tp) || isComponentType(runtimeType) || isFilteredSystemType(tp) || isFilteredSystemType(runtimeType)) {