internal/vulncheck: define Binary over Bin
This simplifies tests for binary and forces us to move other tests to
more appropriate places. Further, internal/scan will use it to load
inputs from a new binary extract mode. For the same reason, also make
the stdlib runtime copies available in internal. This also makes them
more visible.
Change-Id: If01cbdd59112609ff16f712d3968e25f4544189c
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/540355
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Maceo Thompson <maceothompson@google.com>
Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/cmd/govulncheck/testdata/testfiles/failures/binary_fail.ct b/cmd/govulncheck/testdata/testfiles/failures/binary_fail.ct
index 07548d0..c72bf5f 100644
--- a/cmd/govulncheck/testdata/testfiles/failures/binary_fail.ct
+++ b/cmd/govulncheck/testdata/testfiles/failures/binary_fail.ct
@@ -6,8 +6,6 @@
#####
# Test of passing a non-binary file to -mode=binary
$ govulncheck -mode=binary ${moddir}/vuln/go.mod --> FAIL 1
-Scanning your binary for known vulnerabilities...
-
govulncheck: could not parse provided binary: unrecognized file format
#####
diff --git a/internal/vulncheck/internal/buildinfo/README.md b/internal/buildinfo/README.md
similarity index 100%
rename from internal/vulncheck/internal/buildinfo/README.md
rename to internal/buildinfo/README.md
diff --git a/internal/vulncheck/internal/buildinfo/additions_buildinfo.go b/internal/buildinfo/additions_buildinfo.go
similarity index 100%
rename from internal/vulncheck/internal/buildinfo/additions_buildinfo.go
rename to internal/buildinfo/additions_buildinfo.go
diff --git a/internal/vulncheck/internal/buildinfo/additions_scan.go b/internal/buildinfo/additions_scan.go
similarity index 98%
rename from internal/vulncheck/internal/buildinfo/additions_scan.go
rename to internal/buildinfo/additions_scan.go
index d718252..3b483a5 100644
--- a/internal/vulncheck/internal/buildinfo/additions_scan.go
+++ b/internal/buildinfo/additions_scan.go
@@ -20,7 +20,7 @@
"strings"
"golang.org/x/tools/go/packages"
- "golang.org/x/vuln/internal/vulncheck/internal/gosym"
+ "golang.org/x/vuln/internal/gosym"
)
func debugModulesToPackagesModules(debugModules []*debug.Module) []*packages.Module {
diff --git a/internal/buildinfo/additions_scan_test.go b/internal/buildinfo/additions_scan_test.go
new file mode 100644
index 0000000..3f6c620
--- /dev/null
+++ b/internal/buildinfo/additions_scan_test.go
@@ -0,0 +1,170 @@
+// 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.
+
+//go:build go1.18
+// +build go1.18
+
+package buildinfo
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sort"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "golang.org/x/tools/go/packages/packagestest"
+ "golang.org/x/vuln/internal/test"
+ "golang.org/x/vuln/internal/testenv"
+)
+
+// testAll executes testing function ft on all valid combinations
+// of gooss and goarchs.
+func testAll(t *testing.T, gooss, goarchs []string, ft func(*testing.T, string, string)) {
+ // unsupported platforms for building Go binaries.
+ var unsupported = map[string]bool{
+ "darwin/386": true,
+ "darwin/arm": true,
+ }
+
+ for _, g := range gooss {
+ for _, a := range goarchs {
+ goos := g
+ goarch := a
+
+ ga := goos + "/" + goarch
+ if unsupported[ga] {
+ continue
+ }
+
+ t.Run(ga, func(t *testing.T) {
+ ft(t, goos, goarch)
+ })
+ }
+ }
+}
+
+func TestExtractPackagesAndSymbols(t *testing.T) {
+ testAll(t, []string{"linux", "darwin", "windows", "freebsd"}, []string{"amd64", "386", "arm", "arm64"},
+ func(t *testing.T, goos, goarch string) {
+ binary, done := test.GoBuild(t, "testdata", "", false, "GOOS", goos, "GOARCH", goarch)
+ defer done()
+
+ f, err := os.Open(binary)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ _, syms, _, err := ExtractPackagesAndSymbols(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got := sortedSymbols("main", syms)
+ want := []Symbol{
+ {"main", "f"},
+ {"main", "g"},
+ {"main", "main"},
+ }
+
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Errorf("(-want,+got):%s", diff)
+ }
+ })
+}
+
+// sortedSymbols gets symbols for pkg and
+// sorts them for testing purposes.
+func sortedSymbols(pkg string, syms []Symbol) []Symbol {
+ var s []Symbol
+ for _, ps := range syms {
+ if ps.Pkg == pkg {
+ s = append(s, ps)
+ }
+ }
+ sort.SliceStable(s, func(i, j int) bool { return s[i].Pkg+"."+s[i].Name < s[j].Pkg+"."+s[j].Name })
+ return s
+}
+
+// Test58509 is supposed to test issue #58509 where a whole
+// vulnerable function is deleted from the binary so we
+// cannot detect its presence.
+//
+// Note: the issue is still not addressed and the test
+// expectations are set to fail once it gets addressed.
+func Test58509(t *testing.T) {
+ testenv.NeedsGoBuild(t)
+
+ vulnLib := `package bvuln
+
+%s debug = true
+
+func Vuln() {
+ if debug {
+ return
+ }
+ print("vuln")
+}`
+
+ for _, tc := range []struct {
+ gl string
+ want bool
+ }{
+ {"const", false}, // TODO(https://go.dev/issue/58509): change expectations once issue is addressed
+ {"var", true},
+ } {
+ tc := tc
+ t.Run(tc.gl, func(t *testing.T) {
+ e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{
+ {
+ Name: "golang.org/entry",
+ Files: map[string]interface{}{
+ "main.go": `
+ package main
+
+ import (
+ "golang.org/bmod/bvuln"
+ )
+
+ func main() {
+ bvuln.Vuln()
+ }
+ `,
+ }},
+ {
+ Name: "golang.org/bmod@v0.5.0",
+ Files: map[string]interface{}{"bvuln/bvuln.go": fmt.Sprintf(vulnLib, tc.gl)},
+ },
+ })
+ defer e.Cleanup()
+
+ cmd := exec.Command("go", "build", "-o", "entry")
+ cmd.Dir = e.Config.Dir
+ cmd.Env = e.Config.Env
+ out, err := cmd.CombinedOutput()
+ if err != nil || len(out) > 0 {
+ t.Fatalf("failed to build the binary %v %v", err, string(out))
+ }
+
+ exe, err := os.Open(filepath.Join(e.Config.Dir, "entry"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer exe.Close()
+
+ _, syms, _, err := ExtractPackagesAndSymbols(exe)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // effectively, Vuln is not optimized away from the program
+ got := len(sortedSymbols("golang.org/bmod/bvuln", syms)) != 0
+ if got != tc.want {
+ t.Errorf("want %t; got %t", tc.want, got)
+ }
+ })
+ }
+}
diff --git a/internal/vulncheck/internal/buildinfo/additions_stripped_122_test.go b/internal/buildinfo/additions_stripped_122_test.go
similarity index 97%
rename from internal/vulncheck/internal/buildinfo/additions_stripped_122_test.go
rename to internal/buildinfo/additions_stripped_122_test.go
index 9862037..4a48c60 100644
--- a/internal/vulncheck/internal/buildinfo/additions_stripped_122_test.go
+++ b/internal/buildinfo/additions_stripped_122_test.go
@@ -31,7 +31,7 @@
if err != nil {
t.Fatal(err)
}
- if syms != nil {
+ if len(syms) != 0 {
t.Errorf("want empty symbol table; got %v symbols", len(syms))
}
})
diff --git a/internal/vulncheck/internal/buildinfo/additions_stripped_test.go b/internal/buildinfo/additions_stripped_test.go
similarity index 97%
rename from internal/vulncheck/internal/buildinfo/additions_stripped_test.go
rename to internal/buildinfo/additions_stripped_test.go
index eed90a0..e21e9e8 100644
--- a/internal/vulncheck/internal/buildinfo/additions_stripped_test.go
+++ b/internal/buildinfo/additions_stripped_test.go
@@ -60,7 +60,7 @@
t.Fatal(err)
}
- got := mainSortedSymbols(syms)
+ got := sortedSymbols("main", syms)
want := []Symbol{
{"main", "f"},
{"main", "g"},
diff --git a/internal/vulncheck/internal/buildinfo/buildinfo.go b/internal/buildinfo/buildinfo.go
similarity index 100%
rename from internal/vulncheck/internal/buildinfo/buildinfo.go
rename to internal/buildinfo/buildinfo.go
diff --git a/internal/vulncheck/internal/buildinfo/testdata/main.go b/internal/buildinfo/testdata/main.go
similarity index 100%
rename from internal/vulncheck/internal/buildinfo/testdata/main.go
rename to internal/buildinfo/testdata/main.go
diff --git a/internal/vulncheck/internal/gosym/README.md b/internal/gosym/README.md
similarity index 100%
rename from internal/vulncheck/internal/gosym/README.md
rename to internal/gosym/README.md
diff --git a/internal/vulncheck/internal/gosym/additions.go b/internal/gosym/additions.go
similarity index 100%
rename from internal/vulncheck/internal/gosym/additions.go
rename to internal/gosym/additions.go
diff --git a/internal/vulncheck/internal/gosym/additions_test.go b/internal/gosym/additions_test.go
similarity index 100%
rename from internal/vulncheck/internal/gosym/additions_test.go
rename to internal/gosym/additions_test.go
diff --git a/internal/vulncheck/internal/gosym/pclntab.go b/internal/gosym/pclntab.go
similarity index 100%
rename from internal/vulncheck/internal/gosym/pclntab.go
rename to internal/gosym/pclntab.go
diff --git a/internal/vulncheck/internal/gosym/pclntab_test.go b/internal/gosym/pclntab_test.go
similarity index 100%
rename from internal/vulncheck/internal/gosym/pclntab_test.go
rename to internal/gosym/pclntab_test.go
diff --git a/internal/vulncheck/internal/gosym/symtab.go b/internal/gosym/symtab.go
similarity index 100%
rename from internal/vulncheck/internal/gosym/symtab.go
rename to internal/gosym/symtab.go
diff --git a/internal/vulncheck/internal/gosym/symtab_test.go b/internal/gosym/symtab_test.go
similarity index 100%
rename from internal/vulncheck/internal/gosym/symtab_test.go
rename to internal/gosym/symtab_test.go
diff --git a/internal/vulncheck/internal/gosym/testdata/main.go b/internal/gosym/testdata/main.go
similarity index 100%
rename from internal/vulncheck/internal/gosym/testdata/main.go
rename to internal/gosym/testdata/main.go
diff --git a/internal/vulncheck/internal/gosym/testdata/pclinetest.h b/internal/gosym/testdata/pclinetest.h
similarity index 100%
rename from internal/vulncheck/internal/gosym/testdata/pclinetest.h
rename to internal/gosym/testdata/pclinetest.h
diff --git a/internal/vulncheck/internal/gosym/testdata/pclinetest.s b/internal/gosym/testdata/pclinetest.s
similarity index 100%
rename from internal/vulncheck/internal/gosym/testdata/pclinetest.s
rename to internal/gosym/testdata/pclinetest.s
diff --git a/internal/vulncheck/internal/gosym/testdata/pcln115.gz b/internal/gosym/testdata/pcln115.gz
similarity index 100%
rename from internal/vulncheck/internal/gosym/testdata/pcln115.gz
rename to internal/gosym/testdata/pcln115.gz
Binary files differ
diff --git a/internal/scan/binary.go b/internal/scan/binary.go
index 37c6601..62779be 100644
--- a/internal/scan/binary.go
+++ b/internal/scan/binary.go
@@ -9,8 +9,12 @@
import (
"context"
+ "fmt"
+ "io"
"os"
+ "runtime/debug"
+ "golang.org/x/vuln/internal/buildinfo"
"golang.org/x/vuln/internal/client"
"golang.org/x/vuln/internal/derrors"
"golang.org/x/vuln/internal/govulncheck"
@@ -27,9 +31,39 @@
}
defer exe.Close()
+ bin, err := createBin(exe)
+ if err != nil {
+ return err
+ }
+
p := &govulncheck.Progress{Message: binaryProgressMessage}
if err := handler.Progress(p); err != nil {
return err
}
- return vulncheck.Binary(ctx, handler, exe, &cfg.Config, client)
+ return vulncheck.Binary(ctx, handler, bin, &cfg.Config, client)
+}
+
+func createBin(exe io.ReaderAt) (*vulncheck.Bin, error) {
+ mods, packageSymbols, bi, err := buildinfo.ExtractPackagesAndSymbols(exe)
+ if err != nil {
+ return nil, fmt.Errorf("could not parse provided binary: %v", err)
+ }
+ return &vulncheck.Bin{
+ Modules: mods,
+ PkgSymbols: packageSymbols,
+ GoVersion: bi.GoVersion,
+ GOOS: findSetting("GOOS", bi),
+ GOARCH: findSetting("GOARCH", bi),
+ }, nil
+}
+
+// findSetting returns value of setting from bi if present.
+// Otherwise, returns "".
+func findSetting(setting string, bi *debug.BuildInfo) string {
+ for _, s := range bi.Settings {
+ if s.Key == setting {
+ return s.Value
+ }
+ }
+ return ""
}
diff --git a/internal/vulncheck/binary.go b/internal/vulncheck/binary.go
index e637a50..0ca660f 100644
--- a/internal/vulncheck/binary.go
+++ b/internal/vulncheck/binary.go
@@ -10,36 +10,19 @@
import (
"context"
"fmt"
- "io"
- "runtime/debug"
"sort"
"golang.org/x/tools/go/packages"
"golang.org/x/vuln/internal"
+ "golang.org/x/vuln/internal/buildinfo"
"golang.org/x/vuln/internal/client"
"golang.org/x/vuln/internal/govulncheck"
"golang.org/x/vuln/internal/osv"
- "golang.org/x/vuln/internal/vulncheck/internal/buildinfo"
)
-// Binary detects presence of vulnerable symbols in exe and
-// emits findings to exe.
-func Binary(ctx context.Context, handler govulncheck.Handler, exe io.ReaderAt, cfg *govulncheck.Config, client *client.Client) error {
- bin, err := createBin(exe)
- if err != nil {
- return err
- }
-
- vr, err := binary(ctx, handler, bin, cfg, client)
- if err != nil {
- return err
- }
- return emitBinaryResult(handler, vr, binaryCallstacks(vr))
-}
-
-// bin is an abstraction of Go binary containing
+// Bin is an abstraction of Go binary containing
// minimal information needed by govulncheck.
-type bin struct {
+type Bin struct {
Modules []*packages.Module `json:"modules,omitempty"`
PkgSymbols []buildinfo.Symbol `json:"pkgSymbols,omitempty"`
GoVersion string `json:"goVersion,omitempty"`
@@ -47,25 +30,20 @@
GOARCH string `json:"goarch,omitempty"`
}
-func createBin(exe io.ReaderAt) (*bin, error) {
- mods, packageSymbols, bi, err := buildinfo.ExtractPackagesAndSymbols(exe)
+// Binary detects presence of vulnerable symbols in bin and
+// emits findings to handler.
+func Binary(ctx context.Context, handler govulncheck.Handler, bin *Bin, cfg *govulncheck.Config, client *client.Client) error {
+ vr, err := binary(ctx, handler, bin, cfg, client)
if err != nil {
- return nil, fmt.Errorf("could not parse provided binary: %v", err)
+ return err
}
-
- return &bin{
- Modules: mods,
- PkgSymbols: packageSymbols,
- GoVersion: bi.GoVersion,
- GOOS: findSetting("GOOS", bi),
- GOARCH: findSetting("GOARCH", bi),
- }, nil
+ return emitBinaryResult(handler, vr, binaryCallstacks(vr))
}
// binary detects presence of vulnerable symbols in bin.
// It does not compute call graphs so the corresponding
// info in Result will be empty.
-func binary(ctx context.Context, handler govulncheck.Handler, bin *bin, cfg *govulncheck.Config, client *client.Client) (*Result, error) {
+func binary(ctx context.Context, handler govulncheck.Handler, bin *Bin, cfg *govulncheck.Config, client *client.Client) (*Result, error) {
graph := NewPackageGraph(bin.GoVersion)
graph.AddModules(bin.Modules...)
mods := append(bin.Modules, graph.GetModule(internal.GoStdModulePath))
@@ -148,17 +126,6 @@
}
}
-// findSetting returns value of setting from bi if present.
-// Otherwise, returns "".
-func findSetting(setting string, bi *debug.BuildInfo) string {
- for _, s := range bi.Settings {
- if s.Key == setting {
- return s.Value
- }
- }
- return ""
-}
-
// addRequiresOnlyVulns adds to result all vulnerabilities in affVulns.
// Used when the binary under analysis is stripped.
func addRequiresOnlyVulns(result *Result, graph *PackageGraph, affVulns affectingVulns) {
diff --git a/internal/vulncheck/binary_test.go b/internal/vulncheck/binary_test.go
index 66ea343..5608a44 100644
--- a/internal/vulncheck/binary_test.go
+++ b/internal/vulncheck/binary_test.go
@@ -9,110 +9,33 @@
import (
"context"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
"sort"
"testing"
- "golang.org/x/tools/go/packages/packagestest"
+ "golang.org/x/tools/go/packages"
+ "golang.org/x/vuln/internal/buildinfo"
"golang.org/x/vuln/internal/govulncheck"
- "golang.org/x/vuln/internal/semver"
"golang.org/x/vuln/internal/test"
- "golang.org/x/vuln/internal/testenv"
)
-// TODO: we build binary programatically, so what if the underlying tool chain changes?
func TestBinary(t *testing.T) {
- testenv.NeedsGoBuild(t)
-
- e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{
- {
- Name: "golang.org/entry",
- Files: map[string]interface{}{
- "main.go": `
- package main
-
- import (
- "archive/zip"
- "golang.org/cmod/c"
- "golang.org/bmod/bvuln"
- )
-
- func main() {
- c.C()
- bvuln.NoVuln() // no vuln use
-
- _, err := zip.OpenReader("file.zip")
- print(err)
- }
- `,
- }},
- {
- Name: "golang.org/cmod@v1.1.3",
- Files: map[string]interface{}{"c/c.go": `
- package c
-
- import (
- "golang.org/amod/avuln"
- )
-
- func C() {
- v := avuln.VulnData{}
- v.Vuln1() // vuln use
- }
- `},
+ bin := &Bin{
+ Modules: []*packages.Module{
+ {Path: "golang.org/entry"},
+ {Path: "golang.org/cmod", Version: "v1.1.3"},
+ {Path: "golang.org/amod", Version: "v1.1.3"},
+ {Path: "golang.org/bmod", Version: "v0.5.0"},
},
- {
- Name: "golang.org/amod@v1.1.3",
- Files: map[string]interface{}{"avuln/avuln.go": `
- package avuln
-
- type VulnData struct {}
-
- func (v VulnData) Vuln1() {
- print("vuln1")
- }
-
- func (v VulnData) Vuln2() {
- print("vuln2")
- }
- `},
+ GoVersion: "go1.20",
+ GOOS: "linux",
+ GOARCH: "amd64",
+ PkgSymbols: []buildinfo.Symbol{
+ {Pkg: "golang.org/entry", Name: "main"},
+ {Pkg: "golang.org/cmod/c", Name: "C"},
+ {Pkg: "golang.org/amod/avuln", Name: "VulnData.Vuln1"}, // assume linker skips VulnData.Vuln2
+ {Pkg: "golang.org/bmod/bvuln", Name: "NoVuln"}, // assume linker skips NoVuln
+ {Pkg: "archive/zip", Name: "OpenReader"},
},
- {
- Name: "golang.org/bmod@v0.5.0",
- Files: map[string]interface{}{"bvuln/bvuln.go": `
- package bvuln
-
- func Vuln() {
- print("vuln")
- }
-
- func NoVuln() {
- print("novuln")
- }
- `},
- },
- })
- defer e.Cleanup()
-
- cmd := exec.Command("go", "build", "-o", "entry")
- cmd.Dir = e.Config.Dir
- cmd.Env = e.Config.Env
- out, err := cmd.CombinedOutput()
- if err != nil || len(out) > 0 {
- t.Fatalf("failed to build the binary %v %v", err, string(out))
- }
-
- exe, err := os.Open(filepath.Join(e.Config.Dir, "entry"))
- if err != nil {
- t.Fatal(err)
- }
- defer exe.Close()
- bin, err := createBin(exe)
- if err != nil {
- t.Fatal(err)
}
c, err := newTestClient()
@@ -127,24 +50,17 @@
t.Fatal(err)
}
- goversion := goVersion(bin)
- // In importsOnly mode, vulnerable symbols
- // {avuln.VulnData.Vuln1, avuln.VulnData.Vuln2, bvuln.Vuln}
- // should be detected.
+ // With package scan level, all test vulnerable symbols should be detected.
wantVulns := []*testVuln{
{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"},
- }
- if goversion != "" {
- // If binary has recognizable Go version available,
- // then archive/zip.OpenReader should be detected too.
- wantVulns = append(wantVulns, &testVuln{Symbol: "OpenReader", PkgPath: "archive/zip", ModPath: "stdlib"})
+ {Symbol: "OpenReader", PkgPath: "archive/zip", ModPath: "stdlib"},
}
compareVulns(t, wantVulns, res)
- // Test the symbols (non-import mode)
+ // Test the symbols.
cfg.ScanLevel = "symbol"
res, err = binary(context.Background(), test.NewMockHandler(), bin, cfg, c)
if err != nil {
@@ -153,106 +69,12 @@
wantVulns = []*testVuln{
{Symbol: "VulnData.Vuln1", PkgPath: "golang.org/amod/avuln", ModPath: "golang.org/amod"},
- }
- if goversion != "" {
- // If binary has recognizable Go version available,
- // then archive/zip.OpenReader should be detected too.
- wantVulns = append(wantVulns, &testVuln{Symbol: "OpenReader", PkgPath: "archive/zip", ModPath: "stdlib"})
+ {Symbol: "OpenReader", PkgPath: "archive/zip", ModPath: "stdlib"},
}
compareVulns(t, wantVulns, res)
}
-func goVersion(bin *bin) string {
- return semver.GoTagToSemver(bin.GoVersion)
-}
-
-// Test58509 is supposed to test issue #58509 where a whole
-// vulnerable function is deleted from the binary so we
-// cannot detect its presence.
-//
-// Note: the issue is still not addressed and the test
-// expectations are set to fail once it gets addressed.
-func Test58509(t *testing.T) {
- testenv.NeedsGoBuild(t)
-
- vulnLib := `package bvuln
-
-%s debug = true
-
-func Vuln() {
- if debug {
- return
- }
- print("vuln")
-}`
-
- for _, tc := range []struct {
- gl string
- want []*testVuln
- }{
- {"const", nil}, // TODO(https://go.dev/issue/58509): change expectations once issue is addressed
- {"var", []*testVuln{{Symbol: "Vuln", PkgPath: "golang.org/bmod/bvuln", ModPath: "golang.org/bmod"}}},
- } {
- tc := tc
- t.Run(tc.gl, func(t *testing.T) {
- e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{
- {
- Name: "golang.org/entry",
- Files: map[string]interface{}{
- "main.go": `
- package main
-
- import (
- "golang.org/bmod/bvuln"
- )
-
- func main() {
- bvuln.Vuln()
- }
- `,
- }},
- {
- Name: "golang.org/bmod@v0.5.0",
- Files: map[string]interface{}{"bvuln/bvuln.go": fmt.Sprintf(vulnLib, tc.gl)},
- },
- })
- defer e.Cleanup()
-
- cmd := exec.Command("go", "build", "-o", "entry")
- cmd.Dir = e.Config.Dir
- cmd.Env = e.Config.Env
- out, err := cmd.CombinedOutput()
- if err != nil || len(out) > 0 {
- t.Fatalf("failed to build the binary %v %v", err, string(out))
- }
-
- exe, err := os.Open(filepath.Join(e.Config.Dir, "entry"))
- if err != nil {
- t.Fatal(err)
- }
- defer exe.Close()
- bin, err := createBin(exe)
- if err != nil {
- t.Fatal(err)
- }
-
- c, err := newTestClient()
- if err != nil {
- t.Fatal(err)
- }
-
- cfg := &govulncheck.Config{ScanLevel: "symbol"}
- res, err := binary(context.Background(), test.NewMockHandler(), bin, cfg, c)
- if err != nil {
- t.Fatal(err)
- }
-
- compareVulns(t, tc.want, res)
- })
- }
-}
-
type testVuln struct {
Symbol string
PkgPath string
diff --git a/internal/vulncheck/internal/buildinfo/additions_scan_test.go b/internal/vulncheck/internal/buildinfo/additions_scan_test.go
deleted file mode 100644
index cd80972..0000000
--- a/internal/vulncheck/internal/buildinfo/additions_scan_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-//go:build go1.18
-// +build go1.18
-
-package buildinfo
-
-import (
- "os"
- "sort"
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "golang.org/x/vuln/internal/test"
-)
-
-// testAll executes testing function ft on all valid combinations
-// of gooss and goarchs.
-func testAll(t *testing.T, gooss, goarchs []string, ft func(*testing.T, string, string)) {
- // unsupported platforms for building Go binaries.
- var unsupported = map[string]bool{
- "darwin/386": true,
- "darwin/arm": true,
- }
-
- for _, g := range gooss {
- for _, a := range goarchs {
- goos := g
- goarch := a
-
- ga := goos + "/" + goarch
- if unsupported[ga] {
- continue
- }
-
- t.Run(ga, func(t *testing.T) {
- ft(t, goos, goarch)
- })
- }
- }
-}
-
-func TestExtractPackagesAndSymbols(t *testing.T) {
- testAll(t, []string{"linux", "darwin", "windows", "freebsd"}, []string{"amd64", "386", "arm", "arm64"},
- func(t *testing.T, goos, goarch string) {
- binary, done := test.GoBuild(t, "testdata", "", false, "GOOS", goos, "GOARCH", goarch)
- defer done()
-
- f, err := os.Open(binary)
- if err != nil {
- t.Fatal(err)
- }
- defer f.Close()
- _, syms, _, err := ExtractPackagesAndSymbols(f)
- if err != nil {
- t.Fatal(err)
- }
-
- got := mainSortedSymbols(syms)
- want := []Symbol{
- {"main", "f"},
- {"main", "g"},
- {"main", "main"},
- }
-
- if diff := cmp.Diff(want, got); diff != "" {
- t.Errorf("(-want,+got):%s", diff)
- }
- })
-}
-
-// mainSortedSymbols gets symbols for "main" package and
-// sorts them for testing purposes.
-func mainSortedSymbols(syms []Symbol) []Symbol {
- var s []Symbol
- for _, ps := range syms {
- if ps.Pkg == "main" {
- s = append(s, ps)
- }
- }
- sort.SliceStable(s, func(i, j int) bool { return s[i].Pkg+"."+s[i].Name < s[j].Pkg+"."+s[j].Name })
- return s
-}