Skip to content

Commit 4ce2d83

Browse files
committed
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>
1 parent 8fa5789 commit 4ce2d83

24 files changed

+239
-333
lines changed

cmd/govulncheck/testdata/testfiles/failures/binary_fail.ct

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ $ govulncheck -mode=binary notafile --> FAIL 2
66
#####
77
# Test of passing a non-binary file to -mode=binary
88
$ govulncheck -mode=binary ${moddir}/vuln/go.mod --> FAIL 1
9-
Scanning your binary for known vulnerabilities...
10-
119
govulncheck: could not parse provided binary: unrecognized file format
1210

1311
#####

internal/vulncheck/internal/buildinfo/additions_scan.go renamed to internal/buildinfo/additions_scan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"strings"
2121

2222
"golang.org/x/tools/go/packages"
23-
"golang.org/x/vuln/internal/vulncheck/internal/gosym"
23+
"golang.org/x/vuln/internal/gosym"
2424
)
2525

2626
func debugModulesToPackagesModules(debugModules []*debug.Module) []*packages.Module {
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build go1.18
6+
// +build go1.18
7+
8+
package buildinfo
9+
10+
import (
11+
"fmt"
12+
"os"
13+
"os/exec"
14+
"path/filepath"
15+
"sort"
16+
"testing"
17+
18+
"github.com/google/go-cmp/cmp"
19+
"golang.org/x/tools/go/packages/packagestest"
20+
"golang.org/x/vuln/internal/test"
21+
"golang.org/x/vuln/internal/testenv"
22+
)
23+
24+
// testAll executes testing function ft on all valid combinations
25+
// of gooss and goarchs.
26+
func testAll(t *testing.T, gooss, goarchs []string, ft func(*testing.T, string, string)) {
27+
// unsupported platforms for building Go binaries.
28+
var unsupported = map[string]bool{
29+
"darwin/386": true,
30+
"darwin/arm": true,
31+
}
32+
33+
for _, g := range gooss {
34+
for _, a := range goarchs {
35+
goos := g
36+
goarch := a
37+
38+
ga := goos + "/" + goarch
39+
if unsupported[ga] {
40+
continue
41+
}
42+
43+
t.Run(ga, func(t *testing.T) {
44+
ft(t, goos, goarch)
45+
})
46+
}
47+
}
48+
}
49+
50+
func TestExtractPackagesAndSymbols(t *testing.T) {
51+
testAll(t, []string{"linux", "darwin", "windows", "freebsd"}, []string{"amd64", "386", "arm", "arm64"},
52+
func(t *testing.T, goos, goarch string) {
53+
binary, done := test.GoBuild(t, "testdata", "", false, "GOOS", goos, "GOARCH", goarch)
54+
defer done()
55+
56+
f, err := os.Open(binary)
57+
if err != nil {
58+
t.Fatal(err)
59+
}
60+
defer f.Close()
61+
_, syms, _, err := ExtractPackagesAndSymbols(f)
62+
if err != nil {
63+
t.Fatal(err)
64+
}
65+
66+
got := sortedSymbols("main", syms)
67+
want := []Symbol{
68+
{"main", "f"},
69+
{"main", "g"},
70+
{"main", "main"},
71+
}
72+
73+
if diff := cmp.Diff(want, got); diff != "" {
74+
t.Errorf("(-want,+got):%s", diff)
75+
}
76+
})
77+
}
78+
79+
// sortedSymbols gets symbols for pkg and
80+
// sorts them for testing purposes.
81+
func sortedSymbols(pkg string, syms []Symbol) []Symbol {
82+
var s []Symbol
83+
for _, ps := range syms {
84+
if ps.Pkg == pkg {
85+
s = append(s, ps)
86+
}
87+
}
88+
sort.SliceStable(s, func(i, j int) bool { return s[i].Pkg+"."+s[i].Name < s[j].Pkg+"."+s[j].Name })
89+
return s
90+
}
91+
92+
// Test58509 is supposed to test issue #58509 where a whole
93+
// vulnerable function is deleted from the binary so we
94+
// cannot detect its presence.
95+
//
96+
// Note: the issue is still not addressed and the test
97+
// expectations are set to fail once it gets addressed.
98+
func Test58509(t *testing.T) {
99+
testenv.NeedsGoBuild(t)
100+
101+
vulnLib := `package bvuln
102+
103+
%s debug = true
104+
105+
func Vuln() {
106+
if debug {
107+
return
108+
}
109+
print("vuln")
110+
}`
111+
112+
for _, tc := range []struct {
113+
gl string
114+
want bool
115+
}{
116+
{"const", false}, // TODO(https://go.dev/issue/58509): change expectations once issue is addressed
117+
{"var", true},
118+
} {
119+
tc := tc
120+
t.Run(tc.gl, func(t *testing.T) {
121+
e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{
122+
{
123+
Name: "golang.org/entry",
124+
Files: map[string]interface{}{
125+
"main.go": `
126+
package main
127+
128+
import (
129+
"golang.org/bmod/bvuln"
130+
)
131+
132+
func main() {
133+
bvuln.Vuln()
134+
}
135+
`,
136+
}},
137+
{
138+
Name: "golang.org/bmod@v0.5.0",
139+
Files: map[string]interface{}{"bvuln/bvuln.go": fmt.Sprintf(vulnLib, tc.gl)},
140+
},
141+
})
142+
defer e.Cleanup()
143+
144+
cmd := exec.Command("go", "build", "-o", "entry")
145+
cmd.Dir = e.Config.Dir
146+
cmd.Env = e.Config.Env
147+
out, err := cmd.CombinedOutput()
148+
if err != nil || len(out) > 0 {
149+
t.Fatalf("failed to build the binary %v %v", err, string(out))
150+
}
151+
152+
exe, err := os.Open(filepath.Join(e.Config.Dir, "entry"))
153+
if err != nil {
154+
t.Fatal(err)
155+
}
156+
defer exe.Close()
157+
158+
_, syms, _, err := ExtractPackagesAndSymbols(exe)
159+
if err != nil {
160+
t.Fatal(err)
161+
}
162+
163+
// effectively, Vuln is not optimized away from the program
164+
got := len(sortedSymbols("golang.org/bmod/bvuln", syms)) != 0
165+
if got != tc.want {
166+
t.Errorf("want %t; got %t", tc.want, got)
167+
}
168+
})
169+
}
170+
}

internal/vulncheck/internal/buildinfo/additions_stripped_122_test.go renamed to internal/buildinfo/additions_stripped_122_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestStrippedBinary(t *testing.T) {
3131
if err != nil {
3232
t.Fatal(err)
3333
}
34-
if syms != nil {
34+
if len(syms) != 0 {
3535
t.Errorf("want empty symbol table; got %v symbols", len(syms))
3636
}
3737
})

internal/vulncheck/internal/buildinfo/additions_stripped_test.go renamed to internal/buildinfo/additions_stripped_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func TestStrippedDarwin(t *testing.T) {
6060
t.Fatal(err)
6161
}
6262

63-
got := mainSortedSymbols(syms)
63+
got := sortedSymbols("main", syms)
6464
want := []Symbol{
6565
{"main", "f"},
6666
{"main", "g"},

0 commit comments

Comments
 (0)