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