Skip to content

Commit c0ebeb9

Browse files
Jami CogswellJami Cogswell
authored andcommitted
Java: use AdditionalTaintStep
1 parent d21c8d7 commit c0ebeb9

File tree

3 files changed

+21
-46
lines changed

3 files changed

+21
-46
lines changed

java/ql/lib/ext/java.io.model.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ extensions:
8888
- ["java.io", "DataInput", True, "readUTF", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
8989
- ["java.io", "DataInputStream", False, "DataInputStream", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
9090
- ["java.io", "File", False, "File", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
91-
- ["java.io", "File", False, "File", "", "", "Argument[1]", "Argument[this]", "taint", "manual"]
91+
# We model this taint step in QL as `FileConstructorChildArgumentStep` in the `PathSanitizer` library
92+
# since we need to sanitize the use of this argument but not later uses of the same SSA variable,
93+
# which is not currently possible in Java with a standard sanitizer due to use-use flow.
94+
# - ["java.io", "File", False, "File", "", "", "Argument[1]", "Argument[this]", "taint", "manual"]
9295
- ["java.io", "File", True, "getAbsoluteFile", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
9396
- ["java.io", "File", True, "getAbsolutePath", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
9497
- ["java.io", "File", True, "getCanonicalFile", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]

java/ql/lib/semmle/code/java/security/PathSanitizer.qll

Lines changed: 17 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -357,27 +357,6 @@ private predicate maybeNull(Expr expr) {
357357
)
358358
}
359359

360-
/** A taint-tracking configuration for reasoning about tainted arguments. */
361-
private module TaintedArgConfig implements DataFlow::ConfigSig {
362-
predicate isSource(DataFlow::Node src) {
363-
src instanceof ActiveThreatModelSource or
364-
src instanceof ApiSourceNode or
365-
// for InlineFlowTest
366-
src.asExpr().(MethodCall).getMethod().getName() = "source"
367-
}
368-
369-
predicate isSink(DataFlow::Node sink) {
370-
sink.asExpr() =
371-
any(ConstructorCall constrCall |
372-
constrCall.getConstructedType() instanceof TypeFile and
373-
constrCall.getNumArgument() = 2
374-
).getArgument(0)
375-
}
376-
}
377-
378-
/** Tracks taint flow to the parent argument of a `File` constructor. */
379-
private module TaintedArgFlow = TaintTracking::Global<TaintedArgConfig>;
380-
381360
/** Holds if `g` is a guard that checks for `..` components. */
382361
private predicate pathTraversalGuard(Guard g, Expr e, boolean branch) {
383362
// Local taint-flow is used here to handle cases where the validated expression comes from the
@@ -391,31 +370,27 @@ private predicate pathTraversalGuard(Guard g, Expr e, boolean branch) {
391370
}
392371

393372
/**
394-
* A sanitizer that considers a `File` constructor safe if its second argument
395-
* is checked for `..` components (`PathTraversalGuard`) or if any internal
396-
* `..` components are removed from it (`PathNormalizeSanitizer`).
373+
* A taint step from a child argument of a `java.io.File` constructor to the
374+
* constructor call.
397375
*
398-
* This also requires a check to ensure that the first argument of the
399-
* `File` constructor is not tainted.
376+
* This step only applies if the argument is not guarded by a check for `..`
377+
* components (`PathTraversalGuard`), or it does not have any internal `..`
378+
* components removed from it (`PathNormalizeSanitizer`), or if the parent
379+
* argument of the constructor may be null.
400380
*/
401-
private class FileConstructorSanitizer extends PathInjectionSanitizer {
402-
FileConstructorSanitizer() {
403-
exists(ConstructorCall constrCall, Argument arg |
381+
private class FileConstructorChildArgumentStep extends AdditionalTaintStep {
382+
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
383+
exists(ConstructorCall constrCall |
404384
constrCall.getConstructedType() instanceof TypeFile and
405-
// Exclude cases where the parent argument is null since the
406-
// `java.io.File` documentation states that such cases are
407-
// treated as if invoking the single-argument `File` constructor.
408-
not maybeNull(constrCall.getArgument(0)) and
409-
// Since we are sanitizing the constructor call, we need to check
410-
// that the parent argument is not tainted.
411-
not TaintedArgFlow::flowToExpr(constrCall.getArgument(0)) and
412-
arg = constrCall.getArgument(1) and
385+
n1.asExpr() = constrCall.getArgument(1) and
386+
n2.asExpr() = constrCall and
413387
(
414-
arg = DataFlow::BarrierGuard<pathTraversalGuard/3>::getABarrierNode().asExpr() or
415-
arg = ValidationMethod<pathTraversalGuard/3>::getAValidatedNode().asExpr() or
416-
TaintTracking::localExprTaint(any(PathNormalizeSanitizer p), arg)
417-
) and
418-
this.asExpr() = constrCall
388+
not n1 = DataFlow::BarrierGuard<pathTraversalGuard/3>::getABarrierNode() and
389+
not n1 = ValidationMethod<pathTraversalGuard/3>::getAValidatedNode() and
390+
not TaintTracking::localExprTaint(any(PathNormalizeSanitizer p), n1.asExpr())
391+
or
392+
maybeNull(constrCall.getArgument(0))
393+
)
419394
)
420395
}
421396
}

java/ql/test/library-tests/pathsanitizer/Test.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
import java.nio.file.Path;
44
import java.nio.file.Paths;
55
import android.net.Uri;
6-
import java.io.BufferedReader;
7-
import java.io.InputStreamReader;
8-
import java.net.Socket;
96

107
public class Test {
118

0 commit comments

Comments
 (0)