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