cmd/govulncheck: fix mod level behavior

Fixes a bug where govulncheck would incorrectly state that there were no
packages found matching the provided pattern when ran with the
-scan=module flag.
Additionally, this change adds base regression tests to ensure that:
1. Module level scanning short circuits before emitting more granular
   findings
2. Module level scanning still emits the same osvs as source level

Adds tests to ensure that module level scans behave as
expected. Further tests will be added for edge cases.

Change-Id: I144a785c416501e84c0f089c40456cebd7738456
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/543162
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
This commit is contained in:
Maceo Thompson 2023-11-08 15:24:04 -05:00
Родитель 286bb05c5f
Коммит d51afa664d
3 изменённых файлов: 313 добавлений и 21 удалений

Просмотреть файл

@ -0,0 +1,297 @@
#####
# Test that findings with callstacks or packages are not emitted in module mode
$ govulncheck -json -scan module -C ${moddir}/multientry .
{
"config": {
"protocol_version": "v1.0.0",
"scanner_name": "govulncheck",
"scanner_version": "v0.0.0-00000000000-20000101010101",
"db": "testdata/vulndb-v1",
"db_last_modified": "2023-04-03T15:57:51Z",
"go_version": "go1.18",
"scan_level": "module"
}
}
{
"progress": {
"message": "Scanning your code across 2 dependent modules for known vulnerabilities..."
}
}
{
"osv": {
"schema_version": "1.3.1",
"id": "GO-2022-0969",
"modified": "2023-04-03T15:57:51Z",
"published": "2022-09-12T20:23:06Z",
"aliases": [
"CVE-2022-27664",
"GHSA-69cg-p879-7622"
],
"details": "HTTP/2 server connections can hang forever waiting for a clean shutdown that was preempted by a fatal error. This condition can be exploited by a malicious client to cause a denial of service.",
"affected": [
{
"package": {
"name": "stdlib",
"ecosystem": "Go"
},
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "1.18.6"
},
{
"introduced": "1.19.0"
},
{
"fixed": "1.19.1"
}
]
}
],
"ecosystem_specific": {
"imports": [
{
"path": "net/http",
"symbols": [
"ListenAndServe",
"ListenAndServeTLS",
"Serve",
"ServeTLS",
"Server.ListenAndServe",
"Server.ListenAndServeTLS",
"Server.Serve",
"Server.ServeTLS",
"http2Server.ServeConn",
"http2serverConn.goAway"
]
}
]
}
},
{
"package": {
"name": "golang.org/x/net",
"ecosystem": "Go"
},
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "0.0.0-20220906165146-f3363e06e74c"
}
]
}
],
"ecosystem_specific": {
"imports": [
{
"path": "golang.org/x/net/http2",
"symbols": [
"Server.ServeConn",
"serverConn.goAway"
]
}
]
}
}
],
"references": [
{
"type": "WEB",
"url": "https://groups.google.com/g/golang-announce/c/x49AQzIVX-s"
},
{
"type": "REPORT",
"url": "https://go.dev/issue/54658"
},
{
"type": "FIX",
"url": "https://go.dev/cl/428735"
}
],
"credits": [
{
"name": "Bahruz Jabiyev, Tommaso Innocenti, Anthony Gavazzi, Steven Sprecher, and Kaan Onarlioglu"
}
],
"database_specific": {
"url": "https://pkg.go.dev/vuln/GO-2022-0969"
}
}
}
{
"finding": {
"osv": "GO-2022-0969",
"fixed_version": "v1.18.6",
"trace": [
{
"module": "stdlib",
"version": "v1.18.0",
"package": "net/http"
}
]
}
}
{
"osv": {
"schema_version": "1.3.1",
"id": "GO-2021-0113",
"modified": "2023-04-03T15:57:51Z",
"published": "2021-10-06T17:51:21Z",
"aliases": [
"CVE-2021-38561",
"GHSA-ppp9-7jff-5vj2"
],
"details": "Due to improper index calculation, an incorrectly formatted language tag can cause Parse to panic via an out of bounds read. If Parse is used to process untrusted user inputs, this may be used as a vector for a denial of service attack.",
"affected": [
{
"package": {
"name": "golang.org/x/text",
"ecosystem": "Go"
},
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "0.3.7"
}
]
}
],
"ecosystem_specific": {
"imports": [
{
"path": "golang.org/x/text/language",
"symbols": [
"MatchStrings",
"MustParse",
"Parse",
"ParseAcceptLanguage"
]
}
]
}
}
],
"references": [
{
"type": "FIX",
"url": "https://go.dev/cl/340830"
},
{
"type": "FIX",
"url": "https://go.googlesource.com/text/+/383b2e75a7a4198c42f8f87833eefb772868a56f"
}
],
"credits": [
{
"name": "Guido Vranken"
}
],
"database_specific": {
"url": "https://pkg.go.dev/vuln/GO-2021-0113"
}
}
}
{
"finding": {
"osv": "GO-2021-0113",
"fixed_version": "v0.3.7",
"trace": [
{
"module": "golang.org/x/text",
"version": "v0.3.5"
}
]
}
}
{
"osv": {
"schema_version": "1.3.1",
"id": "GO-2020-0015",
"modified": "2023-04-03T15:57:51Z",
"published": "2021-04-14T20:04:52Z",
"aliases": [
"CVE-2020-14040",
"GHSA-5rcv-m4m3-hfh7"
],
"details": "An attacker could provide a single byte to a UTF16 decoder instantiated with UseBOM or ExpectBOM to trigger an infinite loop if the String function on the Decoder is called, or the Decoder is passed to transform.String. If used to parse user supplied input, this may be used as a denial of service vector.",
"affected": [
{
"package": {
"name": "golang.org/x/text",
"ecosystem": "Go"
},
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "0.3.3"
}
]
}
],
"ecosystem_specific": {
"imports": [
{
"path": "golang.org/x/text/encoding/unicode",
"symbols": [
"bomOverride.Transform",
"utf16Decoder.Transform"
]
},
{
"path": "golang.org/x/text/transform",
"symbols": [
"String"
]
}
]
}
}
],
"references": [
{
"type": "FIX",
"url": "https://go.dev/cl/238238"
},
{
"type": "FIX",
"url": "https://go.googlesource.com/text/+/23ae387dee1f90d29a23c0e87ee0b46038fbed0e"
},
{
"type": "REPORT",
"url": "https://go.dev/issue/39491"
},
{
"type": "WEB",
"url": "https://groups.google.com/g/golang-announce/c/bXVeAmGOqz0"
}
],
"credits": [
{
"name": "@abacabadabacaba and Anton Gyllenberg"
}
],
"database_specific": {
"url": "https://pkg.go.dev/vuln/GO-2020-0015"
}
}
}

Просмотреть файл

@ -52,11 +52,11 @@ func runSource(ctx context.Context, handler govulncheck.Handler, cfg *config, cl
return fmt.Errorf("loading packages: %w", err)
}
}
if err := handler.Progress(sourceProgressMessage(pkgs, len(mods)-1)); err != nil {
if err := handler.Progress(sourceProgressMessage(pkgs, len(mods)-1, cfg.ScanLevel)); err != nil {
return err
}
if len(pkgs) == 0 {
if cfg.ScanLevel.WantPackages() && len(pkgs) == 0 {
return nil // early exit
}
return vulncheck.Source(ctx, handler, pkgs, &cfg.Config, client, graph)
@ -71,26 +71,21 @@ func runSource(ctx context.Context, handler govulncheck.Handler, cfg *config, cl
// is 0, then the following message is returned
//
// "No packages matching the provided pattern."
func sourceProgressMessage(topPkgs []*packages.Package, mods int) *govulncheck.Progress {
if len(topPkgs) == 0 {
// The package pattern is valid, but no packages are matching.
// Example is pkg/strace/... (see #59623).
return &govulncheck.Progress{Message: "No packages matching the provided pattern."}
func sourceProgressMessage(topPkgs []*packages.Package, mods int, mode govulncheck.ScanLevel) *govulncheck.Progress {
var pkgsPhrase, modsPhrase string
if mode.WantPackages() {
if len(topPkgs) == 0 {
// The package pattern is valid, but no packages are matching.
// Example is pkg/strace/... (see #59623).
return &govulncheck.Progress{Message: "No packages matching the provided pattern."}
}
pkgs := depPkgs(topPkgs)
pkgsPhrase = fmt.Sprintf(" and %d package%s", pkgs, choose(pkgs != 1, "s", ""))
}
modsPhrase = fmt.Sprintf(" %d dependent module%s", mods, choose(mods != 1, "s", ""))
pkgs := depPkgs(topPkgs)
pkgsPhrase := fmt.Sprintf("%d package", pkgs)
if pkgs != 1 {
pkgsPhrase += "s"
}
modsPhrase := fmt.Sprintf("%d dependent module", mods)
if mods != 1 {
modsPhrase += "s"
}
msg := fmt.Sprintf("Scanning your code and %s across %s for known vulnerabilities...", pkgsPhrase, modsPhrase)
msg := fmt.Sprintf("Scanning your code%s across%s for known vulnerabilities...", pkgsPhrase, modsPhrase)
return &govulncheck.Progress{Message: msg}
}

Просмотреть файл

@ -37,7 +37,6 @@ func source(ctx context.Context, handler govulncheck.Handler, pkgs []*packages.P
ctx, cancel := context.WithCancel(ctx)
defer cancel()
fset := pkgs[0].Fset
// If we are building the callgraph, build ssa and the callgraph in parallel
// with fetching vulnerabilities. If the vulns set is empty, return without
// waiting for SSA construction or callgraph to finish.
@ -48,6 +47,7 @@ func source(ctx context.Context, handler govulncheck.Handler, pkgs []*packages.P
buildErr error
)
if cfg.ScanLevel.WantSymbols() {
fset := pkgs[0].Fset
wg.Add(1)
go func() {
defer wg.Done()