diff --git a/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql b/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql index fbaf1f7e5f4..939792abe1a 100644 --- a/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql +++ b/ql/src/Security/CWE-322/InsecureHostKeyCallback.ql @@ -14,14 +14,14 @@ import DataFlow::PathGraph /** The `ssh.InsecureIgnoreHostKey` function, which allows connecting to any host regardless of its host key. */ class InsecureIgnoreHostKey extends Function { InsecureIgnoreHostKey() { - this.hasQualifiedName("golang.org/x/crypto/ssh", "InsecureIgnoreHostKey") + this.hasQualifiedName(CryptoSsh::packagePath(), "InsecureIgnoreHostKey") } } /** An SSH host-key checking function. */ class HostKeyCallbackFunc extends DataFlow::Node { HostKeyCallbackFunc() { - exists(NamedType nt | nt.hasQualifiedName("golang.org/x/crypto/ssh", "HostKeyCallback") | + exists(NamedType nt | nt.hasQualifiedName(CryptoSsh::packagePath(), "HostKeyCallback") | getType().getUnderlyingType() = nt.getUnderlyingType() ) and // Restrict possible sources to either function definitions or @@ -66,7 +66,7 @@ class HostKeyCallbackAssignmentConfig extends DataFlow::Configuration { */ predicate isSink(DataFlow::Node sink, Write write) { exists(Field f | - f.hasQualifiedName("golang.org/x/crypto/ssh", "ClientConfig", "HostKeyCallback") and + f.hasQualifiedName(CryptoSsh::packagePath(), "ClientConfig", "HostKeyCallback") and write.writesField(_, f, sink) ) } diff --git a/ql/src/Security/CWE-352/ConstantOauth2State.ql b/ql/src/Security/CWE-352/ConstantOauth2State.ql index d28d6c8474b..5ae80cdfc74 100644 --- a/ql/src/Security/CWE-352/ConstantOauth2State.ql +++ b/ql/src/Security/CWE-352/ConstantOauth2State.ql @@ -18,7 +18,9 @@ import DataFlow::PathGraph * to the OAuth 2.0 authorization dialog of the provider. */ class AuthCodeURL extends Method { - AuthCodeURL() { this.hasQualifiedName("golang.org/x/oauth2", "Config", "AuthCodeURL") } + AuthCodeURL() { + this.hasQualifiedName(package("golang.org/x/oauth2", ""), "Config", "AuthCodeURL") + } } /** @@ -52,7 +54,9 @@ class ConstantStateFlowConf extends DataFlow::Configuration { * This propagates flow from the RedirectURL field to the whole Config object. */ predicate isUrlTaintingConfigStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(Write w, Field f | f.hasQualifiedName("golang.org/x/oauth2", "Config", "RedirectURL") | + exists(Write w, Field f | + f.hasQualifiedName(package("golang.org/x/oauth2", ""), "Config", "RedirectURL") + | w.writesField(succ.(DataFlow::PostUpdateNode).getPreUpdateNode(), f, pred) ) } diff --git a/ql/src/semmle/go/frameworks/Beego.qll b/ql/src/semmle/go/frameworks/Beego.qll index 6581f0b462c..246c8cc6b6b 100644 --- a/ql/src/semmle/go/frameworks/Beego.qll +++ b/ql/src/semmle/go/frameworks/Beego.qll @@ -8,19 +8,19 @@ import semmle.go.security.Xss private import semmle.go.security.SafeUrlFlowCustomizations module Beego { - /** Gets the package name. */ + /** Gets the package name `github.com/astaxie/beego`. */ bindingset[result] string packagePath() { result = package("github.com/astaxie/beego", "") } - /** Gets the context subpackage name. */ + /** Gets the context subpackage name `github.com/astaxie/beego/context`. */ bindingset[result] string contextPackagePath() { result = package("github.com/astaxie/beego", "context") } - /** Gets the logs subpackage name. */ + /** Gets the logs subpackage name `github.com/astaxie/beego/logs`. */ bindingset[result] string logsPackagePath() { result = package("github.com/astaxie/beego", "logs") } - /** Gets the utils subpackage name. */ + /** Gets the utils subpackage name `github.com/astaxie/beego/utils`. */ bindingset[result] string utilsPackagePath() { result = package("github.com/astaxie/beego", "utils") } diff --git a/ql/src/semmle/go/frameworks/BeegoOrm.qll b/ql/src/semmle/go/frameworks/BeegoOrm.qll index 9ccf87a0e7c..c6410bd117d 100644 --- a/ql/src/semmle/go/frameworks/BeegoOrm.qll +++ b/ql/src/semmle/go/frameworks/BeegoOrm.qll @@ -7,7 +7,7 @@ import go private import semmle.go.security.StoredXssCustomizations module BeegoOrm { - /** Gets the package name. */ + /** Gets the package name `github.com/astaxie/beego/orm`. */ bindingset[result] string packagePath() { result = package("github.com/astaxie/beego", "orm") } diff --git a/ql/src/semmle/go/frameworks/Chi.qll b/ql/src/semmle/go/frameworks/Chi.qll index 817ed14387f..c50a56641ce 100644 --- a/ql/src/semmle/go/frameworks/Chi.qll +++ b/ql/src/semmle/go/frameworks/Chi.qll @@ -5,12 +5,16 @@ import go private module Chi { + /** Gets the package name `github.com/go-chi/chi`. */ + bindingset[result] + string packagePath() { result = package("github.com/go-chi/chi", "") } + /** * Functions that extract URL parameters, considered as a source of untrusted flow. */ private class UserControlledFunction extends UntrustedFlowSource::Range, DataFlow::CallNode { UserControlledFunction() { - this.getTarget().hasQualifiedName("github.com/go-chi/chi", ["URLParam", "URLParamFromCtx"]) + this.getTarget().hasQualifiedName(packagePath(), ["URLParam", "URLParamFromCtx"]) } } @@ -20,7 +24,7 @@ private module Chi { private class UserControlledRequestMethod extends UntrustedFlowSource::Range, DataFlow::MethodCallNode { UserControlledRequestMethod() { - this.getTarget().hasQualifiedName("github.com/go-chi/chi", "Context", "URLParam") + this.getTarget().hasQualifiedName(packagePath(), "Context", "URLParam") } } } diff --git a/ql/src/semmle/go/frameworks/Echo.qll b/ql/src/semmle/go/frameworks/Echo.qll index 08b1a76fd06..330868f1d68 100644 --- a/ql/src/semmle/go/frameworks/Echo.qll +++ b/ql/src/semmle/go/frameworks/Echo.qll @@ -6,7 +6,7 @@ import go private module Echo { - /** Gets an Echo package name. */ + /** Gets the package name `github.com/labstack/echo`. */ bindingset[result] private string packagePath() { result = package("github.com/labstack/echo", "") } diff --git a/ql/src/semmle/go/frameworks/Email.qll b/ql/src/semmle/go/frameworks/Email.qll index 32f70aeb405..c4234ae6e20 100644 --- a/ql/src/semmle/go/frameworks/Email.qll +++ b/ql/src/semmle/go/frameworks/Email.qll @@ -44,7 +44,10 @@ module EmailData { } /** Gets the package name `github.com/sendgrid/sendgrid-go/helpers/mail`. */ - private string sendgridMail() { result = "github.com/sendgrid/sendgrid-go/helpers/mail" } + bindingset[result] + private string sendgridMail() { + result = package("github.com/sendgrid/sendgrid-go", "helpers/mail") + } private class NewContent extends TaintTracking::FunctionModel { NewContent() { diff --git a/ql/src/semmle/go/frameworks/Encoding.qll b/ql/src/semmle/go/frameworks/Encoding.qll index e575c046a75..ad1fabf5522 100644 --- a/ql/src/semmle/go/frameworks/Encoding.qll +++ b/ql/src/semmle/go/frameworks/Encoding.qll @@ -4,14 +4,17 @@ import go +/** Gets the package name `github.com/json-iterator/go`. */ +bindingset[result] +private string packagePath() { result = package("github.com/json-iterator/go", "") } + /** A model of json-iterator's `Unmarshal` function, propagating taint from the JSON input to the decoded object. */ private class JsonIteratorUnmarshalFunction extends TaintTracking::FunctionModel, UnmarshalingFunction::Range { JsonIteratorUnmarshalFunction() { - this.hasQualifiedName("github.com/json-iterator/go", ["Unmarshal", "UnmarshalFromString"]) + this.hasQualifiedName(packagePath(), ["Unmarshal", "UnmarshalFromString"]) or - this.(Method) - .implements("github.com/json-iterator/go", "API", ["Unmarshal", "UnmarshalFromString"]) + this.(Method).implements(packagePath(), "API", ["Unmarshal", "UnmarshalFromString"]) } override DataFlow::FunctionInput getAnInput() { result.isParameter(0) } diff --git a/ql/src/semmle/go/frameworks/EvanphxJsonPatch.qll b/ql/src/semmle/go/frameworks/EvanphxJsonPatch.qll index 968f79ad0bf..b97561fd80e 100644 --- a/ql/src/semmle/go/frameworks/EvanphxJsonPatch.qll +++ b/ql/src/semmle/go/frameworks/EvanphxJsonPatch.qll @@ -1,10 +1,11 @@ /** - * Provides classes modeling github.com/evanphx/json-patch. + * Provides classes modeling `github.com/evanphx/json-patch`. */ import go private module EvanphxJsonPatch { + /** Gets the package name `github.com/evanphx/json-patch`. */ bindingset[result] private string packagePath() { result = package("github.com/evanphx/json-patch", "") } diff --git a/ql/src/semmle/go/frameworks/Gin.qll b/ql/src/semmle/go/frameworks/Gin.qll index 107ab0fa47c..7007177d1fe 100644 --- a/ql/src/semmle/go/frameworks/Gin.qll +++ b/ql/src/semmle/go/frameworks/Gin.qll @@ -6,7 +6,8 @@ import go private module Gin { /** Gets the package name `github.com/gin-gonic/gin`. */ - private string packagePath() { result = "github.com/gin-gonic/gin" } + bindingset[result] + string packagePath() { result = package("github.com/gin-gonic/gin", "") } /** * Data from a `Context` struct, considered as a source of untrusted flow. diff --git a/ql/src/semmle/go/frameworks/GoRestfulHttp.qll b/ql/src/semmle/go/frameworks/GoRestfulHttp.qll index 75a44366ba1..2219c334f3f 100644 --- a/ql/src/semmle/go/frameworks/GoRestfulHttp.qll +++ b/ql/src/semmle/go/frameworks/GoRestfulHttp.qll @@ -1,15 +1,19 @@ import go /** - * Provides models of the go-restful library (https://github.com/emicklei/go-restful). + * Provides models of the go-restful library (`https://github.com/emicklei/go-restful`). */ private module GoRestfulHttp { + /** Gets the package name `github.com/emicklei/go-restful`. */ + bindingset[result] + string packagePath() { result = package("github.com/emicklei/go-restful", "") } + /** * A model for methods defined on go-restful's `Request` object that may return user-controlled data. */ private class GoRestfulSourceMethod extends Method { GoRestfulSourceMethod() { - this.hasQualifiedName(package("github.com/emicklei/go-restful", ""), "Request", + this.hasQualifiedName(packagePath(), "Request", [ "QueryParameters", "QueryParameter", "BodyParameter", "HeaderParameter", "PathParameter", "PathParameters" @@ -30,8 +34,7 @@ private module GoRestfulHttp { private class GoRestfulReadEntitySource extends UntrustedFlowSource::Range { GoRestfulReadEntitySource() { exists(DataFlow::MethodCallNode call | - call.getTarget() - .hasQualifiedName(package("github.com/emicklei/go-restful", ""), "Request", "ReadEntity") + call.getTarget().hasQualifiedName(packagePath(), "Request", "ReadEntity") | this = FunctionOutput::parameter(0).getExitNode(call) ) diff --git a/ql/src/semmle/go/frameworks/K8sIoApiCoreV1.qll b/ql/src/semmle/go/frameworks/K8sIoApiCoreV1.qll index fbadaa90dd8..9b4bd97c37b 100644 --- a/ql/src/semmle/go/frameworks/K8sIoApiCoreV1.qll +++ b/ql/src/semmle/go/frameworks/K8sIoApiCoreV1.qll @@ -6,7 +6,7 @@ import go * Provides models of commonly used functions in the `k8s.io/api/core/v1` package. */ module K8sIoApiCoreV1 { - /** Gets the package name. */ + /** Gets the package name `k8s.io/api/core/v1`. */ bindingset[result] string packagePath() { result = package("k8s.io/api", "core/v1") } diff --git a/ql/src/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll b/ql/src/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll index 4843cd2f693..774322c41e2 100644 --- a/ql/src/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll +++ b/ql/src/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll @@ -6,7 +6,7 @@ import go * Provides models of commonly used functions in the `k8s.io/apimachinery/pkg/runtime` package. */ module K8sIoApimachineryPkgRuntime { - /** Gets the package name. */ + /** Gets the package name `k8s.io/apimachinery/pkg/runtime`. */ bindingset[result] string packagePath() { result = package("k8s.io/apimachinery", "pkg/runtime") } diff --git a/ql/src/semmle/go/frameworks/K8sIoClientGo.qll b/ql/src/semmle/go/frameworks/K8sIoClientGo.qll index 38048aed95c..c4c9ca34673 100644 --- a/ql/src/semmle/go/frameworks/K8sIoClientGo.qll +++ b/ql/src/semmle/go/frameworks/K8sIoClientGo.qll @@ -7,7 +7,7 @@ import go * package. */ module K8sIoClientGo { - /** Gets the package name. */ + /** Gets the package name `k8s.io/client-go/kubernetes/typed/core/v1`. */ bindingset[result] string packagePath() { result = package("k8s.io/client-go", "kubernetes/typed/core/v1") } diff --git a/ql/src/semmle/go/frameworks/Logrus.qll b/ql/src/semmle/go/frameworks/Logrus.qll index 902ce0fb0e8..4be9c1c2f84 100644 --- a/ql/src/semmle/go/frameworks/Logrus.qll +++ b/ql/src/semmle/go/frameworks/Logrus.qll @@ -4,8 +4,11 @@ import go /** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */ module Logrus { - /** Gets the package name. */ - string packagePath() { result in ["github.com/sirupsen/logrus", "github.com/Sirupsen/logrus"] } + /** Gets the package name `github.com/sirupsen/logrus`. */ + bindingset[result] + string packagePath() { + result = package(["github.com/sirupsen/logrus", "github.com/Sirupsen/logrus"], "") + } bindingset[result] private string getALogResultName() { diff --git a/ql/src/semmle/go/frameworks/Mux.qll b/ql/src/semmle/go/frameworks/Mux.qll index 2c2d783f566..bca64c17cf6 100644 --- a/ql/src/semmle/go/frameworks/Mux.qll +++ b/ql/src/semmle/go/frameworks/Mux.qll @@ -10,6 +10,8 @@ import go module Mux { /** An access to a Mux middleware variable. */ class RequestVars extends DataFlow::UntrustedFlowSource::Range, DataFlow::CallNode { - RequestVars() { this.getTarget().hasQualifiedName("github.com/gorilla/mux", "Vars") } + RequestVars() { + this.getTarget().hasQualifiedName(package("github.com/gorilla/mux", ""), "Vars") + } } } diff --git a/ql/src/semmle/go/frameworks/NoSQL.qll b/ql/src/semmle/go/frameworks/NoSQL.qll index 75ab2dc3765..9f9ca609084 100644 --- a/ql/src/semmle/go/frameworks/NoSQL.qll +++ b/ql/src/semmle/go/frameworks/NoSQL.qll @@ -99,7 +99,8 @@ module NoSQL { MongoDbCollectionQuery() { exists(Method meth, string methodName, int n | mongoDbCollectionMethod(methodName, n) and - meth.hasQualifiedName("go.mongodb.org/mongo-driver/mongo", "Collection", methodName) and + meth.hasQualifiedName(package("go.mongodb.org/mongo-driver", "mongo"), "Collection", + methodName) and this = meth.getACall().getArgument(n) ) } @@ -113,7 +114,7 @@ module NoSQL { // Taint an entry if the `Value` is tainted exists(Write w, DataFlow::Node base, Field f | w.writesField(base, f, pred) | base = succ.(DataFlow::PostUpdateNode).getPreUpdateNode() and - base.getType().hasQualifiedName("go.mongodb.org/mongo-driver/bson/primitive", "E") and + base.getType().hasQualifiedName(package("go.mongodb.org/mongo-driver", "bson/primitive"), "E") and f.getName() = "Value" ) } diff --git a/ql/src/semmle/go/frameworks/Protobuf.qll b/ql/src/semmle/go/frameworks/Protobuf.qll index a9157749a9c..2a0c3bf61b9 100644 --- a/ql/src/semmle/go/frameworks/Protobuf.qll +++ b/ql/src/semmle/go/frameworks/Protobuf.qll @@ -5,17 +5,25 @@ import go /** Provides models of commonly used functions and types in the protobuf packages. */ module Protobuf { /** Gets the name of the modern protobuf top-level implementation package. */ - string modernProtobufPackage() { result = "google.golang.org/protobuf/proto" } + bindingset[result] + string modernProtobufPackage() { result = package("google.golang.org/protobuf", "proto") } /** Gets the name of the modern protobuf implementation's `protoiface` subpackage. */ - string protobufIfacePackage() { result = "google.golang.org/protobuf/runtime/protoiface" } + bindingset[result] + string protobufIfacePackage() { + result = package("google.golang.org/protobuf", "runtime/protoiface") + } /** Gets the name of the modern protobuf implementation's `protoreflect` subpackage. */ - string protobufReflectPackage() { result = "google.golang.org/protobuf/reflect/protoreflect" } + bindingset[result] + string protobufReflectPackage() { + result = package("google.golang.org/protobuf", "reflect/protoreflect") + } /** Gets the name of a top-level protobuf implementation package. */ + bindingset[result] string protobufPackages() { - result in ["github.com/golang/protobuf/proto", modernProtobufPackage()] + result in [package("github.com/golang/protobuf", "proto"), modernProtobufPackage()] } /** The `Marshal` and `MarshalAppend` functions in the protobuf packages. */ diff --git a/ql/src/semmle/go/frameworks/Revel.qll b/ql/src/semmle/go/frameworks/Revel.qll index 399968d1649..5081eb92e2f 100644 --- a/ql/src/semmle/go/frameworks/Revel.qll +++ b/ql/src/semmle/go/frameworks/Revel.qll @@ -7,7 +7,7 @@ private import semmle.go.security.OpenUrlRedirectCustomizations /** Provides classes and methods modelling the Revel web framework. */ module Revel { - /** Gets the package name. */ + /** Gets the package name `github.com/revel/revel`. */ bindingset[result] string packagePath() { result = package(["github.com/revel", "github.com/robfig"], "revel") } diff --git a/ql/src/semmle/go/frameworks/SQL.qll b/ql/src/semmle/go/frameworks/SQL.qll index 60412ac6fd3..3c351969d88 100644 --- a/ql/src/semmle/go/frameworks/SQL.qll +++ b/ql/src/semmle/go/frameworks/SQL.qll @@ -83,8 +83,7 @@ module SQL { SquirrelQueryString() { exists(Function fn | exists(string sq | - sq = "github.com/Masterminds/squirrel" or - sq = "github.com/lann/squirrel" + sq = package(["github.com/Masterminds", "github.com/lann"], "squirrel") | // first argument to `squirrel.Expr` fn.hasQualifiedName(sq, "Expr") @@ -207,7 +206,7 @@ module SQL { private class SqlxSink extends SQL::QueryString::Range { SqlxSink() { exists(Method meth, string name, int n | - meth.hasQualifiedName("github.com/jmoiron/sqlx", ["DB", "Tx"], name) and + meth.hasQualifiedName(package("github.com/jmoiron", "sqlx"), ["DB", "Tx"], name) and this = meth.getACall().getArgument(n) | name = ["Select", "Get"] and n = 1 @@ -219,7 +218,7 @@ module SQL { } module Gorm { - /** Gets the package name. */ + /** Gets the package name for Gorm. */ bindingset[result] string packagePath() { result = package(["github.com/jinzhu/gorm", "github.com/go-gorm/gorm", "gorm.io/gorm"], "") diff --git a/ql/src/semmle/go/frameworks/Spew.qll b/ql/src/semmle/go/frameworks/Spew.qll index eafe0694b0a..ff82bf6fc4d 100644 --- a/ql/src/semmle/go/frameworks/Spew.qll +++ b/ql/src/semmle/go/frameworks/Spew.qll @@ -8,7 +8,9 @@ import go * Provides models of commonly used functions in the `github.com/davecgh/go-spew/spew` package. */ module Spew { - private string packagePath() { result = "github.com/davecgh/go-spew/spew" } + /** Gets the package path `github.com/davecgh/go-spew/spew`. */ + bindingset[result] + private string packagePath() { result = package("github.com/davecgh/go-spew", "spew") } private class SpewCall extends LoggerCall::Range, DataFlow::CallNode { int firstPrintedArg; diff --git a/ql/src/semmle/go/frameworks/SystemCommandExecutors.qll b/ql/src/semmle/go/frameworks/SystemCommandExecutors.qll index 76e49c8c5bd..af121ae151d 100644 --- a/ql/src/semmle/go/frameworks/SystemCommandExecutors.qll +++ b/ql/src/semmle/go/frameworks/SystemCommandExecutors.qll @@ -57,7 +57,7 @@ private class SystemCommandExecutors extends SystemCommandExecution::Range, Data */ private class GoShCommandExecution extends SystemCommandExecution::Range, DataFlow::CallNode { GoShCommandExecution() { - exists(string packagePath | packagePath = "github.com/codeskyblue/go-sh" | + exists(string packagePath | packagePath = package("github.com/codeskyblue/go-sh", "") | // Catch method calls on the `Session` object: exists(Method method | method.hasQualifiedName(packagePath, "Session", "Call") @@ -77,28 +77,34 @@ private class GoShCommandExecution extends SystemCommandExecution::Range, DataFl override DataFlow::Node getCommandName() { result = this.getArgument(0) } } -/** - * A call to a method on a `Session` object from the [ssh](golang.org/x/crypto/ssh) - * package, viewed as a system-command execution. - */ -private class SshCommandExecution extends SystemCommandExecution::Range, DataFlow::CallNode { - SshCommandExecution() { - // Catch method calls on the `Session` object: - exists(Method method, string methodName | - methodName = "CombinedOutput" - or - methodName = "Output" - or - methodName = "Run" - or - methodName = "Start" - | - method.hasQualifiedName("golang.org/x/crypto/ssh", "Session", methodName) and - this = method.getACall() - ) - } +module CryptoSsh { + /** Gets the package path `golang.org/x/crypto/ssh`. */ + bindingset[result] + string packagePath() { result = package("golang.org/x/crypto", "ssh") } - override DataFlow::Node getCommandName() { result = this.getArgument(0) } + /** + * A call to a method on a `Session` object from the [ssh](golang.org/x/crypto/ssh) + * package, viewed as a system-command execution. + */ + private class SshCommandExecution extends SystemCommandExecution::Range, DataFlow::CallNode { + SshCommandExecution() { + // Catch method calls on the `Session` object: + exists(Method method, string methodName | + methodName = "CombinedOutput" + or + methodName = "Output" + or + methodName = "Run" + or + methodName = "Start" + | + method.hasQualifiedName(packagePath(), "Session", methodName) and + this = method.getACall() + ) + } + + override DataFlow::Node getCommandName() { result = this.getArgument(0) } + } } /** diff --git a/ql/src/semmle/go/frameworks/Testing.qll b/ql/src/semmle/go/frameworks/Testing.qll index e9f44d6d07d..8dc8c8b484c 100644 --- a/ql/src/semmle/go/frameworks/Testing.qll +++ b/ql/src/semmle/go/frameworks/Testing.qll @@ -76,11 +76,11 @@ module TestFile { is.getFile() = this | pkg in [ - "gen/thrifttest", "github.com/golang/mock/gomock", "github.com/onsi/ginkgo", - "github.com/onsi/gomega", "github.com/stretchr/testify/assert", - "github.com/stretchr/testify/http", "github.com/stretchr/testify/mock", - "github.com/stretchr/testify/require", "github.com/stretchr/testify/suite", - "gotest.tools/assert", "k8s.io/client-go/testing", "net/http/httptest", "testing" + "gen/thrifttest", package("github.com/golang/mock", "gomock"), Ginkgo::packagePath(), + package("github.com/onsi/gomega", ""), + package("github.com/stretchr/testify", ["assert", "http", "mock", "require", "suite"]), + package("gotest.tools", "assert"), package("k8s.io/client-go", "testing"), + "net/http/httptest", "testing" ] ) } @@ -89,9 +89,13 @@ module TestFile { /** Provides classes modelling Ginkgo. */ module Ginkgo { + /** Gets the package path `github.com/onsi/ginkgo`. */ + bindingset[result] + string packagePath() { result = package("github.com/onsi/ginkgo", "") } + /** The Ginkgo `Fail` function, which always panics. */ private class FailFunction extends Function { - FailFunction() { hasQualifiedName("github.com/onsi/ginkgo", "Fail") } + FailFunction() { hasQualifiedName(packagePath(), "Fail") } override predicate mustPanic() { any() } } diff --git a/ql/src/semmle/go/frameworks/WebSocket.qll b/ql/src/semmle/go/frameworks/WebSocket.qll index 4e03b9a8c95..39e635ac58a 100644 --- a/ql/src/semmle/go/frameworks/WebSocket.qll +++ b/ql/src/semmle/go/frameworks/WebSocket.qll @@ -90,12 +90,12 @@ module WebSocketRequestCall { GobwasWsDialFunc() { // func (d Dialer) Dial(ctx context.Context, urlstr string) (conn net.Conn, br *bufio.Reader, hs Handshake, err error) exists(Method m | - m.hasQualifiedName(package("github.com/gobwas", "ws"), "Dialer", "Dial") and + m.hasQualifiedName(GobwasWs::packagePath(), "Dialer", "Dial") and m = this.getTarget() ) or // func Dial(ctx context.Context, urlstr string) (net.Conn, *bufio.Reader, Handshake, error) - this.getTarget().hasQualifiedName(package("github.com/gobwas", "ws"), "Dial") + this.getTarget().hasQualifiedName(GobwasWs::packagePath(), "Dial") } override DataFlow::Node getRequestUrl() { result = this.getArgument(1) } @@ -107,7 +107,7 @@ module WebSocketRequestCall { private class NhooyrWebSocketDialFunc extends Range { NhooyrWebSocketDialFunc() { // func Dial(ctx context.Context, u string, opts *DialOptions) (*Conn, *http.Response, error) - this.getTarget().hasQualifiedName(package("nhooyr.io", "websocket"), "Dial") + this.getTarget().hasQualifiedName(NhooyrWebSocket::packagePath(), "Dial") } override DataFlow::Node getRequestUrl() { result = this.getArgument(1) } @@ -120,7 +120,8 @@ module WebSocketRequestCall { SacOO7DialFunc() { // func BuildProxy(Url string) func(*http.Request) (*url.URL, error) // func New(url string) Socket - this.getTarget().hasQualifiedName("github.com/sacOO7/gowebsocket", ["BuildProxy", "New"]) + this.getTarget() + .hasQualifiedName(package("github.com/sacOO7/gowebsocket", ""), ["BuildProxy", "New"]) } override DataFlow::Node getRequestUrl() { result = this.getArgument(0) } @@ -194,7 +195,7 @@ module WebSocketReader { private class NhooyrWebSocketRead extends Range, Method { NhooyrWebSocketRead() { // func (c *Conn) Read(ctx context.Context) (MessageType, []byte, error) - this.hasQualifiedName("nhooyr.io/websocket", "Conn", "Read") + this.hasQualifiedName(NhooyrWebSocket::packagePath(), "Conn", "Read") } override FunctionOutput getAnOutput() { result.isResult(1) } @@ -206,7 +207,7 @@ module WebSocketReader { private class NhooyrWebSocketReader extends Range, Method { NhooyrWebSocketReader() { // func (c *Conn) Reader(ctx context.Context) (MessageType, io.Reader, error) - this.hasQualifiedName("nhooyr.io/websocket", "Conn", "Reader") + this.hasQualifiedName(NhooyrWebSocket::packagePath(), "Conn", "Reader") } override FunctionOutput getAnOutput() { result.isResult(1) } @@ -218,7 +219,7 @@ module WebSocketReader { private class GobwasWsReadFrame extends Range { GobwasWsReadFrame() { // func ReadFrame(r io.Reader) (f Frame, err error) - this.hasQualifiedName("github.com/gobwas/ws", "ReadFrame") + this.hasQualifiedName(GobwasWs::packagePath(), "ReadFrame") } override FunctionOutput getAnOutput() { result.isResult(0) } @@ -230,7 +231,7 @@ module WebSocketReader { private class GobwasWsReadHeader extends Range { GobwasWsReadHeader() { // func ReadHeader(r io.Reader) (h Header, err error) - this.hasQualifiedName("github.com/gobwas/ws", "ReadHeader") + this.hasQualifiedName(GobwasWs::packagePath(), "ReadHeader") } override FunctionOutput getAnOutput() { result.isResult(0) } @@ -298,13 +299,25 @@ module WebSocketReader { } module GorillaWebsocket { - /** Gets the package name. */ + /** Gets the package name `github.com/gorilla/websocket`. */ bindingset[result] string packagePath() { result = package("github.com/gorilla", "websocket") } } module GolangOrgXNetWebsocket { - /** Gets the package name. */ + /** Gets the package name `golang.org/x/net/websocket`. */ bindingset[result] string packagePath() { result = package("golang.org/x/net", "websocket") } } + +module NhooyrWebSocket { + /** Gets the package name `nhooyr.io/websocket/`. */ + bindingset[result] + string packagePath() { result = package("nhooyr.io/websocket", "") } +} + +module GobwasWs { + /** Gets the package name `github.com/gobwas/ws`. */ + bindingset[result] + string packagePath() { result = package("github.com/gobwas", "ws") } +} diff --git a/ql/src/semmle/go/frameworks/XNetHtml.qll b/ql/src/semmle/go/frameworks/XNetHtml.qll index 850b5d0c462..50a7d008344 100644 --- a/ql/src/semmle/go/frameworks/XNetHtml.qll +++ b/ql/src/semmle/go/frameworks/XNetHtml.qll @@ -12,7 +12,8 @@ import go /** Provides models of commonly used functions in the `golang.org/x/net/html` subpackage. */ module XNetHtml { /** Gets the package name `golang.org/x/net/html`. */ - string packagePath() { result = "golang.org/x/net/html" } + bindingset[result] + string packagePath() { result = package("golang.org/x/net", "html") } private class EscapeString extends HtmlEscapeFunction, TaintTracking::FunctionModel { EscapeString() { this.hasQualifiedName(packagePath(), "EscapeString") } diff --git a/ql/src/semmle/go/frameworks/XPath.qll b/ql/src/semmle/go/frameworks/XPath.qll index a7665e4ad26..52ec9c82054 100644 --- a/ql/src/semmle/go/frameworks/XPath.qll +++ b/ql/src/semmle/go/frameworks/XPath.qll @@ -32,17 +32,17 @@ module XPath { private class AntchfxXpathXPathExpressionString extends Range { AntchfxXpathXPathExpressionString() { exists(Function f, string name | name.matches("Compile%") | - f.hasQualifiedName("github.com/antchfx/xpath", name) and + f.hasQualifiedName(package("github.com/antchfx/xpath", ""), name) and this = f.getACall().getArgument(0) ) or exists(Function f, string name | name.matches("MustCompile%") | - f.hasQualifiedName("github.com/antchfx/xpath", name) and + f.hasQualifiedName(package("github.com/antchfx/xpath", ""), name) and this = f.getACall().getArgument(0) ) or exists(Function f, string name | name.matches("Select%") | - f.hasQualifiedName("github.com/antchfx/xpath", name) and + f.hasQualifiedName(package("github.com/antchfx/xpath", ""), name) and this = f.getACall().getArgument(1) ) } @@ -52,12 +52,12 @@ module XPath { private class AntchfxHtmlqueryXPathExpressionString extends Range { AntchfxHtmlqueryXPathExpressionString() { exists(Function f, string name | name.matches("Find%") | - f.hasQualifiedName("github.com/antchfx/htmlquery", name) and + f.hasQualifiedName(package("github.com/antchfx/htmlquery", ""), name) and this = f.getACall().getArgument(1) ) or exists(Function f, string name | name.matches("Query%") | - f.hasQualifiedName("github.com/antchfx/htmlquery", name) and + f.hasQualifiedName(package("github.com/antchfx/htmlquery", ""), name) and this = f.getACall().getArgument(1) ) } @@ -67,17 +67,17 @@ module XPath { private class AntchfxXmlqueryXPathExpressionString extends Range { AntchfxXmlqueryXPathExpressionString() { exists(Function f, string name | name.matches("Find%") | - f.hasQualifiedName("github.com/antchfx/xmlquery", name) and + f.hasQualifiedName(package("github.com/antchfx/xmlquery", ""), name) and this = f.getACall().getArgument(1) ) or exists(Function f, string name | name.matches("Query%") | - f.hasQualifiedName("github.com/antchfx/xmlquery", name) and + f.hasQualifiedName(package("github.com/antchfx/xmlquery", ""), name) and this = f.getACall().getArgument(1) ) or exists(Method m, string name | name.matches("Select%") | - m.hasQualifiedName("github.com/antchfx/xmlquery", "Node", name) and + m.hasQualifiedName(package("github.com/antchfx/xmlquery", ""), "Node", name) and this = m.getACall().getArgument(0) ) } @@ -87,12 +87,12 @@ module XPath { private class AntchfxJsonqueryXPathExpressionString extends Range { AntchfxJsonqueryXPathExpressionString() { exists(Function f, string name | name.matches("Find%") | - f.hasQualifiedName("github.com/antchfx/jsonquery", name) and + f.hasQualifiedName(package("github.com/antchfx/jsonquery", ""), name) and this = f.getACall().getArgument(1) ) or exists(Function f, string name | name.matches("Query%") | - f.hasQualifiedName("github.com/antchfx/jsonquery", name) and + f.hasQualifiedName(package("github.com/antchfx/jsonquery", ""), name) and this = f.getACall().getArgument(1) ) } @@ -102,12 +102,12 @@ module XPath { private class GoXmlpathXmlpathXPathExpressionString extends Range { GoXmlpathXmlpathXPathExpressionString() { exists(Function f, string name | name.matches("Compile%") | - f.hasQualifiedName("github.com/go-xmlpath/xmlpath", name) and + f.hasQualifiedName(package("github.com/go-xmlpath/xmlpath", ""), name) and this = f.getACall().getArgument(0) ) or exists(Function f, string name | name.matches("MustCompile%") | - f.hasQualifiedName("github.com/go-xmlpath/xmlpath", name) and + f.hasQualifiedName(package("github.com/go-xmlpath/xmlpath", ""), name) and this = f.getACall().getArgument(0) ) } @@ -117,12 +117,12 @@ module XPath { private class ChrisTrenkampGoxpathXPathExpressionString extends Range { ChrisTrenkampGoxpathXPathExpressionString() { exists(Function f, string name | name.matches("Parse%") | - f.hasQualifiedName("github.com/ChrisTrenkamp/goxpath", name) and + f.hasQualifiedName(package("github.com/ChrisTrenkamp/goxpath", ""), name) and this = f.getACall().getArgument(0) ) or exists(Function f, string name | name.matches("MustParse%") | - f.hasQualifiedName("github.com/ChrisTrenkamp/goxpath", name) and + f.hasQualifiedName(package("github.com/ChrisTrenkamp/goxpath", ""), name) and this = f.getACall().getArgument(0) ) } @@ -132,12 +132,12 @@ module XPath { private class SanthoshTekuriXpathparserXPathExpressionString extends Range { SanthoshTekuriXpathparserXPathExpressionString() { exists(Function f, string name | name.matches("Parse%") | - f.hasQualifiedName("github.com/santhosh-tekuri/xpathparser", name) and + f.hasQualifiedName(package("github.com/santhosh-tekuri/xpathparser", ""), name) and this = f.getACall().getArgument(0) ) or exists(Function f, string name | name.matches("MustParse%") | - f.hasQualifiedName("github.com/santhosh-tekuri/xpathparser", name) and + f.hasQualifiedName(package("github.com/santhosh-tekuri/xpathparser", ""), name) and this = f.getACall().getArgument(0) ) } @@ -147,17 +147,17 @@ module XPath { private class JbowtieGokogiriXPathExpressionString extends Range { JbowtieGokogiriXPathExpressionString() { exists(Function f, string name | name.matches("Compile%") | - f.hasQualifiedName("github.com/jbowtie/gokogiri/xpath", name) and + f.hasQualifiedName(package("github.com/jbowtie/gokogiri", "xpath"), name) and this = f.getACall().getArgument(0) ) or exists(Method m, string name | name.matches("Search%") | - m.hasQualifiedName("github.com/jbowtie/gokogiri/xml", "Node", name) and + m.hasQualifiedName(package("github.com/jbowtie/gokogiri", "xml"), "Node", name) and this = m.getACall().getArgument(0) ) or exists(Method m, string name | name.matches("EvalXPath%") | - m.hasQualifiedName("github.com/jbowtie/gokogiri/xml", "Node", name) and + m.hasQualifiedName(package("github.com/jbowtie/gokogiri", "xml"), "Node", name) and this = m.getACall().getArgument(0) ) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Context.qll b/ql/src/semmle/go/frameworks/stdlib/Context.qll index e68b808d197..f94c24a8529 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Context.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Context.qll @@ -12,7 +12,8 @@ module Context { * The two packages are identical; before Go 1.7 it was only available * under `golang.org/x`; as of Go 1.7 it is included in the standard library. */ - private string packagePath() { result = ["context", "golang.org/x/net/context"] } + bindingset[result] + private string packagePath() { result = ["context", package("golang.org/x/net", "context")] } private class FunctionModels extends TaintTracking::FunctionModel { FunctionInput inp;