mirror of
https://github.com/anchore/syft.git
synced 2026-11-03 16:06:36 +01:00
Recover from panics from the stdlib when cataloging malformed binaries (#663)
* recover from panics in stdlib binary parsing Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * add CLI test to cover regression case Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
@@ -40,12 +40,12 @@ func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []arti
|
||||
for _, location := range fileMatches {
|
||||
r, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return pkgs, nil, fmt.Errorf("failed to resolve file contents by location: %w", err)
|
||||
return pkgs, nil, fmt.Errorf("failed to resolve file contents by location=%q: %w", location.RealPath, err)
|
||||
}
|
||||
|
||||
goPkgs, err := parseGoBin(location, r)
|
||||
goPkgs, err := parseGoBin(location, r, openExe)
|
||||
if err != nil {
|
||||
log.Warnf("could not parse possible go binary: %+v", err)
|
||||
log.Warnf("could not parse possible go binary at %q: %+v", location.RealPath, err)
|
||||
}
|
||||
|
||||
internal.CloseAndLogError(r, location.RealPath)
|
||||
|
||||
@@ -2,6 +2,7 @@ package golang
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
@@ -14,19 +15,29 @@ const (
|
||||
replaceIdentifier = "=>"
|
||||
)
|
||||
|
||||
func parseGoBin(location source.Location, reader io.ReadCloser) ([]pkg.Package, error) {
|
||||
type exeOpener func(file io.ReadCloser) ([]exe, error)
|
||||
|
||||
func parseGoBin(location source.Location, reader io.ReadCloser, opener exeOpener) (pkgs []pkg.Package, err error) {
|
||||
var exes []exe
|
||||
// it has been found that there are stdlib paths within openExe that can panic. We want to prevent this behavior
|
||||
// bubbling up and halting execution. For this reason we try to recover from any panic and return an error.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("recovered from panic while parse go binary at %q: %+v", location.RealPath, r)
|
||||
}
|
||||
}()
|
||||
|
||||
// Identify if bin was compiled by go
|
||||
exes, err := openExe(reader)
|
||||
exes, err = opener(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return pkgs, err
|
||||
}
|
||||
|
||||
var pkgs []pkg.Package
|
||||
for _, x := range exes {
|
||||
goVersion, mod := findVers(x)
|
||||
pkgs = append(pkgs, buildGoPkgInfo(location, mod, goVersion, x.ArchName())...)
|
||||
}
|
||||
return pkgs, nil
|
||||
return pkgs, err
|
||||
}
|
||||
|
||||
func buildGoPkgInfo(location source.Location, mod, goVersion, arch string) []pkg.Package {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -144,17 +145,38 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
location := source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
}
|
||||
pkgs := buildGoPkgInfo(location, tt.mod, goCompiledVersion, archDetails)
|
||||
assert.Equal(t, tt.expected, pkgs)
|
||||
pkgs := buildGoPkgInfo(location, test.mod, goCompiledVersion, archDetails)
|
||||
assert.Equal(t, test.expected, pkgs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseGoBin_recoversFromPanic(t *testing.T) {
|
||||
freakOut := func(file io.ReadCloser) ([]exe, error) {
|
||||
panic("baaahhh!")
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
wantPkgs []pkg.Package
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "recovers from panic",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
pkgs, err := parseGoBin(source.NewLocation("some/path"), nil, freakOut)
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, pkgs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user