blob: 17b5d16e9810ca78c3d86d2ad868e2efe53063bb [file] [log] [blame]
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vulncheck
import (
"context"
"io"
"runtime"
"golang.org/x/tools/go/packages"
"golang.org/x/vuln/vulncheck/internal/binscan"
)
// Binary detects presence of vulnerable symbols in exe. The
// imports, require, and call graph are all unavailable (nil).
func Binary(ctx context.Context, exe io.ReaderAt, cfg *Config) (*Result, error) {
mods, packageSymbols, err := binscan.ExtractPackagesAndSymbols(exe)
if err != nil {
return nil, err
}
modVulns, err := fetchVulnerabilities(ctx, cfg.Client, convertModules(mods))
if err != nil {
return nil, err
}
modVulns = modVulns.Filter(lookupEnv("GOOS", runtime.GOOS), lookupEnv("GOARCH", runtime.GOARCH))
result := &Result{}
for pkg, symbols := range packageSymbols {
for _, symbol := range symbols {
for _, osv := range modVulns.VulnsForSymbol(pkg, symbol) {
for _, affected := range osv.Affected {
if affected.Package.Name != pkg {
continue
}
for _, symbol := range affected.EcosystemSpecific.Symbols {
vuln := &Vuln{
OSV: osv,
Symbol: symbol,
PkgPath: pkg,
// TODO(zpavlinovic): infer mod path from PkgPath and modules?
}
result.Vulns = append(result.Vulns, vuln)
}
}
}
}
}
return result, nil
}
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.
for i, mod := range mods {
vmods[i] = &Module{
Path: mod.Path,
Version: mod.Version,
}
if mod.Replace != nil {
vmods[i].Replace = &Module{
Path: mod.Replace.Path,
Version: mod.Replace.Version,
}
}
}
return vmods
}