@Override protected void analyse(SootClass clazz, final SootMethod method, Body body) { for (Unit unit : body.getUnits()) { unit.apply(new AbstractStmtSwitch() { @Override public void caseInvokeStmt(InvokeStmt stmt) { InvokeExpr expr = stmt.getInvokeExpr(); SootMethod targetMethod = expr.getMethod(); if (!Signatures.methodSignatureMatches(targetMethod, Types.HTTPS_URL_CONNECTION, VoidType.v(), "setDefaultHostnameVerifier", Types.HOSTNAME_VERIFIER)) return; Value value = expr.getArg(0); if (!(value instanceof Local)) return; // TODO e.g. could be a field ref? does soot support points-to in this case? VulnerabilityState state = VulnerabilityState.UNKNOWN; PointsToSet set = Scene.v().getPointsToAnalysis().reachingObjects((Local) value); if (!set.isEmpty()) { if (PointsToUtils.anyTypeVulnerable(set, HostnameVerifierTag.NAME)) { state = VulnerabilityState.VULNERABLE; } else if (PointsToUtils.allTypesSafe(set, HostnameVerifierTag.NAME)) { state = VulnerabilityState.SAFE; } } vulnerabilities.add(new Vulnerability(method, VulnerabilityType.HTTPS_CONNECTION_DEFAULT_HOSTNAME_VERIFIER, state)); } }); } }
@Override protected void analyse(SootClass clazz, final SootMethod method, Body body) { for (Unit unit : body.getUnits()) { unit.apply(new AbstractStmtSwitch() { @Override public void caseInvokeStmt(InvokeStmt stmt) { InvokeExpr expr = stmt.getInvokeExpr(); SootMethod targetMethod = expr.getMethod(); // TODO what if it is casted to HTTP_URL_CONNECTION? if (!Signatures.methodSignatureMatches(targetMethod, Types.HTTPS_URL_CONNECTION, VoidType.v(), "setHostnameVerifier", Types.HOSTNAME_VERIFIER)) return; Value value = expr.getArg(0); if (!(value instanceof Local)) return; VulnerabilityState state = VulnerabilityState.UNKNOWN; PointsToSet set = Scene.v().getPointsToAnalysis().reachingObjects((Local) value); if (!set.isEmpty()) { if (PointsToUtils.anyTypeVulnerable(set, HostnameVerifierTag.NAME)) { state = VulnerabilityState.VULNERABLE; } else if (PointsToUtils.allTypesSafe(set, HostnameVerifierTag.NAME)) { state = VulnerabilityState.SAFE; } } vulnerabilities.add(new Vulnerability(method, VulnerabilityType.HTTPS_CONNECTION_USES_HOSTNAME_VERIFIER, state)); } }); } }
Set<Constraint<Level>> constraintsForBranches(Unit s, final Environment env, final TypeVar oldPc, final TypeVar newPc) throws TypingException { AbstractStmtSwitch g = new AbstractStmtSwitch() { @Override public void defaultCase(Object obj) { throw new NotImplemented(String.format("Branching statement %s not supported yet.", obj)); } @Override public void caseIfStmt(IfStmt stmt) { Set<Constraint<Level>> cs = new HashSet<>(); // add new pc as upper bound to old pc cs.add(Constraints.<Level>le(CTypes.<Level>variable(oldPc), CTypes.<Level>variable(newPc))); for (Var<?> v : ((List<Var<?>>)seqAsJavaListConverter(Vars.getAllFromValueBoxes(stmt.getUseBoxes()).toSeq()).asJava())) { cs.add(Constraints.le(CTypes.<Level>variable(env.get(v)), CTypes.<Level>variable(newPc))); } setResult(cs); } }; s.apply(g); //noinspection unchecked return (Set<Constraint<Level>>) g.getResult(); }
/** * Processes the Write Effect Recursive. * This method is the heart of this class. * @param element The GraphElement, that is currently inspected by the Method. * @param instances The Set of Values, that have been collected so far, as * being a write Effect. */ private void process(GraphElement element, Set<Value> instances) { callDepth++; logger.fine("Processing Write Effect of :"+element+" on depth: "+callDepth + " and visited "+visitCache.size()); // End of Recursion One: // if the sequence of Successors has reached the end if (element == null) return; // End of Recursion Two: // in Case the element is the Post Dominator of the last branching element. // This assures, that one branch is processed after the other. if (currentBranch != null && element.equals(currentBranch.getPostDom())) return; // In Case the Element is branching, then there shall be a call of // recursion. That's the case of an if (or a while - there is no difference here) if (element.isBranchingForwards()) { logger.fine("Contains? "+element); if (visitCache.contains(element)) return; // System.out.println("Seen once before: " + element); // Saving Element into cache visitCache.add(element); logger.fine("Added: "+element); logger.fine("Found Branching Element: "+element + " on Depth: "+ callDepth); // Every new branch shall have its own new Set, that collects the // Writing Effect of this new branch Set<Value> branchInst = new HashSet<>(); currentBranch = element; for (GraphElement branch : element.getSuccessors()) { process(branch, branchInst); } // After processing store it within the cache // If no post dominator is present, simply do nothing if (element.getPostDom() == null) return; Set<Value> branchInstanceCache = instanceCache.get(element.getPostDom().content); if (branchInstanceCache == null) instanceCache.put(element.getPostDom().content, branchInst); else branchInstanceCache.addAll(branchInst); logger.fine("Cached collection: " + branchInst + " for post dom: "+element.getPostDom()); // Reset the last branching, because this branch is now processed, completely currentBranch = null; // Continue with the Post Dominator, everything in between shall be processed process(element.getPostDom(), instances); } else { // Collecting Assignments element.content.apply(new AbstractStmtSwitch() { @Override public void caseAssignStmt(AssignStmt stmt) { logger.fine("Collected "+stmt.getLeftOp() + " on depth "+callDepth); instances.add(stmt.getLeftOp()); } }); process(element.getSuccessor(), instances); } }