From 4b830c18647dcddee02a19c308ca1e0592bfc050 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 4 Feb 2026 13:40:33 +0000 Subject: [PATCH] Test varargs flow with models-as-data --- .../VarArgsWithExternalFlow/Flows.expected | 2 + .../VarArgsWithExternalFlow/Flows.ext.yml | 21 +++++++ .../dataflow/VarArgsWithExternalFlow/Flows.ql | 22 ++++++++ .../dataflow/VarArgsWithExternalFlow/go.mod | 5 ++ .../dataflow/VarArgsWithExternalFlow/main.go | 56 +++++++++++++++++++ .../github.com/nonexistent/test/stub.go | 32 +++++++++++ .../vendor/modules.txt | 3 + 7 files changed, 141 insertions(+) create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.expected create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ext.yml create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ql create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/go.mod create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/main.go create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/github.com/nonexistent/test/stub.go create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/modules.txt diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.expected b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.expected new file mode 100644 index 00000000000..42831abaf15 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.expected @@ -0,0 +1,2 @@ +invalidModelRow +testFailures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ext.yml new file mode 100644 index 00000000000..ca3f9559536 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ext.yml @@ -0,0 +1,21 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: summaryModel + data: + - ["github.com/nonexistent/test", "", False, "FunctionWithParameter", "", "", "Argument[0]", "ReturnValue", "value", "manual"] + - ["github.com/nonexistent/test", "", False, "FunctionWithSliceParameter", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"] + - ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsParameter", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"] + - ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsOutParameter", "", "", "Argument[0]", "Argument[1].ArrayElement", "value", "manual"] + - ["github.com/nonexistent/test", "", False, "FunctionWithSliceOfStructsParameter", "", "", "Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field]", "ReturnValue", "value", "manual"] + - ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsOfStructsParameter", "", "", "Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field]", "ReturnValue", "value", "manual"] + - addsTo: + pack: codeql/go-all + extensible: sourceModel + data: + - ["github.com/nonexistent/test", "", False, "VariadicSource", "", "", "Argument[0]", "qltest", "manual"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["github.com/nonexistent/test", "", False, "VariadicSink", "", "", "Argument[0]", "qltest", "manual"] diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ql new file mode 100644 index 00000000000..873143a6f81 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/Flows.ql @@ -0,0 +1,22 @@ +import go +import semmle.go.dataflow.ExternalFlow +import ModelValidation +import utils.test.InlineFlowTest + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + sourceNode(source, "qltest") + or + exists(Function fn | fn.hasQualifiedName(_, ["source", "taint"]) | + source = fn.getACall().getResult() + ) + } + + predicate isSink(DataFlow::Node sink) { + sinkNode(sink, "qltest") + or + exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument()) + } +} + +import FlowTest diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/go.mod b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/go.mod new file mode 100644 index 00000000000..43614028d1b --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/go.mod @@ -0,0 +1,5 @@ +module semmle.go.Packages + +go 1.25 + +require github.com/nonexistent/test v0.0.0-20200203000000-0000000000000 diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/main.go b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/main.go new file mode 100644 index 00000000000..0a4fc6fa941 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "github.com/nonexistent/test" +) + +func source() string { + return "untrusted data" +} + +func sink(any) { +} + +func main() { + s := source() + sink(test.FunctionWithParameter(s)) // $ hasValueFlow="call to FunctionWithParameter" + + stringSlice := []string{source()} + sink(stringSlice[0]) // $ hasValueFlow="index expression" + + s0 := "" + s1 := source() + sSlice := []string{s0, s1} + sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter" + sink(test.FunctionWithSliceParameter(sSlice)) // $ hasValueFlow="call to FunctionWithSliceParameter" + sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ hasValueFlow="call to FunctionWithVarArgsParameter" + sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to FunctionWithVarArgsParameter" + + var out1 *string + var out2 *string + test.FunctionWithVarArgsOutParameter(source(), out1, out2) + sink(out1) // $ MISSING: hasValueFlow="out1" + sink(out2) // $ MISSING: hasValueFlow="out2" + + sliceOfStructs := []test.A{{Field: source()}} + sink(sliceOfStructs[0].Field) // $ hasValueFlow="selection of Field" + + a0 := test.A{Field: ""} + a1 := test.A{Field: source()} + aSlice := []test.A{a0, a1} + sink(test.FunctionWithSliceOfStructsParameter(aSlice)) // $ hasValueFlow="call to FunctionWithSliceOfStructsParameter" + sink(test.FunctionWithVarArgsOfStructsParameter(aSlice...)) // $ hasValueFlow="call to FunctionWithVarArgsOfStructsParameter" + sink(test.FunctionWithVarArgsOfStructsParameter(a0, a1)) // $ hasValueFlow="call to FunctionWithVarArgsOfStructsParameter" + + var variadicSource string + test.VariadicSource(&variadicSource) + sink(variadicSource) // $ MISSING: hasTaintFlow="variadicSource" + sink(&variadicSource) // $ MISSING: hasTaintFlow="&..." + + var variadicSourcePtr *string + test.VariadicSource(variadicSourcePtr) + sink(variadicSourcePtr) // $ MISSING: hasTaintFlow="variadicSourcePtr" + sink(*variadicSourcePtr) // $ MISSING: hasTaintFlow="star expression" + + test.VariadicSink(source()) // $ hasTaintFlow="[]type{args}" +} diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/github.com/nonexistent/test/stub.go b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/github.com/nonexistent/test/stub.go new file mode 100644 index 00000000000..4c38a21f6d0 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/github.com/nonexistent/test/stub.go @@ -0,0 +1,32 @@ +package test + +type A struct { + Field string +} + +func FunctionWithParameter(s string) string { + return "" +} + +func FunctionWithSliceParameter(s []string) string { + return "" +} + +func FunctionWithVarArgsParameter(s ...string) string { + return "" +} + +func FunctionWithVarArgsOutParameter(in string, out ...*string) { +} + +func FunctionWithSliceOfStructsParameter(s []A) string { + return "" +} + +func FunctionWithVarArgsOfStructsParameter(s ...A) string { + return "" +} + +func VariadicSource(s ...*string) {} + +func VariadicSink(s ...string) {} diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/modules.txt b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/modules.txt new file mode 100644 index 00000000000..b62dbf8819b --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithExternalFlow/vendor/modules.txt @@ -0,0 +1,3 @@ +# github.com/nonexistent/test v0.0.0-20200203000000-0000000000000 +## explicit +github.com/nonexistent/test