From 57d861337be688ec64d37b6bc3ac2b5b73c206fe Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 23 Aug 2022 11:16:23 +0200 Subject: [PATCH] Kotlin: Add dataflow tests for stdlib calls --- .../semmle/code/java/frameworks/generated.qll | 1 + .../frameworks/kotlin/StdLibGenerated.qll | 7 ++ .../library-tests/dataflow/summaries/list.kt | 14 ++-- .../dataflow/summaries/test.expected | 32 ++++++-- .../library-tests/dataflow/summaries/test.kt | 75 +++++++++++++++++++ .../library-tests/dataflow/summaries/test.ql | 19 +---- 6 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 java/ql/lib/semmle/code/java/frameworks/kotlin/StdLibGenerated.qll create mode 100644 java/ql/test/kotlin/library-tests/dataflow/summaries/test.kt diff --git a/java/ql/lib/semmle/code/java/frameworks/generated.qll b/java/ql/lib/semmle/code/java/frameworks/generated.qll index adf537e2c51..7a16e24890e 100644 --- a/java/ql/lib/semmle/code/java/frameworks/generated.qll +++ b/java/ql/lib/semmle/code/java/frameworks/generated.qll @@ -6,4 +6,5 @@ import java private module GeneratedFrameworks { private import apache.IOGenerated + private import kotlin.StdLibGenerated } diff --git a/java/ql/lib/semmle/code/java/frameworks/kotlin/StdLibGenerated.qll b/java/ql/lib/semmle/code/java/frameworks/kotlin/StdLibGenerated.qll new file mode 100644 index 00000000000..89dc1e764b0 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/kotlin/StdLibGenerated.qll @@ -0,0 +1,7 @@ +/** + * THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT. + * Definitions of taint steps in the StdLibGenerated framework. + */ + +import java +private import semmle.code.java.dataflow.ExternalFlow diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/list.kt b/java/ql/test/kotlin/library-tests/dataflow/summaries/list.kt index c15f000f668..31353295182 100644 --- a/java/ql/test/kotlin/library-tests/dataflow/summaries/list.kt +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/list.kt @@ -4,17 +4,17 @@ class ListFlowTest { fun test(l: MutableList) { l[0] = taint("a") - sink(l) - sink(l[0]) + sink(l) // $ hasTaintFlow=a + sink(l[0]) // $ hasValueFlow=a for (s in l) { - sink(s) + sink(s) // $ hasValueFlow=a } - val a = arrayOf(taint("a"), "b") - sink(a) - sink(a[0]) + val a = arrayOf(taint("b"), "c") + sink(a) // $ hasTaintFlow=b + sink(a[0]) // $ hasValueFlow=b for (s in a) { - sink(s) + sink(s) // $ hasValueFlow=b } } } diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected index e946708bee5..16a29b643b2 100644 --- a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected @@ -1,6 +1,26 @@ -| list.kt:6:23:6:23 | a | list.kt:7:14:7:14 | l | -| list.kt:6:23:6:23 | a | list.kt:8:14:8:17 | get(...) | -| list.kt:6:23:6:23 | a | list.kt:10:18:10:18 | s | -| list.kt:13:32:13:32 | a | list.kt:14:14:14:14 | a | -| list.kt:13:32:13:32 | a | list.kt:15:14:15:17 | ...[...] | -| list.kt:13:32:13:32 | a | list.kt:17:18:17:18 | s | +| test.kt:16:53:16:69 | // $ hasTaintFlow | Missing result:hasTaintFlow= | +| test.kt:17:53:17:69 | // $ hasTaintFlow | Missing result:hasTaintFlow= | +| test.kt:20:53:20:69 | // $ hasTaintFlow | Missing result:hasTaintFlow= | +| test.kt:21:53:21:69 | // $ hasTaintFlow | Missing result:hasTaintFlow= | +| test.kt:23:53:23:69 | // $ hasTaintFlow | Missing result:hasTaintFlow= | +| test.kt:26:53:26:71 | // $ hasTaintFlow=a | Missing result:hasTaintFlow=a | +| test.kt:27:53:27:71 | // $ hasTaintFlow=a | Missing result:hasTaintFlow=a | +| test.kt:30:57:30:75 | // $ hasTaintFlow=b | Missing result:hasTaintFlow=b | +| test.kt:31:57:31:75 | // $ hasTaintFlow=c | Missing result:hasTaintFlow=c | +| test.kt:34:53:34:71 | // $ hasTaintFlow=d | Missing result:hasTaintFlow=d | +| test.kt:36:53:36:71 | // $ hasTaintFlow=d | Missing result:hasTaintFlow=d | +| test.kt:39:53:39:71 | // $ hasTaintFlow=e | Missing result:hasTaintFlow=e | +| test.kt:40:53:40:71 | // $ hasTaintFlow=e | Missing result:hasTaintFlow=e | +| test.kt:44:53:44:71 | // $ hasTaintFlow=a | Missing result:hasTaintFlow=a | +| test.kt:45:53:45:71 | // $ hasTaintFlow=a | Missing result:hasTaintFlow=a | +| test.kt:47:53:47:71 | // $ hasTaintFlow=a | Missing result:hasTaintFlow=a | +| test.kt:51:53:51:71 | // $ hasTaintFlow=f | Missing result:hasTaintFlow=f | +| test.kt:52:53:52:71 | // $ hasTaintFlow=f | Missing result:hasTaintFlow=f | +| test.kt:56:53:56:71 | // $ hasTaintFlow=g | Missing result:hasTaintFlow=g | +| test.kt:57:53:57:71 | // $ hasTaintFlow=g | Missing result:hasTaintFlow=g | +| test.kt:61:53:61:71 | // $ hasTaintFlow=h | Missing result:hasTaintFlow=h | +| test.kt:63:53:63:71 | // $ hasTaintFlow=h | Missing result:hasTaintFlow=h | +| test.kt:66:53:66:71 | // $ hasTaintFlow=i | Missing result:hasTaintFlow=i | +| test.kt:67:53:67:71 | // $ hasTaintFlow=i | Missing result:hasTaintFlow=i | +| test.kt:68:53:68:71 | // $ hasTaintFlow=i | Missing result:hasTaintFlow=i | +| test.kt:71:53:71:71 | // $ hasTaintFlow=i | Missing result:hasTaintFlow=i | diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.kt b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.kt new file mode 100644 index 00000000000..6b41ab26557 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.kt @@ -0,0 +1,75 @@ +import kotlin.time.Duration +import kotlin.time.ExperimentalTime +import kotlin.time.TimedValue + +class Test { + fun taint(t: T) = t + fun sink(a: Any) {} + + @OptIn(ExperimentalTime::class) + fun test(b: ByteArray, + f: kotlin.io.FileTreeWalk, + c1: CharArray, + c2: CharArray, + c3: CharArray,) { + + sink(taint(b).copyOf()) // $ hasTaintFlow + sink(taint(f).maxDepth(1)) // $ hasTaintFlow + + val sb = StringBuilder() + sink(sb.insertRange(0, taint(c1), 0, 0)) // $ hasTaintFlow + sink(sb) // $ hasTaintFlow + + sink(taint(c2) + c3) // $ hasTaintFlow + + val p = Pair(taint("a"), "") + sink(p) // $ hasTaintFlow=a + sink(p.component1()) // $ hasTaintFlow=a + sink(p.second) + + sink(taint("b").capitalize()) // $ hasTaintFlow=b + sink(taint("c").replaceFirstChar { _ -> 'x' }) // $ hasTaintFlow=c + + val t = Triple("", taint("d"), "") + sink(t) // $ hasTaintFlow=d + sink(t.component1()) + sink(t.second) // $ hasTaintFlow=d + + val p1 = taint("e") to "" + sink(p1) // $ hasTaintFlow=e + sink(p1.component1()) // $ hasTaintFlow=e + sink(p1.second) + + val l = p.toList() + sink(l) // $ hasTaintFlow=a + sink(l[0]) // $ hasTaintFlow=a + for (s in l) { + sink(s) // $ hasTaintFlow=a + } + + val tv = TimedValue(taint("f"), Duration.parse("")) + sink(tv) // $ hasTaintFlow=f + sink(tv.component1()) // $ hasTaintFlow=f + sink(tv.duration) + + val mg0 = MatchGroup(taint("g"), IntRange(0, 10)) + sink(mg0) // $ hasTaintFlow=g + sink(mg0.value) // $ hasTaintFlow=g + sink(mg0.component2()) + + val iv = IndexedValue(5, taint("h")) + sink(iv) // $ hasTaintFlow=h + sink(iv.index) + sink(iv.component2()) // $ hasTaintFlow=h + + val strings = arrayOf("", taint("i")) + sink(strings.withIndex()) // $ hasTaintFlow=i + sink(strings.withIndex().toList()) // $ hasTaintFlow=i + sink(strings.withIndex().toList()[0].value) // $ hasTaintFlow=i + sink(strings.withIndex().toList()[0].index) + for (x in strings.withIndex()) { + sink(x.value) // $ hasTaintFlow=i + sink(x.index) + } + } +} \ No newline at end of file diff --git a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql index 086a6e80343..5d91e4e8e26 100644 --- a/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql +++ b/java/ql/test/kotlin/library-tests/dataflow/summaries/test.ql @@ -1,19 +1,2 @@ import java -import semmle.code.java.dataflow.TaintTracking -import semmle.code.java.dataflow.ExternalFlow - -class Conf extends TaintTracking::Configuration { - Conf() { this = "qltest:mad-summaries" } - - override predicate isSource(DataFlow::Node n) { - n.asExpr().(Argument).getCall().getCallee().hasName("taint") - } - - override predicate isSink(DataFlow::Node n) { - n.asExpr().(Argument).getCall().getCallee().hasName("sink") - } -} - -from DataFlow::Node src, DataFlow::Node sink, Conf conf -where conf.hasFlow(src, sink) -select src, sink +import TestUtilities.InlineFlowTest