github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/kernel/cataloger.go (about)

     1  /*
     2  Package kernel provides a concrete Cataloger implementation for linux kernel and module files.
     3  */
     4  package kernel
     5  
     6  import (
     7  	"github.com/hashicorp/go-multierror"
     8  
     9  	"github.com/anchore/syft/internal/log"
    10  	"github.com/anchore/syft/syft/artifact"
    11  	"github.com/anchore/syft/syft/file"
    12  	"github.com/anchore/syft/syft/pkg"
    13  	"github.com/anchore/syft/syft/pkg/cataloger/generic"
    14  )
    15  
    16  var _ pkg.Cataloger = (*LinuxKernelCataloger)(nil)
    17  
    18  type LinuxCatalogerConfig struct {
    19  	CatalogModules bool
    20  }
    21  
    22  type LinuxKernelCataloger struct {
    23  	cfg LinuxCatalogerConfig
    24  }
    25  
    26  func DefaultLinuxCatalogerConfig() LinuxCatalogerConfig {
    27  	return LinuxCatalogerConfig{
    28  		CatalogModules: true,
    29  	}
    30  }
    31  
    32  var kernelArchiveGlobs = []string{
    33  	"**/kernel",
    34  	"**/kernel-*",
    35  	"**/vmlinux",
    36  	"**/vmlinux-*",
    37  	"**/vmlinuz",
    38  	"**/vmlinuz-*",
    39  }
    40  
    41  var kernelModuleGlobs = []string{
    42  	"**/lib/modules/**/*.ko",
    43  }
    44  
    45  // NewLinuxKernelCataloger returns a new kernel files cataloger object.
    46  func NewLinuxKernelCataloger(cfg LinuxCatalogerConfig) *LinuxKernelCataloger {
    47  	return &LinuxKernelCataloger{
    48  		cfg: cfg,
    49  	}
    50  }
    51  
    52  func (l LinuxKernelCataloger) Name() string {
    53  	return "linux-kernel-cataloger"
    54  }
    55  
    56  func (l LinuxKernelCataloger) Catalog(resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
    57  	var allPackages []pkg.Package
    58  	var allRelationships []artifact.Relationship
    59  	var errs error
    60  
    61  	kernelPackages, kernelRelationships, err := generic.NewCataloger(l.Name()).WithParserByGlobs(parseLinuxKernelFile, kernelArchiveGlobs...).Catalog(resolver)
    62  	if err != nil {
    63  		errs = multierror.Append(errs, err)
    64  	}
    65  
    66  	allRelationships = append(allRelationships, kernelRelationships...)
    67  	allPackages = append(allPackages, kernelPackages...)
    68  
    69  	if l.cfg.CatalogModules {
    70  		modulePackages, moduleRelationships, err := generic.NewCataloger(l.Name()).WithParserByGlobs(parseLinuxKernelModuleFile, kernelModuleGlobs...).Catalog(resolver)
    71  		if err != nil {
    72  			errs = multierror.Append(errs, err)
    73  		}
    74  
    75  		allPackages = append(allPackages, modulePackages...)
    76  
    77  		moduleToKernelRelationships := createKernelToModuleRelationships(kernelPackages, modulePackages)
    78  		allRelationships = append(allRelationships, moduleRelationships...)
    79  		allRelationships = append(allRelationships, moduleToKernelRelationships...)
    80  	}
    81  
    82  	return allPackages, allRelationships, errs
    83  }
    84  
    85  func createKernelToModuleRelationships(kernelPackages, modulePackages []pkg.Package) []artifact.Relationship {
    86  	// organize kernel and module packages by kernel version
    87  	kernelPackagesByVersion := make(map[string][]*pkg.Package)
    88  	for idx, p := range kernelPackages {
    89  		kernelPackagesByVersion[p.Version] = append(kernelPackagesByVersion[p.Version], &kernelPackages[idx])
    90  	}
    91  
    92  	modulesByKernelVersion := make(map[string][]*pkg.Package)
    93  	for idx, p := range modulePackages {
    94  		m, ok := p.Metadata.(pkg.LinuxKernelModuleMetadata)
    95  		if !ok {
    96  			log.Debug("linux-kernel-module package found without metadata: %s@%s", p.Name, p.Version)
    97  			continue
    98  		}
    99  		modulesByKernelVersion[m.KernelVersion] = append(modulesByKernelVersion[m.KernelVersion], &modulePackages[idx])
   100  	}
   101  
   102  	// create relationships between kernel and modules: [module] --(depends on)--> [kernel]
   103  	// since we try to use singular directions for relationships, we'll use "dependency of" here instead:
   104  	// [kernel] --(dependency of)--> [module]
   105  	var moduleToKernelRelationships []artifact.Relationship
   106  	for kernelVersion, modules := range modulesByKernelVersion {
   107  		kps, ok := kernelPackagesByVersion[kernelVersion]
   108  		if !ok {
   109  			// it's ok if there is a module that has no installed kernel...
   110  			continue
   111  		}
   112  
   113  		// we don't know which kernel is the "right" one, so we'll create a relationship for each one
   114  		for _, kp := range kps {
   115  			for _, mp := range modules {
   116  				moduleToKernelRelationships = append(moduleToKernelRelationships, artifact.Relationship{
   117  					// note: relationships should have Package objects, not pointers
   118  					From: *kp,
   119  					To:   *mp,
   120  					Type: artifact.DependencyOfRelationship,
   121  				})
   122  			}
   123  		}
   124  	}
   125  
   126  	return moduleToKernelRelationships
   127  }