예제 #1
0
  /*
   * @see org.jakstab.analysis.ConfigurableProgramAnalysis#post(org.jakstab.analysis.AbstractState, org.jakstab.analysis.StateTransformer, org.jakstab.analysis.Precision)
   */
  @Override
  public Set<AbstractState> post(final AbstractState state, CFAEdge cfaEdge, Precision precision) {

    final RTLStatement statement = (RTLStatement) cfaEdge.getTransformer();
    final ValuationState iState = (ValuationState) state;

    return Collections.singleton(
        statement.accept(
            new DefaultStatementVisitor<AbstractState>() {

              @Override
              protected AbstractState visitDefault(RTLStatement stmt) {
                return state;
              }

              @Override
              public AbstractState visit(RTLVariableAssignment stmt) {
                ValuationState post = new ValuationState(iState);
                Writable lhs = stmt.getLeftHandSide();
                RTLExpression rhs = stmt.getRightHandSide();
                AbstractDomainElement evaledRhs = iState.abstractEval(rhs);

                // Check for stackpointer alignment assignments (workaround for gcc compiled files)
                RTLVariable sp = Program.getProgram().getArchitecture().stackPointer();
                if (lhs.equals(sp) && rhs instanceof RTLOperation) {
                  RTLOperation op = (RTLOperation) rhs;
                  if (op.getOperator().equals(Operator.AND)
                      && op.getOperands()[0].equals(sp)
                      && op.getOperands()[1] instanceof RTLNumber) {
                    evaledRhs = iState.getVariableValue(sp);
                    logger.warn("Ignoring stackpointer alignment at " + stmt.getAddress());
                  }
                }

                post.setVariableValue((RTLVariable) lhs, evaledRhs);

                return post;
              }

              @Override
              public AbstractState visit(RTLMemoryAssignment stmt) {
                ValuationState post = new ValuationState(iState);
                RTLMemoryLocation m = stmt.getLeftHandSide();
                RTLExpression rhs = stmt.getRightHandSide();
                AbstractDomainElement evaledRhs = iState.abstractEval(rhs);
                AbstractDomainElement evaledAddress = iState.abstractEval(m.getAddress());
                post.setMemoryValue(evaledAddress, m.getBitWidth(), evaledRhs);
                return post;
              }

              @Override
              public AbstractState visit(RTLAssume stmt) {

                ValuationState post = new ValuationState(iState);

                RTLExpression assumption = stmt.getAssumption();

                // TODO: implement assume

                if (assumption instanceof RTLOperation) {
                  RTLOperation op = (RTLOperation) assumption;
                  switch (op.getOperator()) {
                    case UNSIGNED_LESS_OR_EQUAL:
                      RTLExpression lhs = op.getOperands()[0];
                      RTLExpression rhs = op.getOperands()[1];
                      IntervalElement evaledLhs = (IntervalElement) iState.abstractEval(lhs);
                      IntervalElement evaledRhs = (IntervalElement) iState.abstractEval(rhs);

                      if (evaledRhs.getLeft() >= 0) {
                        IntervalElement uLessInt =
                            new IntervalElement(
                                evaledRhs.getRegion(),
                                0,
                                evaledRhs.getRight(),
                                1,
                                evaledLhs.getBitWidth());
                        // TODO: Implement meet for interval elements for optimal result
                        // uLessInt = uLessInt.meet(evaledLhs);
                        // if uLessInt.isBot() return Collections.emptySet();
                        // cheap but sound solution for now: only use new interval if it has less
                        // elements
                        if (uLessInt.size() < evaledLhs.size()) {
                          if (lhs instanceof RTLVariable) {
                            post.setVariableValue((RTLVariable) lhs, uLessInt);
                          } else if (lhs instanceof RTLMemoryLocation) {
                            RTLMemoryLocation m = (RTLMemoryLocation) lhs;
                            AbstractDomainElement evaledAddress =
                                iState.abstractEval(m.getAddress());
                            post.setMemoryValue(evaledAddress, m.getBitWidth(), uLessInt);
                          }
                        }
                      }
                      break;
                    default: // nothing
                  }
                }

                return post;
              }

              @Override
              public AbstractState visit(RTLAlloc stmt) {
                ValuationState post = new ValuationState(iState);
                Writable lhs = stmt.getPointer();

                MemoryRegion newRegion;
                if (stmt.getAllocationName() != null) {
                  newRegion = MemoryRegion.create(stmt.getAllocationName());
                } else {
                  // TODO: Detect whether this allocation is unique to allow strong updates
                  newRegion = MemoryRegion.createAsSummary("alloc" + stmt.getLabel());
                }

                IntervalElement basePointer =
                    new IntervalElement(newRegion, ExpressionFactory.createNumber(0, 32));

                if (lhs instanceof RTLVariable) {
                  post.setVariableValue((RTLVariable) lhs, basePointer);
                } else {
                  RTLMemoryLocation m = (RTLMemoryLocation) lhs;
                  AbstractDomainElement evaledAddress = iState.abstractEval(m.getAddress());
                  post.setMemoryValue(evaledAddress, m.getBitWidth(), basePointer);
                }

                return post;
              }

              @Override
              public AbstractState visit(RTLHavoc stmt) {
                ValuationState post = new ValuationState(iState);

                // Only create a single state with the havoc range, since this analysis
                // is not path sensitive
                post.setVariableValue(
                    stmt.getVariable(),
                    // new IntervalElement(ExpressionFactory.getInstance().createNumber(0,
                    // stmt.getVariable().getBitWidth()),
                    // (RTLNumber)stmt.getMaximum()));
                    new IntervalElement(
                        MemoryRegion.GLOBAL,
                        0,
                        ((RTLNumber) stmt.getMaximum()).longValue(),
                        1,
                        stmt.getVariable().getBitWidth()));

                return post;
              }

              @Override
              public AbstractState visit(RTLUnknownProcedureCall stmt) {
                ValuationState post = new ValuationState(iState);
                for (RTLVariable var : stmt.getDefinedVariables()) {
                  post.setVariableValue(var, IntervalElement.getTop(var.getBitWidth()));
                }
                post.setMemoryValue(
                    IntervalElement.getTop(
                        Program.getProgram().getArchitecture().getAddressBitWidth()),
                    32,
                    IntervalElement.getTop(32));
                return post;
              }
            }));
  }
예제 #2
0
파일: Program.java 프로젝트: matneu/jakstab
 /**
  * Returns all variables used in the program. At the current state of the implementation, this
  * includes only registers and flags.
  *
  * @return A set containing all variables used in this program.
  */
 public SetOfVariables getUsedVariables() {
   SetOfVariables result = new SetOfVariables();
   for (CFAEdge edge : cfg.getEdges())
     result.addAll(((RTLStatement) edge.getTransformer()).getUsedVariables());
   return result;
 }
예제 #3
0
  @Override
  public void run() {
    Runtime runtime = Runtime.getRuntime();
    // Jakstab Algorithm
    System.out.println("Starting CPA algorithm.");
    AbstractState start = cpa.initStartState(transformerFactory.getInitialLocation());
    worklist.add(start);
    reached.add(start);
    if (art != null) art.setRoot(start);

    // Set up precisions
    Precision precision = cpa.initPrecision(transformerFactory.getInitialLocation(), null);
    Map<Location, Precision> precisionMap = new HashMap<Location, Precision>();
    precisionMap.put(start.getLocation(), precision);

    int steps = 0;
    statesVisited = 0;
    final int stepThreshold = 1000;
    long startTime = System.currentTimeMillis();
    long lastSteps = 0;
    long lastTime = 0;
    while (!worklist.isEmpty() && !stop && (!failFast || isSound())) {

      statesVisited++;
      if (++steps == stepThreshold) {

        // Helps limit memory usage
        long now = System.currentTimeMillis();
        System.gc();
        long gcTime = System.currentTimeMillis() - now;
        logger.debug("Time for GC: " + gcTime + "ms");

        now = System.currentTimeMillis();
        long duration = Math.max(1, now - lastTime);
        long speed = (1000L * (statesVisited - lastSteps) / duration);
        // speed = Math.min(speed, 1000);

        logger.warn(
            "*** Reached "
                + reached.size()
                + " states, processed "
                + statesVisited
                + " states after "
                + (now - startTime)
                + "ms, at "
                + speed
                + " states/second"
                + (transformerFactory instanceof ResolvingTransformerFactory
                    ? ", " + program.getInstructionCount() + " instructions."
                    : "."));

        logger.info(
            String.format(
                "    Allocated heap memory: %.2f MByte",
                (runtime.totalMemory() - runtime.freeMemory()) / (1024.0 * 1024.0)));

        steps = 0;

        // StatsPlotter.plot((now - startTime) + "\t" + statesVisited
        // +"\t" + program.getInstructionCount() + "\t" + gcTime + "\t"
        // + speed);

        lastSteps = statesVisited;
        lastTime = now;

        if (Options.timeout.getValue() > 0
            && (System.currentTimeMillis() - startTime > Options.timeout.getValue() * 1000)) {
          logger.error("Timeout after " + Options.timeout.getValue() + "s!");
          stop = true;
        }
      }

      // We need the state before precision refinement for building the
      // ART
      AbstractState unadjustedState = worklist.pick();

      /*
       * if (unadjustedState.getLocation().getAddress().toString().equals(
       * "0x00401189") //||
       * unadjustedState.getLocation().getAddress().toString
       * ().equals("0x0040119b") ||
       * unadjustedState.getLocation().getAddress
       * ().toString().equals("0x00401078") ||
       * unadjustedState.getLocation(
       * ).getAddress().toString().equals("0x0040100a") )
       * System.out.println("Debug " +
       * unadjustedState.getLocation().getAddress().toString());
       */

      precision = precisionMap.get(unadjustedState.getLocation());

      Pair<AbstractState, Precision> pair = cpa.prec(unadjustedState, precision, reached);

      // Warning: The refined a is not stored in "reached", only used for
      // successor calculation
      AbstractState a = pair.getLeft();

      /*
       * CompositeState a1 = (CompositeState) a; BasedNumberValuation a2 =
       * (BasedNumberValuation)a1.getComponent(1); if
       * (a2.getStore().isTop()) System.out.println("Debug TOP Value");
       */

      precision = pair.getRight();
      precisionMap.put(a.getLocation(), precision);

      // logger.debug("Picked from worklist: " + a.getIdentifier());

      // getTransformers() and post() might throw exceptions
      try {
        // For each outgoing edge
        // if (a.isTop())
        // System.out.println("Debug TOP");

        /*
         * if
         * (a.getLocation().getAddress().toString().equals("0x004106cd")
         * ||
         * (a.getLocation().getAddress().toString().equals("0x00410498")
         * && a.getLocation().getIndex() >= 0))
         * System.out.println("Debug Transformer Factory:" +
         * a.getLocation().getAddress().toString());
         */

        // Set<CFAEdge> s = transformerFactory.getTransformers(a);
        // System.out.println("Debug Transformer Factory:" +
        // a.getLocation().getAddress().toString());
        for (CFAEdge cfaEdge : transformerFactory.getTransformers(a)) {

          Precision targetPrecision = precisionMap.get(cfaEdge.getTarget());
          if (targetPrecision == null) {
            targetPrecision = cpa.initPrecision(cfaEdge.getTarget(), cfaEdge.getTransformer());
            precisionMap.put(cfaEdge.getTarget(), targetPrecision);
          }

          // Prefix everything by current location for easier
          // debugging
          // Logger.setGlobalPrefix(cfaEdge.getSource().toString());
          // if
          // (cfaEdge.getSource().getAddress().toString().equals("0x00401027")
          // &&
          // cfaEdge.getTarget().getAddress().toString().equals("0x0040102e"))
          // System.out.println("Debug Edge");
          // Calculate the set of abstract successors
          Set<AbstractState> successors = cpa.post(a, cfaEdge, targetPrecision);

          if (successors.isEmpty()) {
            logger.debug("No successors along edge " + cfaEdge + ", reached halt?");
            continue;
          }

          // logger.debug("via edge " + cfaEdge.toString() + " " +
          // successors.size() + " successors.");

          // Process every successor
          for (AbstractState succ : successors) {
            // logger.debug("Processing new post state: " +
            // succ.getIdentifier());

            // Try to merge the new state with an existing one
            Set<AbstractState> statesToRemove = new FastSet<AbstractState>();
            Set<AbstractState> statesToAdd = new FastSet<AbstractState>();

            for (AbstractState r : reached.where(0, ((CompositeState) succ).getComponent(0))) {
              AbstractState merged = cpa.merge(succ, r, targetPrecision);
              if (!merged.equals(r)) {
                // logger.debug("Merge of " +
                // succ.getIdentifier() + " and " +
                // r.getIdentifier() + " produced new state " +
                // merged.getIdentifier());
                statesToRemove.add(r);
                statesToAdd.add(merged);
              }
            }

            // replace the old state in worklist and reached with
            // the merged version
            for (AbstractState r : statesToRemove) {
              reached.remove(r);
              worklist.remove(r);
              // art.remove(r);
            }

            for (AbstractState r : statesToAdd) {
              // Only add r to the worklist if it hasn't been
              // reached yet
              if (reached.add(r)) {
                worklist.add(r);
                if (art != null) art.addChild(unadjustedState, r);
              }
            }

            // if not stopped add to worklist
            if (!cpa.stop(succ, reached, targetPrecision)
                || this.program.checkSMPos(((CompositeState) succ).getLocation().getAddress())) {
              worklist.add(succ);
              reached.add(succ);
              if (art != null) art.addChild(unadjustedState, succ);
            }
          }
          // end for each outgoing edge
        }
      } catch (StateException e) {
        if (e.getState() == null) {
          e.setState(a);
        }
        if (art != null && !unadjustedState.equals(e.getState()))
          art.addChild(unadjustedState, e.getState());
        throw e;
      }
    }
    long endTime = System.currentTimeMillis();
    if (endTime - startTime > 0) {
      logger.info(
          "Processed "
              + statesVisited
              + " states at "
              + (1000L * statesVisited / (endTime - startTime))
              + " states/second");
      logger.info(
          String.format(
              "Allocated heap memory: %.2f MByte",
              (runtime.totalMemory() - runtime.freeMemory()) / (1024.0 * 1024.0)));
    }

    completed = worklist.isEmpty();
  }