From da62a046537c65918c94e322e6720a24a1e435bb Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 20 Nov 2023 18:14:36 +0000 Subject: [PATCH] Note that binding variables may be casting nodes --- .../dataflow/internal/DataFlowPrivate.qll | 13 +++++- .../flow-through-binding/Test.java | 42 +++++++++++++++++++ .../flow-through-binding/options | 1 + .../flow-through-binding/test.expected | 3 ++ .../flow-through-binding/test.ql | 18 ++++++++ 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 java/ql/test/library-tests/flow-through-binding/Test.java create mode 100644 java/ql/test/library-tests/flow-through-binding/options create mode 100644 java/ql/test/library-tests/flow-through-binding/test.expected create mode 100644 java/ql/test/library-tests/flow-through-binding/test.ql diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index bdfa9507673..f5466b2d739 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -375,7 +375,18 @@ predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { compatibleTypes0(t /** A node that performs a type cast. */ class CastNode extends ExprNode { - CastNode() { this.getExpr() instanceof CastingExpr } + CastNode() { + this.getExpr() instanceof CastingExpr + or + exists(SsaExplicitUpdate upd | + upd.getDefiningExpr().(VariableAssign).getSource() = + [ + any(SwitchStmt ss).getExpr(), any(SwitchExpr se).getExpr(), + any(InstanceOfExpr ioe).getExpr() + ] and + this.asExpr() = upd.getAFirstUse() + ) + } } private newtype TDataFlowCallable = diff --git a/java/ql/test/library-tests/flow-through-binding/Test.java b/java/ql/test/library-tests/flow-through-binding/Test.java new file mode 100644 index 00000000000..b3e4cbef73c --- /dev/null +++ b/java/ql/test/library-tests/flow-through-binding/Test.java @@ -0,0 +1,42 @@ +public class Test { + + public static Object testFlowThroughSwitchStmt(String s, Integer i, boolean unknown) { + Object o = unknown ? s : i; + switch (o) { + case Integer i2 -> { return i2; } + default -> { return null; } + } + } + + public static Object testFlowThroughSwitchExpr(String s, Integer i, boolean unknown) { + Object o = unknown ? s : i; + Integer toRet = switch (o) { + case Integer i2 -> i2; + default -> null; + }; + return toRet; + } + + public static Object testFlowThroughBindingInstanceOf(String s, Integer i, boolean unknown) { + Object o = unknown ? s : i; + if (o instanceof Integer i2) + return i2; + else + return null; + } + + public static T source() { return null; } + + public static void sink(Object o) { } + + public static void test(boolean unknown, boolean unknown2) { + + String source1 = source(); + Integer source2 = source(); + sink(testFlowThroughSwitchStmt(source1, source2, unknown)); + sink(testFlowThroughSwitchExpr(source1, source2, unknown)); + sink(testFlowThroughBindingInstanceOf(source1, source2, unknown)); + + } + +} diff --git a/java/ql/test/library-tests/flow-through-binding/options b/java/ql/test/library-tests/flow-through-binding/options new file mode 100644 index 00000000000..a0d1b7e7002 --- /dev/null +++ b/java/ql/test/library-tests/flow-through-binding/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --release 21 diff --git a/java/ql/test/library-tests/flow-through-binding/test.expected b/java/ql/test/library-tests/flow-through-binding/test.expected new file mode 100644 index 00000000000..8fa7e64d645 --- /dev/null +++ b/java/ql/test/library-tests/flow-through-binding/test.expected @@ -0,0 +1,3 @@ +| Test.java:35:23:35:30 | source(...) | Test.java:36:10:36:61 | testFlowThroughSwitchStmt(...) | +| Test.java:35:23:35:30 | source(...) | Test.java:37:10:37:61 | testFlowThroughSwitchExpr(...) | +| Test.java:35:23:35:30 | source(...) | Test.java:38:10:38:68 | testFlowThroughBindingInstanceOf(...) | diff --git a/java/ql/test/library-tests/flow-through-binding/test.ql b/java/ql/test/library-tests/flow-through-binding/test.ql new file mode 100644 index 00000000000..26c4f88db06 --- /dev/null +++ b/java/ql/test/library-tests/flow-through-binding/test.ql @@ -0,0 +1,18 @@ +import java +import semmle.code.java.dataflow.DataFlow + +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.asExpr() = any(MethodCall mc | mc.getCallee().getName() = "source") + } + + predicate isSink(DataFlow::Node sink) { + sink.asExpr() = any(MethodCall mc | mc.getMethod().getName() = "sink").getAnArgument() + } +} + +module Flow = DataFlow::Global; + +from DataFlow::Node source, DataFlow::Node sink +where Flow::flow(source, sink) +select source, sink