private List<Unit> instrumentIntentAddings( BiDiInterproceduralCFG<Unit, SootMethod> cfg, Unit unit, InvokeExpr sinkExpr, Set<ResultSourceInfo> sourceInfo) { if (isMethodInterComponentSink(sinkExpr.getMethod())) { SootMethod method = cfg.getMethodOf(unit); Body body = null; if (method.hasActiveBody()) body = method.retrieveActiveBody(); else throw new RuntimeException("No body found!"); Set<String> sourceCategories = getDataIdList(sourceInfo); final String hashSetType = "java.util.HashSet"; List<Unit> generated = new ArrayList<Unit>(); // HashSet initialization Local hashSetLocal = generateFreshLocal(body, RefType.v(hashSetType)); NewExpr newExpr = Jimple.v().newNewExpr(RefType.v(hashSetType)); AssignStmt assignStmt = Jimple.v().newAssignStmt(hashSetLocal, newExpr); generated.add(assignStmt); // constructor call SpecialInvokeExpr constructorCall = Jimple.v() .newSpecialInvokeExpr( hashSetLocal, Scene.v().getMethod("<java.util.HashSet: void <init>()>").makeRef()); InvokeStmt constructorCallStmt = Jimple.v().newInvokeStmt(constructorCall); generated.add(constructorCallStmt); // add categories to HashSet for (String cat : sourceCategories) { InterfaceInvokeExpr addCall = Jimple.v() .newInterfaceInvokeExpr( hashSetLocal, Scene.v().getMethod("<java.util.Set: boolean add(java.lang.Object)>").makeRef(), StringConstant.v(cat)); InvokeStmt addCallStmt = Jimple.v().newInvokeStmt(addCall); generated.add(addCallStmt); } // get Intent Value intent = sinkExpr.getArg(0); List<Object> args = new ArrayList<Object>(); args.add(RefType.v("android.content.Intent")); args.add(intent); args.add(RefType.v(hashSetType)); args.add(hashSetLocal); StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr( Settings.INSTRUMENTATION_HELPER_JAVA, "addTaintInformationToIntent", args); InvokeStmt invStmt = Jimple.v().newInvokeStmt(sie); generated.add(invStmt); return generated; } return Collections.emptyList(); }
/** * Generate a default assignment with 'local' as left-hand-side value. * * @param local * @return */ private Unit createCorrectDummyAssignment(Local local) { Unit dummyAssignemnt = null; if (local.getType() instanceof PrimType) { if (local.getType() instanceof IntType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr(Settings.SANITIZER, "dummyInteger", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else if (local.getType() instanceof BooleanType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr(Settings.SANITIZER, "dummyBoolean", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else if (local.getType() instanceof ByteType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr(Settings.SANITIZER, "dummyByte", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else if (local.getType() instanceof CharType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr( Settings.SANITIZER, "dummyCharacter", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else if (local.getType() instanceof DoubleType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr(Settings.SANITIZER, "dummyDouble", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else if (local.getType() instanceof FloatType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr(Settings.SANITIZER, "dummyFloat", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else if (local.getType() instanceof LongType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr(Settings.SANITIZER, "dummyLong", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else if (local.getType() instanceof ShortType) { StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr(Settings.SANITIZER, "dummyShort", null); dummyAssignemnt = Jimple.v().newAssignStmt(local, sie); } else throw new RuntimeException("Oops, the primitive type is not correct"); } else { if (local.getType().equals(RefType.v("java.lang.String"))) dummyAssignemnt = Jimple.v().newAssignStmt(local, StringConstant.v("")); else dummyAssignemnt = Jimple.v().newAssignStmt(local, NullConstant.v()); } return dummyAssignemnt; }
/** * Generate Policy Enforcement Point (PEP) for Unit 'unit'. * * @param unit * @param invExpr * @param body * @param dataFlowAvailable * @param assignmentStatement * @return */ private List<Unit> generatePolicyEnforcementPoint( Unit unit, InvokeExpr invExpr, Body body, int dataFlowAvailable, boolean assignmentStatement) { log.debug("Dataflow available: " + dataFlowAvailable); List<Unit> generated = new ArrayList<Unit>(); // store all new units that are generated String methodSignature = invExpr.getMethod().getSignature(); EventInformation eventInfo = allEventInformation.get(methodSignature); String eventName = eventInfo.getEventName(); Set<Pair<Integer, String>> allParameterInformation = eventInfo.getParameterInformation(); // This list containts types and parameters that are used to build the // invoke expression to "isStmtExecutionAllowed': // // java.lang.String "eventName" // IntType "dataFlowAvailable" // java.lang.Object[] "parameters" // List<Object> parameterForHelperMethod = new ArrayList<Object>(); List<Object> categories = new ArrayList<Object>(); // add event name information Type eventNameType = RefType.v("java.lang.String"); parameterForHelperMethod.add(eventNameType); StringConstant eventNameConstant = StringConstant.v(eventName); parameterForHelperMethod.add(eventNameConstant); // add information about dataflow availability parameterForHelperMethod.add(IntType.v()); parameterForHelperMethod.add(IntConstant.v(dataFlowAvailable)); // add information about parameters parameterForHelperMethod.add(getParameterArrayType()); List<Value> paramValues = new ArrayList<Value>(); for (Pair<Integer, String> parameterInfo : allParameterInformation) { paramValues.add(StringConstant.v("param" + parameterInfo.getLeft() + "value")); paramValues.add(invExpr.getArg(parameterInfo.getLeft())); } Pair<Value, List<Unit>> arrayRefAndInstrumentation = generateParameterArray(paramValues, body); generated.addAll(arrayRefAndInstrumentation.getRight()); parameterForHelperMethod.add(arrayRefAndInstrumentation.getLeft()); // Generate PEP call to the PDP. Store the result send by the PDP to 'resultPDPLocal' // Pseudo code looks like this: // // resultPDPLocal = isStmtExecutionAllowed(eventName, dataFlowAvailable, parameters); // StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr( Settings.INSTRUMENTATION_HELPER_JAVA, "isStmtExecutionAllowed", parameterForHelperMethod); Local resultPDPLocal = generateFreshLocal(body, soot.IntType.v()); AssignStmt asssCondition = Jimple.v().newAssignStmt(resultPDPLocal, sie); generated.add(asssCondition); for (Unit u : generated) { System.out.println("isStmt gen: " + u); } if (assignmentStatement) { // If the method call before which the PEP in inserted is an assignment statement of // the form "resultPDPLocal = originalCallThatIsChecked()", generate a new assignment // statement that stores a default value to "resultPDPLocal" if the PDP does not // allow the call of method originalCallThatIsChecked(). // // Pseudo-code: // // if(resultPDPLocal == 0) goto dummyLabel: // result = originalCallThatIsChecked(); // goto dummyLabel2: // dummyLabel: // result = dummyValue (i.e., 0 for IntType, false for BooleanType, ...) // dummyLabel2: // nop // if (unit instanceof DefinitionStmt) { DefinitionStmt defStmt = (DefinitionStmt) unit; Value pepCondition = Jimple.v().newEqExpr(resultPDPLocal, IntConstant.v(0)); // insert nop Unit label2Nop = Jimple.v().newNopStmt(); body.getUnits().insertAfter(label2Nop, unit); // insert result = dummyValue Unit dummyStatement = createCorrectDummyAssignment((Local) defStmt.getLeftOp()); body.getUnits().insertAfter(dummyStatement, unit); log.debug("insert c: " + dummyStatement); // insert goto dummyLabel2: body.getUnits().insertAfter(Jimple.v().newGotoStmt(label2Nop), unit); IfStmt ifStmt = Jimple.v().newIfStmt(pepCondition, dummyStatement); generated.add(ifStmt); } else { throw new RuntimeException( "error: expected DefinitionStmt got " + unit + " -> " + unit.getClass()); } } else { // If the method call before which the PEP in inserted is a call statement of // the form "originalCallThatIsChecked()", generate a new nop statement // to jump to if the PDP does not allow the call of method originalCallThatIsChecked(). // // Pseudo-code: // // if(resultPDPLocal == 0) goto nopLabel: // result = originalCallThatIsChecked(); // nopLabel: // nop // Value pepCondition = Jimple.v().newEqExpr(resultPDPLocal, IntConstant.v(0)); NopStmt nopStmt = Jimple.v().newNopStmt(); body.getUnits().insertAfter(nopStmt, unit); log.debug("insert d: " + nopStmt); IfStmt ifStmt = Jimple.v().newIfStmt(pepCondition, nopStmt); generated.add(ifStmt); } return generated; }
/** * @param cfg * @param sink * @param assignmentStatement */ private void instrumentSourceToSinkConnections( BiDiInterproceduralCFG<Unit, SootMethod> cfg, ResultSinkInfo sink, boolean assignmentStatement) { sourceSinkConnectionCounter += 1; // loop through the sinks for (ResultSinkInfo key : results.getResults().keySet()) { log.debug("compare: " + key); log.debug(" to: " + sink); // if the current sink is the sink at the unit tagged with 'sink' if (key.equals(sink)) { // loop through the sources for (ResultSourceInfo si : results.getResults().get(key)) { Stmt stmt = si.getSource(); SootMethod sm = cfg.getMethodOf(stmt); Body body = sm.retrieveActiveBody(); // Source instrumentation. The three type categories for the source are: // - callback // - ICC source method (i.e., Intent.getExtras()) // - not a callback and not an ICC source method (i.e., getLine1Number()) // if (isInterComponentSourceCallback(si, cfg)) { throw new RuntimeException("Callbacks as sources are not supported right now"); } else if (isInterComponentSourceNoCallback(si, cfg)) { // only invoke expression are treated here if (stmt.containsInvokeExpr()) { // only statements that return a android.os.Bundle are currently supported if (stmt instanceof DefinitionStmt) { DefinitionStmt defStmt = (DefinitionStmt) stmt; Value leftValue = defStmt.getLeftOp(); if (leftValue.getType().equals(RefType.v("android.os.Bundle"))) { List<Object> args = new ArrayList<Object>(); args.add(IntType.v()); args.add(IntConstant.v(sourceSinkConnectionCounter)); args.add(RefType.v("android.os.Bundle")); args.add(leftValue); InvokeExpr invExpr = Instrumentation.createJimpleStaticInvokeExpr( Settings.INSTRUMENTATION_HELPER_JAVA, "registerNewSourceSinkConnection", args); InvokeStmt invStmt = Jimple.v().newInvokeStmt(invExpr); Unit instrumentationPoint = null; if (stmt instanceof IdentityStmt) { instrumentationPoint = getLastIdentityStmt(body); } else { instrumentationPoint = stmt; } body.getUnits().insertAfter(invStmt, instrumentationPoint); log.debug("insert a: " + invStmt); } else { System.err.println("We do only support android.os.Bundle right now!"); } } } } else { String sourceCat = getSourceCategory(si); if (sourceCat != null) { List<Object> args = new ArrayList<Object>(); args.add(IntType.v()); args.add(IntConstant.v(sourceSinkConnectionCounter)); args.add(RefType.v("java.lang.String")); args.add(StringConstant.v(sourceCat)); InvokeExpr invExpr = Instrumentation.createJimpleStaticInvokeExpr( Settings.INSTRUMENTATION_HELPER_JAVA, "registerNewSourceSinkConnection", args); InvokeStmt invStmt = Jimple.v().newInvokeStmt(invExpr); Unit instrumentationPoint = null; if (stmt instanceof IdentityStmt) instrumentationPoint = getLastIdentityStmt(body); else instrumentationPoint = stmt; body.getUnits().insertAfter(invStmt, instrumentationPoint); log.debug("insert b: " + invStmt); } } // sink instrumentation if (sink.getSink().containsInvokeExpr()) { Body bodyOfSink = cfg.getMethodOf(key.getSink()).getActiveBody(); InvokeExpr invExpr = sink.getSink().getInvokeExpr(); List<Unit> generated = new ArrayList<Unit>(); generated.addAll( instrumentIntentAddings(cfg, stmt, invExpr, results.getResults().get(key))); EventInformation sinkEventInfo = allEventInformation.get(invExpr.getMethod().getSignature()); EventInformation sourceEventInfo = allEventInformation.get(si.getSource().getInvokeExpr().getMethod().getSignature()); generated.addAll( generatePolicyEnforcementPoint( key.getSink(), invExpr, bodyOfSink, sourceSinkConnectionCounter, assignmentStatement)); log.debug("body with data flow:\n" + body); for (Unit u : generated) { log.debug("gen: " + u); } if (sinkEventInfo.isInstrumentAfterStatement()) bodyOfSink.getUnits().insertAfter(generated, key.getSink()); else bodyOfSink.getUnits().insertBefore(generated, key.getSink()); } else throw new RuntimeException("Double-Check the assumption"); } // loop through the sources } // if the sink at the unit is the current sink } // loop through the sinks }