diff --git a/go/ql/lib/change-notes/2024-02-14-range-map-read.md b/go/ql/lib/change-notes/2024-02-14-range-map-read.md new file mode 100644 index 000000000000..ea45737a72ea --- /dev/null +++ b/go/ql/lib/change-notes/2024-02-14-range-map-read.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Fixed dataflow out of a `map` using a `range` statement. diff --git a/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll b/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll index ad985e2c5b5a..e6a21a06decb 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll @@ -41,11 +41,11 @@ predicate containerStoreStep(Node node1, Node node2, Content c) { or c instanceof MapKeyContent and node2.getType() instanceof MapType and - exists(Write w | w.writesElement(node2, node1, _)) + exists(Write w | w.writesElement(node2.(PostUpdateNode).getPreUpdateNode(), node1, _)) or c instanceof MapValueContent and node2.getType() instanceof MapType and - exists(Write w | w.writesElement(node2, _, node1)) + exists(Write w | w.writesElement(node2.(PostUpdateNode).getPreUpdateNode(), _, node1)) } /** @@ -57,11 +57,11 @@ predicate containerStoreStep(Node node1, Node node2, Content c) { predicate containerReadStep(Node node1, Node node2, Content c) { c instanceof ArrayContent and ( - node2.(Read).readsElement(node1, _) and - ( - node1.getType() instanceof ArrayType or - node1.getType() instanceof SliceType - ) + node1.getType() instanceof ArrayType or + node1.getType() instanceof SliceType + ) and + ( + node2.(Read).readsElement(node1, _) or node2.(RangeElementNode).getBase() = node1 or @@ -85,5 +85,5 @@ predicate containerReadStep(Node node1, Node node2, Content c) { or c instanceof MapValueContent and node1.getType() instanceof MapType and - node2.(Read).readsElement(node1, _) + (node2.(Read).readsElement(node1, _) or node2.(RangeElementNode).getBase() = node1) } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/Flows.expected b/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/Flows.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/Flows.ql new file mode 100644 index 000000000000..1b27b27d6dc2 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/Flows.ql @@ -0,0 +1,3 @@ +import go +import TestUtilities.InlineFlowTest +import DefaultFlowTest diff --git a/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/test.go b/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/test.go new file mode 100644 index 000000000000..b6dedf748b3d --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/MapReadsAndStores/test.go @@ -0,0 +1,25 @@ +package main + +func source() string { + return "untrusted data" +} + +func sink(any) { +} + +func main() { + var someMap map[string]string = map[string]string{} + someMap["someKey"] = source() + + for _, val := range someMap { + sink(val) // $ hasValueFlow="val" + } +} + +func testLiteral() { + someMap := map[string]string{"someKey": source()} + + for _, val := range someMap { + sink(val) // $ hasValueFlow="val" + } +}