CodeShield-Security / SPDS

Efficient and Precise Pointer-Tracking Data-Flow Framework
Eclipse Public License 2.0
66 stars 12 forks source link

Dataflow gap with static setter/getter + alias #28

Open tiganov opened 3 years ago

tiganov commented 3 years ago

I think I've found a case where Boomerang misses some dataflow (3.1.2).

The reproducer below is based on FlowDroid Listing 2 (PLDI '14), but uses a static setter/getter instead of direct field writes.

boomerangPDS/src/main/java/boomerang/example/BoomerangExampleTarget1.java

public class BoomerangExampleTarget1 {
  public static void main(String... args) {
    Data p = new Data();
    taintIt(customSource(), p);
  }

  private static String customSource() { return "I'm tainted"; }
  private static void customSink(String sunk) { System.out.println(sunk); }

  private static void taintIt(String in, Data out) {
    Data x = out;
    Data.setter(x, in);
    customSink(Data.getter(out));
  }

  static class Data {
    private String f;
    static void setter(Data self, String value) {
      self.f = value;
    }
    static String getter(Data self) {
      return self.f;
    }
  }
}

If I change Data.setter(x, in); to Data.setter(out, in);, then I get a path from the source to the sink.

boomerangPDS/src/main/java/boomerang/example/ExampleMain1.java: createAnalysisTransformer()

 private static Transformer createAnalysisTransformer() {
    return new SceneTransformer() {
      protected void internalTransform(
          String phaseName, @SuppressWarnings("rawtypes") Map options) {
        SootCallGraph sootCallGraph = new SootCallGraph();
        AnalysisScope scope =
            new AnalysisScope(sootCallGraph) {
              @Override
              protected Collection<? extends Query> generate(Edge cfgEdge) {
                Statement statement = cfgEdge.getStart();
                if (statement.toString().contains("customSource") && statement.containsInvokeExpr()) {
                  Val arg = statement.getLeftOp();
                  return Collections.singleton(new ForwardQuery(cfgEdge,
                          new AllocVal(arg, statement, arg)));
                }
                return Collections.emptySet();
              }
            };

        Boomerang solver =
            new Boomerang(
                sootCallGraph, SootDataFlowScope.make(Scene.v()), new DefaultBoomerangOptions() {
              @Override
              public int analysisTimeoutMS() {
                return 10000;
              }
            });

        Collection<Query> seeds = scope.computeSeeds();
        for (Query query : seeds) {
          System.out.println("Solving query: " + query);

          ForwardBoomerangResults<Weight.NoWeight> res = solver.solve((ForwardQuery) query);

          if (res.isTimedout()) {
            throw new RuntimeException("Timed out");
          }

          res.asStatementValWeightTable().cellSet().forEach(cell -> {
            if (cell.getRowKey().getStart().containsInvokeExpr() &&
                    cell.getRowKey().getStart().getInvokeExpr().getMethod().getName().contains("customSink") &&
                    cell.getRowKey().getStart().uses(cell.getColumnKey())) {
              System.out.println("SOURCE: " + query.cfgEdge().getStart().toString());
              System.out.println("SINK: " + cell.getRowKey().getStart().toString());
            }
          });
        }
      }
    };
  }