diff --git a/change-notes/2021-01-07-gokit-sources.md b/change-notes/2021-01-07-gokit-sources.md new file mode 100644 index 00000000000..3f544e14f25 --- /dev/null +++ b/change-notes/2021-01-07-gokit-sources.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Models for gokit request sources have been added as an opt-in feature; import `semmle.go.frameworks.GoKit` in a query to enable these sources. diff --git a/ql/src/semmle/go/frameworks/GoKit.qll b/ql/src/semmle/go/frameworks/GoKit.qll new file mode 100644 index 00000000000..2d19e06cdbc --- /dev/null +++ b/ql/src/semmle/go/frameworks/GoKit.qll @@ -0,0 +1,47 @@ +/** + * Provides classes for working with concepts relating to the [github.com/go-kit/kit](https://pkg.go.dev/github.com/go-kit/kit) package. + * + * Note that these models are not included by default; to include them, add `import semmle.go.frameworks.GoKit` to your query or to + * `Customizations.qll`. + */ + +import go + +/** + * Provides classes for working with concepts relating to the [github.com/go-kit/kit](https://pkg.go.dev/github.com/go-kit/kit) package. + */ +module GoKit { + /** Gets the package name. */ + bindingset[result] + string packagePath() { result = package("github.com/go-kit/kit", "") } + + /** + * Provides classes for working with concepts relating to the `endpoint` package of the + * [github.com/go-kit/kit](https://pkg.go.dev/github.com/go-kit/kit) package. + */ + module Endpoint { + /** Gets the package name. */ + bindingset[result] + string endpointPackagePath() { result = package("github.com/go-kit/kit", "endpoint") } + + // gets a function that returns an endpoint + private DataFlow::Node getAnEndpointFactoryResult() { + exists(Function mkFn, FunctionOutput res | + mkFn.getResultType(0).hasQualifiedName(endpointPackagePath(), "Endpoint") and + result = res.getEntryNode(mkFn.getFuncDecl()).getAPredecessor*() + ) + } + + private FuncDef getAnEndpointFunction() { + exists(Function endpointFn | endpointFn.getFuncDecl() = result | + endpointFn.getARead() = getAnEndpointFactoryResult() + ) + or + DataFlow::exprNode(result.(FuncLit)) = getAnEndpointFactoryResult() + } + + private class EndpointRequest extends UntrustedFlowSource::Range { + EndpointRequest() { this = DataFlow::parameterNode(getAnEndpointFunction().getParameter(1)) } + } + } +} diff --git a/ql/test/library-tests/semmle/go/frameworks/GoKit/go.mod b/ql/test/library-tests/semmle/go/frameworks/GoKit/go.mod new file mode 100644 index 00000000000..82f9fc4a1a5 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/GoKit/go.mod @@ -0,0 +1,5 @@ +module codeql-go-tests/frameworks/GoKit + +go 1.15 + +require github.com/go-kit/kit v0.10.0 diff --git a/ql/test/library-tests/semmle/go/frameworks/GoKit/main.go b/ql/test/library-tests/semmle/go/frameworks/GoKit/main.go new file mode 100644 index 00000000000..17228a994da --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/GoKit/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "github.com/go-kit/kit/endpoint" +) + +type MyService interface { + Lit(string) string + Func(string) string +} + +func makeEndpointLit(svc MyService) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { // $source=definition of request + return request, nil + } +} + +func endpointfn(_ context.Context, request interface{}) (interface{}, error) { // $source=definition of request + return request, nil +} + +func makeEndpointFn(svc MyService) endpoint.Endpoint { + return endpointfn +} + +func main() {} diff --git a/ql/test/library-tests/semmle/go/frameworks/GoKit/untrustedflowsource.expected b/ql/test/library-tests/semmle/go/frameworks/GoKit/untrustedflowsource.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/test/library-tests/semmle/go/frameworks/GoKit/untrustedflowsource.ql b/ql/test/library-tests/semmle/go/frameworks/GoKit/untrustedflowsource.ql new file mode 100644 index 00000000000..08a5973a458 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/GoKit/untrustedflowsource.ql @@ -0,0 +1,18 @@ +import go +import semmle.go.frameworks.GoKit +import TestUtilities.InlineExpectationsTest + +class UntrustedFlowSourceTest extends InlineExpectationsTest { + UntrustedFlowSourceTest() { this = "untrustedflowsourcetest" } + + override string getARelevantTag() { result = "source" } + + override predicate hasActualResult(string file, int line, string element, string tag, string value) { + exists(UntrustedFlowSource source | + source.hasLocationInfo(file, line, _, _, _) and + element = source.toString() and + value = source.toString() and + tag = "source" + ) + } +} diff --git a/ql/test/library-tests/semmle/go/frameworks/GoKit/vendor/github.com/go-kit/kit/endpoint/stub.go b/ql/test/library-tests/semmle/go/frameworks/GoKit/vendor/github.com/go-kit/kit/endpoint/stub.go new file mode 100644 index 00000000000..8407318ab76 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/GoKit/vendor/github.com/go-kit/kit/endpoint/stub.go @@ -0,0 +1,14 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/go-kit/kit/endpoint, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/go-kit/kit/endpoint (exports: Endpoint; functions: ) + +// Package endpoint is a stub of github.com/go-kit/kit/endpoint, generated by depstubber. +package endpoint + +import ( + context "context" +) + +type Endpoint func(context.Context, interface{}) (interface{}, error) diff --git a/ql/test/library-tests/semmle/go/frameworks/GoKit/vendor/modules.txt b/ql/test/library-tests/semmle/go/frameworks/GoKit/vendor/modules.txt new file mode 100644 index 00000000000..fdebbe5cf25 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/GoKit/vendor/modules.txt @@ -0,0 +1,3 @@ +# github.com/go-kit/kit v0.10.0 +## explicit +github.com/go-kit/kit/endpoint