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 }