diff --git a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll index 5a631a2fdff3..8e2305faeb4d 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -180,6 +180,12 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) { or method.hasName(["nCopies", "singletonMap"]) and arg = 1 ) + or + method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + ( + method.hasName(["copyOf", "copyOfRange", "spliterator", "stream"]) and + arg = 0 + ) } /** @@ -195,6 +201,13 @@ private predicate taintPreservingArgToArg(Method method, int input, int output) or method.hasName("replaceAll") and input = 2 and output = 0 ) + or + method.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + ( + method.hasName("fill") and + output = 0 and + input = method.getNumberOfParameters() - 1 + ) } private predicate argToQualifierStep(Expr tracked, Expr sink) { @@ -208,10 +221,18 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) { /** Access to a method that passes taint from an argument. */ private predicate argToMethodStep(Expr tracked, MethodAccess sink) { - exists(Method m, int i | + exists(Method m | m = sink.getMethod() and - taintPreservingArgumentToMethod(m, i) and - tracked = sink.getArgument(i) + ( + exists(int i | + taintPreservingArgumentToMethod(m, i) and + tracked = sink.getArgument(i) + ) + or + m.getDeclaringType().hasQualifiedName("java.util", "Arrays") and + m.hasName("asList") and + tracked = sink.getAnArgument() + ) ) } diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java b/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java new file mode 100644 index 000000000000..f016cb63fd3d --- /dev/null +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/ArraysTest.java @@ -0,0 +1,23 @@ +import java.util.Arrays; +import java.util.List; + +class ArraysTest { + public static void taintSteps(String[] source) { + Arrays.asList(); + Arrays.asList("one"); + Arrays.asList("two", "three"); + Arrays.copyOf(source, 10); + Arrays.copyOfRange(source, 0, 10); + Arrays.deepToString(source); + Arrays.spliterator(source); + Arrays.stream(source); + Arrays.toString(source); + Arrays.fill(source, "value"); + Arrays.fill(source, 0, 10, "data"); + Arrays.parallelPrefix(source, (x, y) -> x + y); + Arrays.parallelPrefix(source, 0, 10, (x, y) -> x + y); + Arrays.parallelSetAll(source, x -> Integer.toString(x)); + Arrays.setAll(source, x -> Integer.toString(x)); + } +} + diff --git a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected index 43e179695152..4de5be40177b 100644 --- a/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected +++ b/java/ql/test/library-tests/dataflow/local-additional-taint/localAdditionalTaintStep.expected @@ -1,3 +1,23 @@ +| ArraysTest.java:7:17:7:21 | "one" | ArraysTest.java:7:3:7:22 | asList(...) | +| ArraysTest.java:7:17:7:21 | "one" | ArraysTest.java:7:3:7:22 | new ..[] { .. } | +| ArraysTest.java:8:17:8:21 | "two" | ArraysTest.java:8:3:8:31 | asList(...) | +| ArraysTest.java:8:17:8:21 | "two" | ArraysTest.java:8:3:8:31 | new ..[] { .. } | +| ArraysTest.java:8:24:8:30 | "three" | ArraysTest.java:8:3:8:31 | asList(...) | +| ArraysTest.java:8:24:8:30 | "three" | ArraysTest.java:8:3:8:31 | new ..[] { .. } | +| ArraysTest.java:9:17:9:22 | source | ArraysTest.java:9:3:9:27 | copyOf(...) | +| ArraysTest.java:10:22:10:27 | source | ArraysTest.java:10:3:10:35 | copyOfRange(...) | +| ArraysTest.java:12:22:12:27 | source | ArraysTest.java:12:3:12:28 | spliterator(...) | +| ArraysTest.java:13:17:13:22 | source | ArraysTest.java:13:3:13:23 | stream(...) | +| ArraysTest.java:15:23:15:29 | "value" | ArraysTest.java:15:15:15:20 | source [post update] | +| ArraysTest.java:16:30:16:35 | "data" | ArraysTest.java:16:15:16:20 | source [post update] | +| ArraysTest.java:17:43:17:43 | x | ArraysTest.java:17:43:17:47 | ... + ... | +| ArraysTest.java:17:47:17:47 | y | ArraysTest.java:17:43:17:47 | ... + ... | +| ArraysTest.java:18:50:18:50 | x | ArraysTest.java:18:50:18:54 | ... + ... | +| ArraysTest.java:18:54:18:54 | y | ArraysTest.java:18:50:18:54 | ... + ... | +| ArraysTest.java:19:38:19:44 | Integer | ArraysTest.java:19:38:19:56 | toString(...) | +| ArraysTest.java:19:55:19:55 | x | ArraysTest.java:19:38:19:56 | toString(...) | +| ArraysTest.java:20:30:20:36 | Integer | ArraysTest.java:20:30:20:48 | toString(...) | +| ArraysTest.java:20:47:20:47 | x | ArraysTest.java:20:30:20:48 | toString(...) | | CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:3:8:33 | new ..[] { .. } | | CollectionsTest.java:8:28:8:32 | "one" | CollectionsTest.java:8:22:8:25 | list [post update] | | CollectionsTest.java:9:28:9:32 | "two" | CollectionsTest.java:9:3:9:42 | new ..[] { .. } |