github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/pkg/cataloger/binary/cataloger.go (about)

     1  /*
     2  Package binary provides a concrete Cataloger implementations for surfacing possible packages based on signatures found within binary files.
     3  */
     4  package binary
     5  
     6  import (
     7  	"github.com/anchore/syft/syft/artifact"
     8  	"github.com/anchore/syft/syft/file"
     9  	"github.com/anchore/syft/syft/pkg"
    10  	"github.com/lineaje-labs/syft/internal/log"
    11  )
    12  
    13  const catalogerName = "binary-cataloger"
    14  
    15  func NewCataloger() pkg.Cataloger {
    16  	return &Cataloger{}
    17  }
    18  
    19  // Cataloger is the cataloger responsible for surfacing evidence of a very limited set of binary files,
    20  // which have been identified by the classifiers. The Cataloger is _NOT_ a place to catalog any and every
    21  // binary, but rather the specific set that has been curated to be important, predominantly related to toolchain-
    22  // related runtimes like Python, Go, Java, or Node. Some exceptions can be made for widely-used binaries such
    23  // as busybox.
    24  type Cataloger struct{}
    25  
    26  // Name returns a string that uniquely describes the Cataloger
    27  func (c Cataloger) Name() string {
    28  	return catalogerName
    29  }
    30  
    31  // Catalog is given an object to resolve file references and content, this function returns any discovered Packages
    32  // after analyzing the catalog source.
    33  func (c Cataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
    34  	var packages []pkg.Package
    35  	var relationships []artifact.Relationship
    36  
    37  	for _, cls := range defaultClassifiers {
    38  		log.WithFields("classifier", cls.Class).Trace("cataloging binaries")
    39  		newPkgs, err := catalog(resolver, cls)
    40  		if err != nil {
    41  			log.WithFields("error", err, "classifier", cls.Class).Warn("unable to catalog binary package: %w", err)
    42  			continue
    43  		}
    44  	newPackages:
    45  		for i := range newPkgs {
    46  			newPkg := &newPkgs[i]
    47  			for j := range packages {
    48  				p := &packages[j]
    49  				// consolidate identical packages found in different locations or by different classifiers
    50  				if packagesMatch(p, newPkg) {
    51  					mergePackages(p, newPkg)
    52  					continue newPackages
    53  				}
    54  			}
    55  			packages = append(packages, *newPkg)
    56  		}
    57  	}
    58  
    59  	return packages, relationships, nil
    60  }
    61  
    62  // mergePackages merges information from the extra package into the target package
    63  func mergePackages(target *pkg.Package, extra *pkg.Package) {
    64  	// add the locations
    65  	target.Locations.Add(extra.Locations.ToSlice()...)
    66  	// update the metadata to indicate which classifiers were used
    67  	meta, _ := target.Metadata.(pkg.BinarySignature)
    68  	if m, ok := extra.Metadata.(pkg.BinarySignature); ok {
    69  		meta.Matches = append(meta.Matches, m.Matches...)
    70  	}
    71  	target.Metadata = meta
    72  }
    73  
    74  func catalog(resolver file.Resolver, cls classifier) (packages []pkg.Package, err error) {
    75  	locations, err := resolver.FilesByGlob(cls.FileGlob)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	for _, location := range locations {
    80  		pkgs, err := cls.EvidenceMatcher(resolver, cls, location)
    81  		if err != nil {
    82  			return nil, err
    83  		}
    84  		packages = append(packages, pkgs...)
    85  	}
    86  	return packages, nil
    87  }
    88  
    89  // packagesMatch returns true if the binary packages "match" based on basic criteria
    90  func packagesMatch(p1 *pkg.Package, p2 *pkg.Package) bool {
    91  	if p1.Name != p2.Name ||
    92  		p1.Version != p2.Version ||
    93  		p1.Language != p2.Language ||
    94  		p1.Type != p2.Type {
    95  		return false
    96  	}
    97  
    98  	return true
    99  }