[Java] Tracking Taint through Fluent Libraries #5809
-
I'm attempting to track taint as it flows through a fluent async promise-based library built into the ratpack framework. In particular, I'm attempting to track taint in the following situation: void test2(Context ctx) {
ctx.getRequest().getBody().map(TypedData::source).then(this::sink); //$hasTaintFlow
} The source is This is query that I've come up with so far: import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
/** A reference type that extends a parameterization the Promise type. */
class RatpackPromise extends RefType {
RatpackPromise() {
getSourceDeclaration().getASourceSupertype*().hasQualifiedName("ratpack.exec", "Promise")
}
}
class RatpackPromiseMapMethod extends Method {
RatpackPromiseMapMethod() {
getDeclaringType() instanceof RatpackPromise and
hasName("map")
}
}
class RatpackPromiseMapMethodAccess extends MethodAccess {
RatpackPromiseMapMethodAccess() { getMethod() instanceof RatpackPromiseMapMethod }
}
class RatpackPromiseThenMethod extends Method {
RatpackPromiseThenMethod() {
getDeclaringType() instanceof RatpackPromise and
hasName("then")
}
}
class RatpackPromiseThenMethodAccess extends MethodAccess {
RatpackPromiseThenMethodAccess() { getMethod() instanceof RatpackPromiseThenMethod }
}
private class RatpackPromiseTaintPreservingCallable extends AdditionalTaintStep {
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
stepFromFunctionalExpToPromise(node1, node2) or
stepFromPromiseToFunctionalArgument(node1, node2)
}
/**
* Tracks taint from return from lambda function to the outer `Promise`.
*/
private predicate stepFromFunctionalExpToPromise(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionalExpr fe |
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
node2.asExpr().(RatpackPromiseMapMethodAccess).getArgument(0) = fe
)
}
/**
* Tracks taint from the previous `Promise` to the first argument of lambda passed to `map` or `then`.
*/
private predicate stepFromPromiseToFunctionalArgument(DataFlow::Node node1, DataFlow::Node node2) {
exists(RatpackPromiseMapMethodAccess ma |
node1.asExpr() = ma.getQualifier() and
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
)
or
exists(RatpackPromiseThenMethodAccess ma |
node1.asExpr() = ma.getQualifier() and
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
)
}
} If it helps, this is the definition of
Independently running Relevant PR: #4991 |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
I'd say this is a perfect question for @smowton as he (afaik) recently added support for modeling fluent methods in Java. |
Beta Was this translation helpful? Give feedback.
-
I figured it out. My query is actually correct. I just goofed and had failed to import |
Beta Was this translation helpful? Give feedback.
I figured it out. My query is actually correct. I just goofed and had failed to import
private import semmle.code.java.frameworks.ratpack.RatpackExec
into theFramework
module so my additional taint steps weren't being loaded. My overall approach here was correct though.