Add test for record-pattern instanceof

This commit is contained in:
Chris Smowton
2023-11-02 13:50:37 +00:00
parent e41da3b10a
commit 32416f0fdc
8 changed files with 213 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
Test.java:
# 0| [CompilationUnit] Test
# 1| 1: [Class] Test
# 3| 2: [Method] test
# 3| 3: [TypeAccess] void
#-----| 4: (Parameters)
# 3| 0: [Parameter] inp
# 3| 0: [TypeAccess] boolean
# 3| 5: [BlockStmt] { ... }
# 5| 0: [LocalVariableDeclStmt] var ...;
# 5| 0: [TypeAccess] String
# 5| 1: [LocalVariableDeclExpr] directTaint
# 5| 0: [MethodCall] source(...)
# 6| 1: [LocalVariableDeclStmt] var ...;
# 6| 0: [TypeAccess] String
# 6| 1: [LocalVariableDeclExpr] indirectTaint
# 6| 0: [MethodCall] source(...)
# 8| 2: [LocalVariableDeclStmt] var ...;
# 8| 0: [TypeAccess] Object
# 8| 1: [LocalVariableDeclExpr] o
# 8| 0: [ConditionalExpr] ...?...:...
# 8| 0: [VarAccess] inp
# 8| 1: [VarAccess] directTaint
# 8| 2: [ClassInstanceExpr] new Outer(...)
# 8| -3: [TypeAccess] Outer
# 8| 0: [ClassInstanceExpr] new Inner(...)
# 8| -3: [TypeAccess] Inner
# 8| 0: [VarAccess] indirectTaint
# 8| 1: [StringLiteral] "not tainted"
# 8| 1: [StringLiteral] "not tainted 2"
# 10| 3: [IfStmt] if (...)
# 10| 0: [InstanceOfExpr] ...instanceof...
# 10| 0: [VarAccess] o
#-----| 2: (Single Local Variable Declaration)
# 10| 0: [TypeAccess] String
# 10| 1: [LocalVariableDeclExpr] s
# 10| 1: [BlockStmt] { ... }
# 11| 0: [ExprStmt] <Expr>;
# 11| 0: [MethodCall] sink(...)
# 11| 0: [VarAccess] s
# 14| 4: [IfStmt] if (...)
# 14| 0: [InstanceOfExpr] ...instanceof...
# 14| 0: [VarAccess] o
# 14| 2: [RecordPatternExpr] Outer(...)
# 14| 0: [RecordPatternExpr] Inner(...)
# 14| 0: [LocalVariableDeclExpr] tainted
# 14| 1: [LocalVariableDeclExpr] notTainted
# 14| 1: [LocalVariableDeclExpr] alsoNotTainted
# 14| 1: [BlockStmt] { ... }
# 15| 0: [ExprStmt] <Expr>;
# 15| 0: [MethodCall] sink(...)
# 15| 0: [VarAccess] tainted
# 16| 1: [ExprStmt] <Expr>;
# 16| 0: [MethodCall] sink(...)
# 16| 0: [VarAccess] notTainted
# 17| 2: [ExprStmt] <Expr>;
# 17| 0: [MethodCall] sink(...)
# 17| 0: [VarAccess] alsoNotTainted
# 22| 3: [Method] source
# 22| 3: [TypeAccess] String
# 22| 5: [BlockStmt] { ... }
# 22| 0: [ReturnStmt] return ...
# 22| 0: [StringLiteral] "tainted"
# 23| 4: [Method] sink
# 23| 3: [TypeAccess] void
#-----| 4: (Parameters)
# 23| 0: [Parameter] sunk
# 23| 0: [TypeAccess] String
# 23| 5: [BlockStmt] { ... }
# 27| 2: [Class] Outer
# 27| 7: [FieldDeclaration] Inner i;
# 27| 8: [FieldDeclaration] String otherField;
# 28| 3: [Class] Inner
# 28| 7: [FieldDeclaration] String taintedField;
# 28| 8: [FieldDeclaration] String nonTaintedField;

View File

@@ -0,0 +1 @@
semmle/code/java/PrintAst.ql

View File

@@ -0,0 +1,28 @@
public class Test {
public static void test(boolean inp) {
String directTaint = source();
String indirectTaint = source();
Object o = inp ? directTaint : new Outer(new Inner(indirectTaint, "not tainted"), "not tainted 2");
if (o instanceof String s) {
sink(s);
}
if (o instanceof Outer(Inner(String tainted, String notTainted), String alsoNotTainted)) {
sink(tainted);
sink(notTainted);
sink(alsoNotTainted);
}
}
public static String source() { return "tainted"; }
public static void sink(String sunk) { }
}
record Outer(Inner i, String otherField) { }
record Inner(String taintedField, String nonTaintedField) { }

View File

@@ -0,0 +1,72 @@
| Test.java:1:14:1:17 | super(...) | Test.java:1:14:1:17 | Test |
| Test.java:1:14:1:17 | { ... } | Test.java:1:14:1:17 | super(...) |
| Test.java:3:40:20:3 | { ... } | Test.java:5:5:5:34 | var ...; |
| Test.java:5:5:5:34 | var ...; | Test.java:5:26:5:33 | source(...) |
| Test.java:5:12:5:33 | directTaint | Test.java:6:5:6:36 | var ...; |
| Test.java:5:26:5:33 | source(...) | Test.java:5:12:5:33 | directTaint |
| Test.java:6:5:6:36 | var ...; | Test.java:6:28:6:35 | source(...) |
| Test.java:6:12:6:35 | indirectTaint | Test.java:8:5:8:103 | var ...; |
| Test.java:6:28:6:35 | source(...) | Test.java:6:12:6:35 | indirectTaint |
| Test.java:8:5:8:103 | var ...; | Test.java:8:16:8:102 | ...?...:... |
| Test.java:8:12:8:102 | o | Test.java:10:5:10:30 | if (...) |
| Test.java:8:16:8:18 | inp | Test.java:8:22:8:32 | directTaint |
| Test.java:8:16:8:18 | inp | Test.java:8:56:8:68 | indirectTaint |
| Test.java:8:16:8:102 | ...?...:... | Test.java:8:16:8:18 | inp |
| Test.java:8:22:8:32 | directTaint | Test.java:8:12:8:102 | o |
| Test.java:8:36:8:102 | new Outer(...) | Test.java:8:12:8:102 | o |
| Test.java:8:46:8:84 | new Inner(...) | Test.java:8:87:8:101 | "not tainted 2" |
| Test.java:8:56:8:68 | indirectTaint | Test.java:8:71:8:83 | "not tainted" |
| Test.java:8:71:8:83 | "not tainted" | Test.java:8:46:8:84 | new Inner(...) |
| Test.java:8:87:8:101 | "not tainted 2" | Test.java:8:36:8:102 | new Outer(...) |
| Test.java:10:5:10:30 | if (...) | Test.java:10:9:10:9 | o |
| Test.java:10:9:10:9 | o | Test.java:10:9:10:29 | ...instanceof... |
| Test.java:10:9:10:29 | ...instanceof... | Test.java:10:29:10:29 | s |
| Test.java:10:9:10:29 | ...instanceof... | Test.java:14:5:14:92 | if (...) |
| Test.java:10:29:10:29 | s | Test.java:10:32:12:5 | { ... } |
| Test.java:10:32:12:5 | { ... } | Test.java:11:7:11:14 | <Expr>; |
| Test.java:11:7:11:13 | sink(...) | Test.java:14:5:14:92 | if (...) |
| Test.java:11:7:11:14 | <Expr>; | Test.java:11:12:11:12 | s |
| Test.java:11:12:11:12 | s | Test.java:11:7:11:13 | sink(...) |
| Test.java:14:5:14:92 | if (...) | Test.java:14:9:14:9 | o |
| Test.java:14:9:14:9 | o | Test.java:14:9:14:91 | ...instanceof... |
| Test.java:14:9:14:91 | ...instanceof... | Test.java:3:22:3:25 | test |
| Test.java:14:9:14:91 | ...instanceof... | Test.java:14:41:14:47 | tainted |
| Test.java:14:22:14:91 | Outer(...) | Test.java:14:94:18:5 | { ... } |
| Test.java:14:28:14:67 | Inner(...) | Test.java:14:77:14:90 | alsoNotTainted |
| Test.java:14:41:14:47 | tainted | Test.java:14:57:14:66 | notTainted |
| Test.java:14:57:14:66 | notTainted | Test.java:14:28:14:67 | Inner(...) |
| Test.java:14:77:14:90 | alsoNotTainted | Test.java:14:22:14:91 | Outer(...) |
| Test.java:14:94:18:5 | { ... } | Test.java:15:7:15:20 | <Expr>; |
| Test.java:15:7:15:19 | sink(...) | Test.java:16:7:16:23 | <Expr>; |
| Test.java:15:7:15:20 | <Expr>; | Test.java:15:12:15:18 | tainted |
| Test.java:15:12:15:18 | tainted | Test.java:15:7:15:19 | sink(...) |
| Test.java:16:7:16:22 | sink(...) | Test.java:17:7:17:27 | <Expr>; |
| Test.java:16:7:16:23 | <Expr>; | Test.java:16:12:16:21 | notTainted |
| Test.java:16:12:16:21 | notTainted | Test.java:16:7:16:22 | sink(...) |
| Test.java:17:7:17:26 | sink(...) | Test.java:3:22:3:25 | test |
| Test.java:17:7:17:27 | <Expr>; | Test.java:17:12:17:25 | alsoNotTainted |
| Test.java:17:12:17:25 | alsoNotTainted | Test.java:17:7:17:26 | sink(...) |
| Test.java:22:33:22:53 | { ... } | Test.java:22:42:22:50 | "tainted" |
| Test.java:22:35:22:51 | return ... | Test.java:22:24:22:29 | source |
| Test.java:22:42:22:50 | "tainted" | Test.java:22:35:22:51 | return ... |
| Test.java:23:40:23:42 | { ... } | Test.java:23:22:23:25 | sink |
| Test.java:27:8:27:12 | ...=... | Test.java:27:8:27:12 | <Expr>; |
| Test.java:27:8:27:12 | ...=... | Test.java:27:8:27:12 | Outer |
| Test.java:27:8:27:12 | <Expr>; | Test.java:27:8:27:12 | this |
| Test.java:27:8:27:12 | <Expr>; | Test.java:27:8:27:12 | this |
| Test.java:27:8:27:12 | i | Test.java:27:8:27:12 | ...=... |
| Test.java:27:8:27:12 | otherField | Test.java:27:8:27:12 | ...=... |
| Test.java:27:8:27:12 | super(...) | Test.java:27:8:27:12 | <Expr>; |
| Test.java:27:8:27:12 | this | Test.java:27:8:27:12 | i |
| Test.java:27:8:27:12 | this | Test.java:27:8:27:12 | otherField |
| Test.java:27:8:27:12 | { ... } | Test.java:27:8:27:12 | super(...) |
| Test.java:28:8:28:12 | ...=... | Test.java:28:8:28:12 | <Expr>; |
| Test.java:28:8:28:12 | ...=... | Test.java:28:8:28:12 | Inner |
| Test.java:28:8:28:12 | <Expr>; | Test.java:28:8:28:12 | this |
| Test.java:28:8:28:12 | <Expr>; | Test.java:28:8:28:12 | this |
| Test.java:28:8:28:12 | nonTaintedField | Test.java:28:8:28:12 | ...=... |
| Test.java:28:8:28:12 | super(...) | Test.java:28:8:28:12 | <Expr>; |
| Test.java:28:8:28:12 | taintedField | Test.java:28:8:28:12 | ...=... |
| Test.java:28:8:28:12 | this | Test.java:28:8:28:12 | nonTaintedField |
| Test.java:28:8:28:12 | this | Test.java:28:8:28:12 | taintedField |
| Test.java:28:8:28:12 | { ... } | Test.java:28:8:28:12 | super(...) |

View File

@@ -0,0 +1,5 @@
import java
from ControlFlowNode cn
where cn.getFile().getBaseName() = "Test.java"
select cn, cn.getASuccessor()

View File

@@ -0,0 +1,2 @@
| Test.java:5:26:5:33 | source(...) | Test.java:11:12:11:12 | s |
| Test.java:6:28:6:35 | source(...) | Test.java:15:12:15:18 | tainted |

View File

@@ -0,0 +1,29 @@
import java
import semmle.code.java.controlflow.Guards
import semmle.code.java.dataflow.DataFlow
private predicate isSafe(Guard g, Expr checked, boolean branch) {
exists(MethodCall mc | g = mc |
mc.getMethod().hasName("isSafe") and
checked = mc.getAnArgument() and
branch = true
)
}
module TestConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() = any(MethodCall mc | mc.getMethod().getName() = "source") }
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(MethodCall mc | mc.getMethod().getName() = "sink").getAnArgument() }
predicate isBarrier(DataFlow::Node node) {
node = DataFlow::BarrierGuard<isSafe/3>::getABarrierNode()
}
}
module Flow = DataFlow::Global<TestConfig>;
from DataFlow::Node source, DataFlow::Node sink
where Flow::flow(source, sink)
select source, sink

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args --release 21