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..21b5800bb017 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/ContainerFlow.qll @@ -89,45 +89,95 @@ class ContainerType extends RefType { } private predicate taintPreservingQualifierToMethod(Method m) { + // java.util.Map.Entry m.getDeclaringType() instanceof EntryType and - m.hasName("getValue") + m.hasName(["getValue", "setValue"]) or + // java.util.Iterable m.getDeclaringType() instanceof IterableType and - m.hasName("iterator") + m.hasName(["iterator", "spliterator"]) or + // java.util.Iterator m.getDeclaringType() instanceof IteratorType and m.hasName("next") or + // java.util.ListIterator + m.getDeclaringType() instanceof IteratorType and + m.hasName("previous") + or + // java.util.Enumeration m.getDeclaringType() instanceof EnumerationType and - m.hasName("nextElement") + m.hasName(["asIterator", "nextElement"]) or - m.(MapMethod).hasName("entrySet") + // java.util.Map + m + .(MapMethod) + .hasName(["computeIfAbsent", "entrySet", "get", "getOrDefault", "put", "putIfAbsent", + "remove", "replace", "values"]) or - m.(MapMethod).hasName("get") + // java.util.Collection + m.(CollectionMethod).hasName(["parallelStream", "stream", "toArray"]) or - m.(MapMethod).hasName("remove") + // java.util.List + m.(CollectionMethod).hasName(["get", "listIterator", "set", "subList"]) or - m.(MapMethod).hasName("values") + m.(CollectionMethod).hasName("remove") and m.getParameterType(0).(PrimitiveType).hasName("int") or - m.(CollectionMethod).hasName("toArray") + // java.util.Vector + m.(CollectionMethod).hasName(["elementAt", "elements", "firstElement", "lastElement"]) or - m.(CollectionMethod).hasName("get") + // java.util.Stack + m.(CollectionMethod).hasName(["peek", "pop"]) or - m.(CollectionMethod).hasName("remove") and m.getParameterType(0).(PrimitiveType).hasName("int") + // java.util.Queue + m.(CollectionMethod).hasName(["element", "poll"]) or m.(CollectionMethod).hasName("remove") and m.getNumberOfParameters() = 0 or - m.(CollectionMethod).hasName("subList") + // java.util.Deque + m + .(CollectionMethod) + .hasName(["getFirst", "getLast", "peekFirst", "peekLast", "pollFirst", "pollLast", + "removeFirst", "removeLast"]) + or + // java.util.concurrent.BlockingQueue + // covered by Queue: poll(long, TimeUnit) + m.(CollectionMethod).hasName("take") + or + // java.util.concurrent.BlockingDeque + // covered by Deque: pollFirst(long, TimeUnit), pollLast(long, TimeUnit) + m.(CollectionMethod).hasName(["takeFirst", "takeLast"]) or - m.(CollectionMethod).hasName("firstElement") + // java.util.SortedSet + m.(CollectionMethod).hasName(["first", "headSet", "last", "subSet", "tailSet"]) or - m.(CollectionMethod).hasName("lastElement") + // java.util.NavigableSet + // covered by Deque: pollFirst(), pollLast() + // covered by SortedSet: headSet(E, boolean), subSet(E, boolean, E, boolean) and tailSet(E, boolean) + m + .(CollectionMethod) + .hasName(["ceiling", "descendingIterator", "descendingSet", "floor", "higher", "lower"]) or - m.(CollectionMethod).hasName("poll") + // java.util.SortedMap + m.(MapMethod).hasName(["headMap", "subMap", "tailMap"]) or - m.(CollectionMethod).hasName("peek") + // java.util.NavigableMap + // covered by SortedMap: headMap(K, boolean), subMap(K, boolean, K, boolean), tailMap(K, boolean) + m + .(MapMethod) + .hasName(["ceilingEntry", "descendingMap", "firstEntry", "floorEntry", "higherEntry", + "lastEntry", "lowerEntry", "pollFirstEntry", "pollLastEntry"]) or - m.(CollectionMethod).hasName("element") + // java.util.Dictionary + m + .getDeclaringType() + .getSourceDeclaration() + .getASourceSupertype*() + .hasQualifiedName("java.util", "Dictionary") and + m.hasName(["elements", "get", "put", "remove"]) + or + // java.util.concurrent.ConcurrentHashMap + m.(MapMethod).hasName(["elements", "search", "searchEntries", "searchValues"]) } private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { @@ -135,28 +185,83 @@ private predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) { tracked = sink.getQualifier() } -private predicate qualifierToArgumentStep(Expr tracked, RValue sink) { - exists(MethodAccess ma | - ma.getMethod().(CollectionMethod).hasName("toArray") and +private predicate qualifierToArgumentStep(Expr tracked, Expr sink) { + exists(MethodAccess ma, CollectionMethod method | + method = ma.getMethod() and + ( + // java.util.Vector + method.hasName("copyInto") + or + // java.util.concurrent.BlockingQueue + method.hasName("drainTo") + or + // java.util.Collection + method.hasName("toArray") and method.getParameter(0).getType() instanceof Array + ) and tracked = ma.getQualifier() and - sink = ma.getArgument(1) + sink = ma.getArgument(0) ) } private predicate taintPreservingArgumentToQualifier(Method method, int arg) { - method.(MapMethod).hasName("put") and arg = 1 + // java.util.Map.Entry + method.getDeclaringType() instanceof EntryType and + method.hasName("setValue") and + arg = 0 or - method.(MapMethod).hasName("putAll") and arg = 0 + // java.util.Map + method.(MapMethod).hasName(["merge", "put", "putIfAbsent"]) and arg = 1 or - method.(CollectionMethod).hasName("add") and arg = method.getNumberOfParameters() - 1 + method.(MapMethod).hasName("replace") and arg = method.getNumberOfParameters() - 1 or - method.(CollectionMethod).hasName("addAll") and arg = method.getNumberOfParameters() - 1 + method.(MapMethod).hasName("putAll") and arg = 0 + or + // java.util.ListIterator + method.getDeclaringType() instanceof IteratorType and + method.hasName(["add", "set"]) and + arg = 0 or - method.(CollectionMethod).hasName("addElement") and arg = 0 + // java.util.Collection + method.(CollectionMethod).hasName(["add", "addAll"]) and + // Refer to the last parameter to also cover List::add(int, E) and List::addAll(int, Collection) + arg = method.getNumberOfParameters() - 1 or + // java.util.List + // covered by Collection: add(int, E), addAll(int, Collection) method.(CollectionMethod).hasName("set") and arg = 1 or + // java.util.Vector + method.(CollectionMethod).hasName(["addElement", "insertElementAt", "setElementAt"]) and arg = 0 + or + // java.util.Stack + method.(CollectionMethod).hasName("push") and arg = 0 + or + // java.util.Queue method.(CollectionMethod).hasName("offer") and arg = 0 + or + // java.util.Deque + // covered by Stack: push(E) + method.(CollectionMethod).hasName(["addFirst", "addLast", "offerFirst", "offerLast"]) and arg = 0 + or + // java.util.concurrent.BlockingQueue + // covered by Queue: offer(E, long, TimeUnit) + method.(CollectionMethod).hasName("put") and arg = 0 + or + // java.util.concurrent.TransferQueue + method.(CollectionMethod).hasName(["transfer", "tryTransfer"]) and arg = 0 + or + // java.util.concurrent.BlockingDeque + // covered by Deque: offerFirst(E, long, TimeUnit), offerLast(E, long, TimeUnit) + method.(CollectionMethod).hasName(["putFirst", "putLast"]) and arg = 0 + or + //java.util.Dictionary + method + .getDeclaringType() + .getSourceDeclaration() + .getASourceSupertype*() + .hasQualifiedName("java.util", "Dictionary") and + method.hasName("put") and + arg = 1 } /** @@ -164,6 +269,9 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) { * `arg`th argument is tainted. */ private predicate taintPreservingArgumentToMethod(Method method, int arg) { + // java.util.Stack + method.(CollectionMethod).hasName("push") and arg = 0 + or method.getDeclaringType().hasQualifiedName("java.util", "Collections") and ( method diff --git a/java/ql/test/library-tests/dataflow/collections/ContainterTest.java b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java new file mode 100644 index 000000000000..ab9b699be9bd --- /dev/null +++ b/java/ql/test/library-tests/dataflow/collections/ContainterTest.java @@ -0,0 +1,228 @@ + +import java.util.Collection; +import java.util.List; +import java.util.Vector; +import java.util.Stack; +import java.util.Queue; +import java.util.Deque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TransferQueue; +import java.util.concurrent.BlockingDeque; +import java.util.SortedSet; +import java.util.NavigableSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.NavigableMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.Dictionary; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Enumeration; + +class ContainerTest { + + private static T sink(T object) { return object; } + private static T mkSink(Class cls) { return null; } + private static T source(T object) { return object; } + + public static void taintSteps( + Iterable iterable, + Collection collection, + List list, + Vector vector, + Stack stack, + Queue queue, + Deque deque, + BlockingQueue blockQueue, + BlockingDeque blockDeque, + TransferQueue transferQ, + SortedSet sortedSet, + NavigableSet navSet, + Map map, + Map.Entry entry, + SortedMap sortedMap, + NavigableMap navMap, + ConcurrentHashMap syncHashMap, + Dictionary dict, + Iterator iter, + ListIterator listIter, + Enumeration enumeration + ) throws InterruptedException { + // java.util.Iterable + sink(iterable.iterator()); + sink(iterable.spliterator()); + + // java.util.Collection + sink(collection.parallelStream()); + sink(collection.stream()); + sink(collection.toArray()); + sink(collection.toArray(x -> new String[x])); + sink(collection.toArray(new String[5])); + collection.toArray(mkSink(String[].class)); + mkSink(Collection.class).add(source("value")); + mkSink(Collection.class).addAll(collection); + + // java.util.List + sink(list.get(1)); + sink(list.listIterator()); + sink(list.listIterator(2)); + sink(list.remove(3)); + sink(list.set(4, "value")); + sink(list.subList(5, 6)); + mkSink(List.class).add(7, source("value")); + mkSink(List.class).addAll(8, collection); + mkSink(List.class).set(9, source("value")); + + // java.util.Vector + sink(vector.elementAt(7)); + sink(vector.elements()); + sink(vector.firstElement()); + sink(vector.lastElement()); + mkSink(Vector.class).addElement(source("element")); + mkSink(Vector.class).insertElementAt(source("element"), 1); + mkSink(Vector.class).setElementAt(source("element"), 2); + vector.copyInto(mkSink(String[].class)); + + // java.util.Stack + sink(stack.peek()); + sink(stack.pop()); + sink(stack.push("value")); // not tainted + sink(new Stack().push(source("value"))); + mkSink(Stack.class).push(source("value")); + + // java.util.Queue + sink(queue.element()); + sink(queue.peek()); + sink(queue.poll()); + sink(queue.remove()); + mkSink(Queue.class).offer(source("element")); + + // java.util.Deque + sink(deque.getFirst()); + sink(deque.getLast()); + sink(deque.peekFirst()); + sink(deque.peekLast()); + sink(deque.pollFirst()); + sink(deque.pollLast()); + sink(deque.removeFirst()); + sink(deque.removeLast()); + mkSink(Deque.class).addFirst(source("value")); + mkSink(Deque.class).addLast(source("value")); + mkSink(Deque.class).offerFirst(source("value")); + mkSink(Deque.class).offerLast(source("value")); + mkSink(Deque.class).push(source("value")); + + // java.util.concurrent.BlockingQueue + sink(blockQueue.poll(10, TimeUnit.SECONDS)); + sink(blockQueue.take()); + blockQueue.drainTo(mkSink(Collection.class)); + blockQueue.drainTo(mkSink(Collection.class), 4); + + // java.util.concurrent.TransferQueue + mkSink(TransferQueue.class).transfer(source("value")); + mkSink(TransferQueue.class).tryTransfer(source("value")); + mkSink(TransferQueue.class).tryTransfer(source("value"), 9, TimeUnit.SECONDS); + + // java.util.concurrent.BlockingDeque + sink(blockDeque.pollFirst(11, TimeUnit.SECONDS)); + sink(blockDeque.pollLast(12, TimeUnit.SECONDS)); + sink(blockDeque.takeFirst()); + sink(blockDeque.takeLast()); + mkSink(BlockingDeque.class).offer(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).put(source("value")); + mkSink(BlockingDeque.class).offerFirst(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).offerLast(source("value"), 10, TimeUnit.SECONDS); + mkSink(BlockingDeque.class).putFirst(source("value")); + mkSink(BlockingDeque.class).putLast(source("value")); + + // java.util.SortedSet + sink(sortedSet.first()); + sink(sortedSet.headSet("a")); + sink(sortedSet.last()); + sink(sortedSet.subSet("b", "c")); + sink(sortedSet.tailSet("d")); + + // java.util.NavigableSet + sink(navSet.ceiling("e")); + sink(navSet.descendingIterator()); + sink(navSet.descendingSet()); + sink(navSet.floor("f")); + sink(navSet.headSet("g", true)); + sink(navSet.higher("h")); + sink(navSet.lower("i")); + sink(navSet.pollFirst()); + sink(navSet.pollLast()); + sink(navSet.subSet("j", true, "k", false)); + sink(navSet.tailSet("l", true)); + + // java.util.Map + sink(map.computeIfAbsent("key", key -> "result")); + sink(map.entrySet()); + sink(map.get("key")); + sink(map.getOrDefault("key", "default")); + sink(map.merge("key", "value", (x, y) -> x + y)); + sink(map.put("key", "value")); + sink(map.putIfAbsent("key", "value")); + sink(map.remove("object")); + sink(map.replace("key", "value")); + sink(map.values()); + mkSink(Map.class).merge("key", source("v"), (x,y) -> "" + x + y); + mkSink(Map.class).put("key", source("v")); + mkSink(Map.class).putAll(map); + mkSink(Map.class).putIfAbsent("key", source("v")); + mkSink(Map.class).replace("key", source("v")); + mkSink(Map.class).replace("key", "old", source("v")); + mkSink(Map.class).replace("key", source("old"), "v"); // not tainted + + // java.util.Map.Entry + sink(entry.getValue()); + sink(entry.setValue("value")); + mkSink(Map.Entry.class).setValue(source("value")); + // java.util.SortedMap + sink(sortedMap.headMap("key")); + sink(sortedMap.subMap("key1", "key2")); + sink(sortedMap.tailMap("key")); + + // java.util.NavigableMap + sink(navMap.ceilingEntry("key")); + sink(navMap.descendingMap()); + sink(navMap.firstEntry()); + sink(navMap.floorEntry("key")); + sink(navMap.headMap("key", true)); + sink(navMap.higherEntry("key")); + sink(navMap.lastEntry()); + sink(navMap.lowerEntry("key")); + sink(navMap.pollFirstEntry()); + sink(navMap.pollLastEntry()); + sink(navMap.subMap("key1", true, "key2", true)); + sink(navMap.tailMap("key", true)); + + // java.util.concurrent.ConcurrentHashMap + sink(syncHashMap.elements()); + sink(syncHashMap.search(10, (k, v) -> v)); + sink(syncHashMap.searchEntries(11, e -> e.getValue())); + sink(syncHashMap.searchValues(12, v -> v)); + + // java.util.Dictionary + sink(dict.elements()); + sink(dict.get("object")); + sink(dict.put("key", "value")); + sink(dict.remove("object")); + mkSink(Dictionary.class).put("key", source("value")); + + // java.util.Iterator + sink(iter.next()); + + // java.util.ListIterator + sink(listIter.previous()); + mkSink(ListIterator.class).add(source("value")); + mkSink(ListIterator.class).set(source("value")); + + // java.util.Enumeration + sink(enumeration.asIterator()); + sink(enumeration.nextElement()); + } +} + diff --git a/java/ql/test/library-tests/dataflow/collections/flow.expected b/java/ql/test/library-tests/dataflow/collections/flow.expected index e2ccd7702b37..d54e99218563 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.expected +++ b/java/ql/test/library-tests/dataflow/collections/flow.expected @@ -1,3 +1,133 @@ +| ContainterTest.java:31:4:31:28 | iterable | ContainterTest.java:54:8:54:26 | iterator(...) | +| ContainterTest.java:31:4:31:28 | iterable | ContainterTest.java:55:8:55:29 | spliterator(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:58:8:58:34 | parallelStream(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:59:8:59:26 | stream(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:60:8:60:27 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:61:8:61:45 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:62:8:62:40 | toArray(...) | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:63:22:63:43 | mkSink(...) [post update] | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:65:3:65:26 | mkSink(...) [post update] | +| ContainterTest.java:32:4:32:32 | collection | ContainterTest.java:75:3:75:20 | mkSink(...) [post update] | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:68:8:68:18 | get(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:69:8:69:26 | listIterator(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:70:8:70:27 | listIterator(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:71:8:71:21 | remove(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:72:8:72:27 | set(...) | +| ContainterTest.java:33:4:33:20 | list | ContainterTest.java:73:8:73:25 | subList(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:79:8:79:26 | elementAt(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:80:8:80:24 | elements(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:81:8:81:28 | firstElement(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:82:8:82:27 | lastElement(...) | +| ContainterTest.java:34:4:34:24 | vector | ContainterTest.java:86:19:86:40 | mkSink(...) [post update] | +| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:89:8:89:19 | peek(...) | +| ContainterTest.java:35:4:35:22 | stack | ContainterTest.java:90:8:90:18 | pop(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:96:8:96:22 | element(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:97:8:97:19 | peek(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:98:8:98:19 | poll(...) | +| ContainterTest.java:36:4:36:22 | queue | ContainterTest.java:99:8:99:21 | remove(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:103:8:103:23 | getFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:104:8:104:22 | getLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:105:8:105:24 | peekFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:106:8:106:23 | peekLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:107:8:107:24 | pollFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:108:8:108:23 | pollLast(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:109:8:109:26 | removeFirst(...) | +| ContainterTest.java:37:4:37:22 | deque | ContainterTest.java:110:8:110:25 | removeLast(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:118:8:118:44 | poll(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:119:8:119:24 | take(...) | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:120:22:120:45 | mkSink(...) [post update] | +| ContainterTest.java:38:4:38:35 | blockQueue | ContainterTest.java:121:22:121:45 | mkSink(...) [post update] | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:129:8:129:49 | pollFirst(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:130:8:130:48 | pollLast(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:131:8:131:29 | takeFirst(...) | +| ContainterTest.java:39:4:39:35 | blockDeque | ContainterTest.java:132:8:132:28 | takeLast(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:141:8:141:24 | first(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:142:8:142:29 | headSet(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:143:8:143:23 | last(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:144:8:144:33 | subSet(...) | +| ContainterTest.java:41:4:41:30 | sortedSet | ContainterTest.java:145:8:145:29 | tailSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:148:8:148:26 | ceiling(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:149:8:149:34 | descendingIterator(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:150:8:150:29 | descendingSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:151:8:151:24 | floor(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:152:8:152:32 | headSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:153:8:153:25 | higher(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:154:8:154:24 | lower(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:155:8:155:25 | pollFirst(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:156:8:156:24 | pollLast(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:157:8:157:43 | subSet(...) | +| ContainterTest.java:42:4:42:30 | navSet | ContainterTest.java:158:8:158:32 | tailSet(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:161:8:161:50 | computeIfAbsent(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:162:8:162:21 | entrySet(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:163:8:163:21 | get(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:164:8:164:41 | getOrDefault(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:166:8:166:30 | put(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:167:8:167:38 | putIfAbsent(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:168:8:168:27 | remove(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:169:8:169:34 | replace(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:170:8:170:19 | values(...) | +| ContainterTest.java:43:4:43:26 | map | ContainterTest.java:173:3:173:19 | mkSink(...) [post update] | +| ContainterTest.java:44:4:44:34 | entry | ContainterTest.java:180:8:180:23 | getValue(...) | +| ContainterTest.java:44:4:44:34 | entry | ContainterTest.java:181:8:181:30 | setValue(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:184:8:184:31 | headMap(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:185:8:185:39 | subMap(...) | +| ContainterTest.java:45:4:45:38 | sortedMap | ContainterTest.java:186:8:186:31 | tailMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:189:8:189:33 | ceilingEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:190:8:190:29 | descendingMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:191:8:191:26 | firstEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:192:8:192:31 | floorEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:193:8:193:34 | headMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:194:8:194:32 | higherEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:195:8:195:25 | lastEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:196:8:196:31 | lowerEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:197:8:197:30 | pollFirstEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:198:8:198:29 | pollLastEntry(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:199:8:199:48 | subMap(...) | +| ContainterTest.java:46:4:46:38 | navMap | ContainterTest.java:200:8:200:34 | tailMap(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:203:8:203:29 | elements(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:204:8:204:42 | search(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:205:8:205:55 | searchEntries(...) | +| ContainterTest.java:47:4:47:48 | syncHashMap | ContainterTest.java:206:8:206:43 | searchValues(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:209:8:209:22 | elements(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:210:8:210:25 | get(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:211:8:211:31 | put(...) | +| ContainterTest.java:48:4:48:34 | dict | ContainterTest.java:212:8:212:28 | remove(...) | +| ContainterTest.java:49:4:49:24 | iter | ContainterTest.java:216:8:216:18 | next(...) | +| ContainterTest.java:50:4:50:32 | listIter | ContainterTest.java:219:8:219:26 | previous(...) | +| ContainterTest.java:51:4:51:34 | enumeration | ContainterTest.java:224:8:224:31 | asIterator(...) | +| ContainterTest.java:51:4:51:34 | enumeration | ContainterTest.java:225:8:225:32 | nextElement(...) | +| ContainterTest.java:64:39:64:45 | "value" | ContainterTest.java:64:3:64:26 | mkSink(...) [post update] | +| ContainterTest.java:74:36:74:42 | "value" | ContainterTest.java:74:3:74:20 | mkSink(...) [post update] | +| ContainterTest.java:76:36:76:42 | "value" | ContainterTest.java:76:3:76:20 | mkSink(...) [post update] | +| ContainterTest.java:83:42:83:50 | "element" | ContainterTest.java:83:3:83:22 | mkSink(...) [post update] | +| ContainterTest.java:84:47:84:55 | "element" | ContainterTest.java:84:3:84:22 | mkSink(...) [post update] | +| ContainterTest.java:85:44:85:52 | "element" | ContainterTest.java:85:3:85:22 | mkSink(...) [post update] | +| ContainterTest.java:92:32:92:38 | "value" | ContainterTest.java:92:8:92:40 | push(...) | +| ContainterTest.java:93:35:93:41 | "value" | ContainterTest.java:93:3:93:21 | mkSink(...) [post update] | +| ContainterTest.java:100:36:100:44 | "element" | ContainterTest.java:100:3:100:21 | mkSink(...) [post update] | +| ContainterTest.java:111:39:111:45 | "value" | ContainterTest.java:111:3:111:21 | mkSink(...) [post update] | +| ContainterTest.java:112:38:112:44 | "value" | ContainterTest.java:112:3:112:21 | mkSink(...) [post update] | +| ContainterTest.java:113:41:113:47 | "value" | ContainterTest.java:113:3:113:21 | mkSink(...) [post update] | +| ContainterTest.java:114:40:114:46 | "value" | ContainterTest.java:114:3:114:21 | mkSink(...) [post update] | +| ContainterTest.java:115:35:115:41 | "value" | ContainterTest.java:115:3:115:21 | mkSink(...) [post update] | +| ContainterTest.java:124:47:124:53 | "value" | ContainterTest.java:124:3:124:29 | mkSink(...) [post update] | +| ContainterTest.java:125:50:125:56 | "value" | ContainterTest.java:125:3:125:29 | mkSink(...) [post update] | +| ContainterTest.java:126:50:126:56 | "value" | ContainterTest.java:126:3:126:29 | mkSink(...) [post update] | +| ContainterTest.java:133:44:133:50 | "value" | ContainterTest.java:133:3:133:29 | mkSink(...) [post update] | +| ContainterTest.java:134:42:134:48 | "value" | ContainterTest.java:134:3:134:29 | mkSink(...) [post update] | +| ContainterTest.java:135:49:135:55 | "value" | ContainterTest.java:135:3:135:29 | mkSink(...) [post update] | +| ContainterTest.java:136:48:136:54 | "value" | ContainterTest.java:136:3:136:29 | mkSink(...) [post update] | +| ContainterTest.java:137:47:137:53 | "value" | ContainterTest.java:137:3:137:29 | mkSink(...) [post update] | +| ContainterTest.java:138:46:138:52 | "value" | ContainterTest.java:138:3:138:29 | mkSink(...) [post update] | +| ContainterTest.java:171:41:171:43 | "v" | ContainterTest.java:171:3:171:19 | mkSink(...) [post update] | +| ContainterTest.java:172:39:172:41 | "v" | ContainterTest.java:172:3:172:19 | mkSink(...) [post update] | +| ContainterTest.java:174:47:174:49 | "v" | ContainterTest.java:174:3:174:19 | mkSink(...) [post update] | +| ContainterTest.java:175:43:175:45 | "v" | ContainterTest.java:175:3:175:19 | mkSink(...) [post update] | +| ContainterTest.java:176:50:176:52 | "v" | ContainterTest.java:176:3:176:19 | mkSink(...) [post update] | +| ContainterTest.java:182:43:182:49 | "value" | ContainterTest.java:182:3:182:25 | mkSink(...) [post update] | +| ContainterTest.java:213:46:213:52 | "value" | ContainterTest.java:213:3:213:26 | mkSink(...) [post update] | +| ContainterTest.java:220:41:220:47 | "value" | ContainterTest.java:220:3:220:28 | mkSink(...) [post update] | +| ContainterTest.java:221:41:221:47 | "value" | ContainterTest.java:221:3:221:28 | mkSink(...) [post update] | | Test.java:13:18:13:24 | tainted | Test.java:15:10:15:11 | x2 | | Test.java:13:18:13:24 | tainted | Test.java:18:10:18:11 | x3 | | Test.java:13:18:13:24 | tainted | Test.java:22:12:22:13 | x4 | diff --git a/java/ql/test/library-tests/dataflow/collections/flow.ql b/java/ql/test/library-tests/dataflow/collections/flow.ql index dab06a3d9662..e485725250dc 100644 --- a/java/ql/test/library-tests/dataflow/collections/flow.ql +++ b/java/ql/test/library-tests/dataflow/collections/flow.ql @@ -5,13 +5,22 @@ class Conf extends TaintTracking::Configuration { Conf() { this = "conf" } override predicate isSource(DataFlow::Node src) { - src.asExpr().(VarAccess).getVariable().hasName("tainted") + ( + src.asExpr().(VarAccess).getVariable().hasName("tainted") + or + src.asParameter().getCallable().hasName("taintSteps") + or + src.asExpr() = any(MethodAccess ma | ma.getMethod().hasName("source")).getAnArgument() + ) } override predicate isSink(DataFlow::Node sink) { exists(MethodAccess ma | sink.asExpr() = ma.getAnArgument() and ma.getMethod().hasName("sink") + or + sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = ma and + ma.getMethod().hasName("mkSink") ) } }