mirror of
https://github.com/anchore/syft.git
synced 2026-11-01 23:16:30 +01:00
fix: improved Python binary detection (#1648)
This commit is contained in:
@@ -2,6 +2,9 @@ package binary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
@@ -10,6 +13,7 @@ import (
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||
@@ -49,12 +53,12 @@ type classifier struct {
|
||||
}
|
||||
|
||||
// evidenceMatcher is a function called to catalog Packages that match some sort of evidence
|
||||
type evidenceMatcher func(classifier classifier, reader source.LocationReadCloser) ([]pkg.Package, error)
|
||||
type evidenceMatcher func(resolver source.FileResolver, classifier classifier, location source.Location) ([]pkg.Package, error)
|
||||
|
||||
func evidenceMatchers(matchers ...evidenceMatcher) evidenceMatcher {
|
||||
return func(classifier classifier, reader source.LocationReadCloser) ([]pkg.Package, error) {
|
||||
return func(resolver source.FileResolver, classifier classifier, location source.Location) ([]pkg.Package, error) {
|
||||
for _, matcher := range matchers {
|
||||
match, err := matcher(classifier, reader)
|
||||
match, err := matcher(resolver, classifier, location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -68,12 +72,12 @@ func evidenceMatchers(matchers ...evidenceMatcher) evidenceMatcher {
|
||||
|
||||
func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate string) evidenceMatcher {
|
||||
pat := regexp.MustCompile(fileNamePattern)
|
||||
return func(classifier classifier, reader source.LocationReadCloser) ([]pkg.Package, error) {
|
||||
if !pat.MatchString(reader.RealPath) {
|
||||
return func(resolver source.FileResolver, classifier classifier, location source.Location) ([]pkg.Package, error) {
|
||||
if !pat.MatchString(location.RealPath) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
filepathNamedGroupValues := internal.MatchNamedCaptureGroups(pat, reader.RealPath)
|
||||
filepathNamedGroupValues := internal.MatchNamedCaptureGroups(pat, location.RealPath)
|
||||
|
||||
tmpl, err := template.New("").Parse(contentTemplate)
|
||||
if err != nil {
|
||||
@@ -91,26 +95,70 @@ func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate stri
|
||||
return nil, fmt.Errorf("unable to compile rendered regex=%q: %w", patternBuf.String(), err)
|
||||
}
|
||||
|
||||
contents, err := getContents(reader)
|
||||
contents, err := getContents(resolver, location)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
|
||||
}
|
||||
|
||||
matchMetadata := internal.MatchNamedCaptureGroups(tmplPattern, string(contents))
|
||||
return singlePackage(classifier, reader, matchMetadata), nil
|
||||
return singlePackage(classifier, location, matchMetadata), nil
|
||||
}
|
||||
}
|
||||
|
||||
func fileContentsVersionMatcher(pattern string) evidenceMatcher {
|
||||
pat := regexp.MustCompile(pattern)
|
||||
return func(classifier classifier, reader source.LocationReadCloser) ([]pkg.Package, error) {
|
||||
contents, err := getContents(reader)
|
||||
return func(resolver source.FileResolver, classifier classifier, location source.Location) ([]pkg.Package, error) {
|
||||
contents, err := getContents(resolver, location)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
|
||||
}
|
||||
|
||||
matchMetadata := internal.MatchNamedCaptureGroups(pat, string(contents))
|
||||
return singlePackage(classifier, reader, matchMetadata), nil
|
||||
return singlePackage(classifier, location, matchMetadata), nil
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher evidenceMatcher) evidenceMatcher {
|
||||
pat := regexp.MustCompile(sharedLibraryPattern)
|
||||
return func(resolver source.FileResolver, classifier classifier, location source.Location) (packages []pkg.Package, _ error) {
|
||||
libs, err := sharedLibraries(resolver, location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, lib := range libs {
|
||||
if !pat.MatchString(lib) {
|
||||
continue
|
||||
}
|
||||
|
||||
locations, err := resolver.FilesByGlob("**/" + lib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, libraryLication := range locations {
|
||||
pkgs, err := sharedLibraryMatcher(resolver, classifier, libraryLication)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
// set the source binary as the first location
|
||||
locationSet := source.NewLocationSet(location)
|
||||
locationSet.Add(p.Locations.ToSlice()...)
|
||||
p.Locations = locationSet
|
||||
meta, _ := p.Metadata.(pkg.BinaryMetadata)
|
||||
p.Metadata = pkg.BinaryMetadata{
|
||||
Matches: append([]pkg.ClassifierMatch{
|
||||
{
|
||||
Classifier: classifier.Class,
|
||||
Location: location,
|
||||
},
|
||||
}, meta.Matches...),
|
||||
}
|
||||
packages = append(packages, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
return packages, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +170,7 @@ func mustPURL(purl string) packageurl.PackageURL {
|
||||
return p
|
||||
}
|
||||
|
||||
func singlePackage(classifier classifier, reader source.LocationReadCloser, matchMetadata map[string]string) []pkg.Package {
|
||||
func singlePackage(classifier classifier, location source.Location, matchMetadata map[string]string) []pkg.Package {
|
||||
version, ok := matchMetadata["version"]
|
||||
if !ok {
|
||||
return nil
|
||||
@@ -140,7 +188,7 @@ func singlePackage(classifier classifier, reader source.LocationReadCloser, matc
|
||||
p := pkg.Package{
|
||||
Name: classifier.Package,
|
||||
Version: version,
|
||||
Locations: source.NewLocationSet(reader.Location),
|
||||
Locations: source.NewLocationSet(location),
|
||||
Type: pkg.BinaryPkg,
|
||||
CPEs: cpes,
|
||||
FoundBy: catalogerName,
|
||||
@@ -149,7 +197,7 @@ func singlePackage(classifier classifier, reader source.LocationReadCloser, matc
|
||||
Matches: []pkg.ClassifierMatch{
|
||||
{
|
||||
Classifier: classifier.Class,
|
||||
Location: reader.Location,
|
||||
Location: location,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -174,8 +222,13 @@ func singlePackage(classifier classifier, reader source.LocationReadCloser, matc
|
||||
return []pkg.Package{p}
|
||||
}
|
||||
|
||||
func getContents(reader source.LocationReadCloser) ([]byte, error) {
|
||||
unionReader, err := unionreader.GetUnionReader(reader.ReadCloser)
|
||||
func getContents(resolver source.FileResolver, location source.Location) ([]byte, error) {
|
||||
reader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unionReader, err := unionreader.GetUnionReader(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get union reader for file: %w", err)
|
||||
}
|
||||
@@ -195,3 +248,43 @@ func singleCPE(cpeString string) []cpe.CPE {
|
||||
cpe.Must(cpeString),
|
||||
}
|
||||
}
|
||||
|
||||
// sharedLibraries returns a list of all shared libraries found within a binary, currently
|
||||
// supporting: elf, macho, and windows pe
|
||||
func sharedLibraries(resolver source.FileResolver, location source.Location) ([]string, error) {
|
||||
contents, err := getContents(resolver, location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := bytes.NewReader(contents)
|
||||
|
||||
e, _ := elf.NewFile(r)
|
||||
if e != nil {
|
||||
symbols, err := e.ImportedLibraries()
|
||||
if err != nil {
|
||||
log.Debugf("unable to read elf binary at: %s -- %s", location.RealPath, err)
|
||||
}
|
||||
return symbols, nil
|
||||
}
|
||||
|
||||
m, _ := macho.NewFile(r)
|
||||
if m != nil {
|
||||
symbols, err := m.ImportedLibraries()
|
||||
if err != nil {
|
||||
log.Debugf("unable to read macho binary at: %s -- %s", location.RealPath, err)
|
||||
}
|
||||
return symbols, nil
|
||||
}
|
||||
|
||||
p, _ := pe.NewFile(r)
|
||||
if p != nil {
|
||||
symbols, err := p.ImportedLibraries()
|
||||
if err != nil {
|
||||
log.Debugf("unable to read pe binary at: %s -- %s", location.RealPath, err)
|
||||
}
|
||||
return symbols, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user