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