Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import utils.test.InlineFlowTest

module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { sourceNode(src, "qltest") }
predicate isSource(DataFlow::Node source) { sourceNode(source, "qltest") }

predicate isSink(DataFlow::Node src) { sinkNode(src, "qltest") }
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "qltest") }
}

import ValueFlowTest<Config>
12 changes: 11 additions & 1 deletion go/ql/test/library-tests/semmle/go/dataflow/VarArgs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ func source() string {
return "untrusted data"
}

func sink(string) {
func sink(any) {
}

type A struct {
Expand All @@ -19,6 +19,10 @@ func functionWithVarArgsParameter(s ...string) string {
return s[1]
}

func functionWithVarArgsOutParameter(in string, out ...*string) {
*out[0] = in
}

func functionWithSliceOfStructsParameter(s []A) string {
return s[1].f
}
Expand All @@ -38,6 +42,12 @@ func main() {
sink(functionWithVarArgsParameter(sSlice...)) // $ hasValueFlow="call to functionWithVarArgsParameter"
sink(functionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to functionWithVarArgsParameter"

var out1 *string
var out2 *string
functionWithVarArgsOutParameter(source(), out1, out2)
sink(out1) // $ MISSING: hasValueFlow="out1"
sink(out2) // $ MISSING: hasValueFlow="out2"

sliceOfStructs := []A{{f: source()}}
sink(sliceOfStructs[0].f) // $ hasValueFlow="selection of f"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
invalidModelRow
testFailures
Original file line number Diff line number Diff line change
@@ -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"]
Original file line number Diff line number Diff line change
@@ -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<Config, Config>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module semmle.go.Packages

go 1.25

require github.com/nonexistent/test v0.0.0-20200203000000-0000000000000
Original file line number Diff line number Diff line change
@@ -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}"
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# github.com/nonexistent/test v0.0.0-20200203000000-0000000000000
## explicit
github.com/nonexistent/test
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class SummaryModelTest extends DataFlow::FunctionModel {
this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithVarArgsParameter") and
(inp.isParameter(_) and outp.isResult())
or
this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithVarArgsOutParameter") and
(inp.isParameter(0) and outp.isParameter(any(int i | i >= 1)))
or
this.hasQualifiedName("github.com/nonexistent/test", "FunctionWithSliceOfStructsParameter") and
(inp.isParameter(0) and outp.isResult())
or
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module semmle.go.Packages

go 1.17
go 1.25

require github.com/nonexistent/test v0.0.0-20200203000000-0000000000000
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func source() string {
return "untrusted data"
}

func sink(string) {
func sink(any) {
}

func main() {
Expand All @@ -21,10 +21,17 @@ func main() {
s0 := ""
s1 := source()
sSlice := []string{s0, s1}
sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter"
sink(test.FunctionWithSliceParameter(sSlice)) // $ hasTaintFlow="call to FunctionWithSliceParameter" MISSING: hasValueFlow="call to FunctionWithSliceParameter"
sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ hasTaintFlow="call to FunctionWithVarArgsParameter" MISSING: hasValueFlow="call to FunctionWithVarArgsParameter"
sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsParameter"
sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter"
sink(test.FunctionWithSliceParameter(sSlice)) // $ hasTaintFlow="call to FunctionWithSliceParameter" MISSING: hasValueFlow="call to FunctionWithSliceParameter"
sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ hasTaintFlow="call to FunctionWithVarArgsParameter" MISSING: hasValueFlow="call to FunctionWithVarArgsParameter"
randomFunctionWithMoreThanOneParameter(1, 2, 3, 4, 5) // This is needed to make the next line pass, because we need to have seen a call to a function with at least 2 parameters for ParameterInput to exist with index 1.
sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to FunctionWithVarArgsParameter"

var out1 *string
var out2 *string
test.FunctionWithVarArgsOutParameter(source(), out1, out2)
sink(out1) // $ hasValueFlow="out1"
sink(out2) // $ hasValueFlow="out2"

sliceOfStructs := []test.A{{Field: source()}}
sink(sliceOfStructs[0].Field) // $ hasValueFlow="selection of Field"
Expand All @@ -37,3 +44,6 @@ func main() {
sink(test.FunctionWithVarArgsOfStructsParameter(aSlice...)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
sink(test.FunctionWithVarArgsOfStructsParameter(a0, a1)) // $ MISSING: hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
}

func randomFunctionWithMoreThanOneParameter(i1, i2, i3, i4, i5 int) {
}
Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading