mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 10:36:45 +01:00
117 lines
3.6 KiB
Go
117 lines
3.6 KiB
Go
package golang
|
|
|
|
import (
|
|
"debug/buildinfo"
|
|
"fmt"
|
|
"io"
|
|
"runtime/debug"
|
|
|
|
"github.com/kastenhq/goversion/version"
|
|
|
|
"github.com/anchore/syft/internal/log"
|
|
"github.com/anchore/syft/internal/unknown"
|
|
"github.com/anchore/syft/syft/file"
|
|
"github.com/anchore/syft/syft/internal/unionreader"
|
|
)
|
|
|
|
type extendedBuildInfo struct {
|
|
*debug.BuildInfo
|
|
cryptoSettings []string
|
|
arch string
|
|
}
|
|
|
|
// scanFile scans file to try to report the Go and module versions.
|
|
func scanFile(location file.Location, reader unionreader.UnionReader) ([]*extendedBuildInfo, error) {
|
|
// NOTE: multiple readers are returned to cover universal binaries, which are files
|
|
// with more than one binary
|
|
readers, errs := unionreader.GetReaders(reader)
|
|
if errs != nil {
|
|
log.WithFields("error", errs).Debug("failed to open a golang binary")
|
|
return nil, fmt.Errorf("failed to open a golang binary: %w", errs)
|
|
}
|
|
|
|
var builds []*extendedBuildInfo
|
|
for _, r := range readers {
|
|
bi, err := getBuildInfo(r)
|
|
if err != nil {
|
|
log.WithFields("file", location.RealPath, "error", err).Trace("unable to read golang buildinfo")
|
|
|
|
continue
|
|
}
|
|
// it's possible the reader just isn't a go binary, in which case just skip it
|
|
if bi == nil {
|
|
continue
|
|
}
|
|
|
|
v, err := getCryptoInformation(r)
|
|
if err != nil {
|
|
log.WithFields("file", location.RealPath, "error", err).Trace("unable to read golang version info")
|
|
// don't skip this build info.
|
|
// we can still catalog packages, even if we can't get the crypto information
|
|
errs = unknown.Appendf(errs, location, "unable to read golang version info: %w", err)
|
|
}
|
|
arch := getGOARCH(bi.Settings)
|
|
if arch == "" {
|
|
arch, err = getGOARCHFromBin(r)
|
|
if err != nil {
|
|
log.WithFields("file", location.RealPath, "error", err).Trace("unable to read golang arch info")
|
|
// don't skip this build info.
|
|
// we can still catalog packages, even if we can't get the arch information
|
|
errs = unknown.Appendf(errs, location, "unable to read golang arch info: %w", err)
|
|
}
|
|
}
|
|
|
|
builds = append(builds, &extendedBuildInfo{BuildInfo: bi, cryptoSettings: v, arch: arch})
|
|
}
|
|
return builds, errs
|
|
}
|
|
|
|
func getCryptoInformation(reader io.ReaderAt) ([]string, error) {
|
|
v, err := version.ReadExeFromReader(reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return getCryptoSettingsFromVersion(v), nil
|
|
}
|
|
|
|
func getCryptoSettingsFromVersion(v version.Version) []string {
|
|
cryptoSettings := []string{}
|
|
if v.StandardCrypto {
|
|
cryptoSettings = append(cryptoSettings, "standard-crypto")
|
|
}
|
|
if v.BoringCrypto {
|
|
cryptoSettings = append(cryptoSettings, "boring-crypto")
|
|
}
|
|
if v.FIPSOnly {
|
|
cryptoSettings = append(cryptoSettings, "crypto/tls/fipsonly")
|
|
}
|
|
return cryptoSettings
|
|
}
|
|
|
|
func getBuildInfo(r io.ReaderAt) (bi *debug.BuildInfo, err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
// this can happen in cases where a malformed binary is passed in can be initially parsed, but not
|
|
// used without error later down the line. This is the case with :
|
|
// https://github.com/llvm/llvm-project/blob/llvmorg-15.0.6/llvm/test/Object/Inputs/macho-invalid-dysymtab-bad-size
|
|
err = fmt.Errorf("recovered from panic: %v", r)
|
|
}
|
|
}()
|
|
bi, err = buildinfo.Read(r)
|
|
|
|
// note: the stdlib does not export the error we need to check for
|
|
if err != nil {
|
|
if err.Error() == "not a Go executable" {
|
|
// since the cataloger can only select executables and not distinguish if they are a go-compiled
|
|
// binary, we should not show warnings/logs in this case. For this reason we nil-out err here.
|
|
err = nil
|
|
return
|
|
}
|
|
// in this case we could not read the or parse the file, but not explicitly because it is not a
|
|
// go-compiled binary (though it still might be).
|
|
return
|
|
}
|
|
return
|
|
}
|