vulncheck: add module path to vulns in binary mode
When analyzing a binary, populate Vuln.ModPath with a module path that
corresponds to the package path.
Change-Id: Iea3405a66bd9f8b2cbc58e8d3809bc2911c23559
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/400117
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
diff --git a/vulncheck/binary.go b/vulncheck/binary.go
index 0d1d331..273a3fd 100644
--- a/vulncheck/binary.go
+++ b/vulncheck/binary.go
@@ -11,6 +11,7 @@
"context"
"io"
"runtime"
+ "strings"
"golang.org/x/tools/go/packages"
"golang.org/x/vuln/internal/derrors"
@@ -34,10 +35,11 @@
modVulns = modVulns.filter(lookupEnv("GOOS", runtime.GOOS), lookupEnv("GOARCH", runtime.GOARCH))
result := &Result{}
for pkg, symbols := range packageSymbols {
+ mod := findPackageModule(pkg, cmods)
if cfg.ImportsOnly {
- addImportsOnlyVulns(pkg, symbols, result, modVulns)
+ addImportsOnlyVulns(pkg, mod, symbols, result, modVulns)
} else {
- addSymbolVulns(pkg, symbols, result, modVulns)
+ addSymbolVulns(pkg, mod, symbols, result, modVulns)
}
}
setModules(result, cmods)
@@ -46,7 +48,7 @@
// addImportsOnlyVulns adds Vuln entries to result in imports only mode, i.e., for each vulnerable symbol
// of pkg.
-func addImportsOnlyVulns(pkg string, symbols []string, result *Result, modVulns moduleVulnerabilities) {
+func addImportsOnlyVulns(pkg, mod string, symbols []string, result *Result, modVulns moduleVulnerabilities) {
for _, osv := range modVulns.vulnsForPackage(pkg) {
for _, affected := range osv.Affected {
if affected.Package.Name != pkg {
@@ -70,7 +72,7 @@
OSV: osv,
Symbol: symbol,
PkgPath: pkg,
- // TODO(zpavlinovic): infer mod path from PkgPath and modules?
+ ModPath: mod,
}
result.Vulns = append(result.Vulns, vuln)
}
@@ -79,7 +81,7 @@
}
// addSymbolVulns adds Vuln entries to result for every symbol of pkg in the binary that is vulnerable.
-func addSymbolVulns(pkg string, symbols []string, result *Result, modVulns moduleVulnerabilities) {
+func addSymbolVulns(pkg, mod string, symbols []string, result *Result, modVulns moduleVulnerabilities) {
for _, symbol := range symbols {
for _, osv := range modVulns.vulnsForSymbol(pkg, symbol) {
for _, affected := range osv.Affected {
@@ -90,7 +92,7 @@
OSV: osv,
Symbol: symbol,
PkgPath: pkg,
- // TODO(zpavlinovic): infer mod path from PkgPath and modules?
+ ModPath: mod,
}
result.Vulns = append(result.Vulns, vuln)
break
@@ -102,7 +104,7 @@
func convertModules(mods []*packages.Module) []*Module {
vmods := make([]*Module, len(mods))
// TODO(github.com/golang/go/issues/50030): should we share unique
- // modules? Not needed nowas module info is not returned by Binary.
+ // modules? Not needed now as module info is not returned by Binary.
for i, mod := range mods {
vmods[i] = &Module{
Path: mod.Path,
@@ -117,3 +119,16 @@
}
return vmods
}
+
+// findPackageModule returns the path of a module that could contain the import
+// path pkg. It uses paths only. It is possible but unlikely for a package path
+// to match two or more different module paths. We just take the first one.
+// If no module path matches, findPackageModule returns the empty string.
+func findPackageModule(pkg string, mods []*Module) string {
+ for _, m := range mods {
+ if pkg == m.Path || strings.HasPrefix(pkg, m.Path+"/") {
+ return m.Path
+ }
+ }
+ return ""
+}
diff --git a/vulncheck/binary_test.go b/vulncheck/binary_test.go
index 2051c34..c610b1c 100644
--- a/vulncheck/binary_test.go
+++ b/vulncheck/binary_test.go
@@ -118,8 +118,16 @@
// In importsOnly mode, all three vulnerable symbols
// {avuln.VulnData.Vuln1, avuln.VulnData.Vuln2, bvuln.Vuln}
// should be detected.
- if len(res.Vulns) != 3 {
- t.Errorf("expected 3 vuln symbols; got %d", len(res.Vulns))
+ wantVulns := []*Vuln{
+ {Symbol: "Vuln", PkgPath: "golang.org/bmod/bvuln", ModPath: "golang.org/bmod"},
+ {Symbol: "VulnData.Vuln1", PkgPath: "golang.org/amod/avuln", ModPath: "golang.org/amod"},
+ {Symbol: "VulnData.Vuln2", PkgPath: "golang.org/amod/avuln", ModPath: "golang.org/amod"},
+ }
+ diff := cmp.Diff(wantVulns, res.Vulns,
+ cmpopts.IgnoreFields(Vuln{}, "OSV"),
+ cmpopts.SortSlices(func(v1, v2 *Vuln) bool { return v1.Symbol < v2.Symbol }))
+ if diff != "" {
+ t.Errorf("vulns mismatch (-want, +got)\n%s", diff)
}
// Test the symbols (non-import mode)