codeql icon indicating copy to clipboard operation
codeql copied to clipboard

explicit java Function<X,Y> implementation is not tainted?

Open odipar opened this issue 1 year ago • 3 comments

I hit on an issue while implementing a taint tracking use case. So I've prepared a minimal example that showcases the issue: Here is the java code:

import java.util.Optional;
import java.util.function.Function;

public class SourceToSinkBug {
    public class DoubleToString implements Function<Double, String> {
        public String apply(Double x) { return x.toString(); }
    } 
    public String flow0() { // toString() is tainted
        Double source0 = 1.0;
        String sink0 = source0.toString();
        return sink0;
    }

    public String flow1() { // Lambda is tainted
        Double source1 = 1.0;
        Optional<Double> opt1 = Optional.of(source1);
        Optional<String> map1 = opt1.map(x -> x.toString());
        String sink1 = map1.get();
        return sink1;
    }
    public String flow2() { // BUG?: DoubleToString *isn't* tainted?
        Double source2 = 2.0;
        Optional<Double> opt2 = Optional.of(source2);
        Optional<String> map2 = opt2.map(new DoubleToString());
        String sink2 = map2.get();
        return sink2;
    }
    public String flow3() { // Inline function is tainted
        Double source3 = 3.0;
        Optional<Double> opt3 = Optional.of(source3);
        Optional<String> map3 = opt3.map(
            new Function<Double,String>(){ public String apply(Double x) { return x.toString(); }});
        String sink3 = map3.get();
        return sink3;
    }
}

I expect all flows to be in the query result when we taint source(x) with sink(x). However flow2 is not reported?

Here is the codeql query:

import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking

class Source1 extends VarAccess {
  Source1() { this.getVariable().getName().matches("source%")}
}
class Sink1 extends VarAccess {
  Sink1() { this.getVariable().getName().matches("sink%") }
}

// source% to sink%
module Config implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) { source.asExpr() instanceof Source1 }
  predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof Sink1 }
}

module MyFlow = TaintTracking::Global<Config>;

from DataFlow::Node source, DataFlow::Node sink
where MyFlow::flow(source, sink)
select source, sink, "source to sink"

odipar avatar Jan 31 '24 18:01 odipar