github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/kernel/parse_linux_kernel_module_file.go (about) 1 package kernel 2 3 import ( 4 "debug/elf" 5 "fmt" 6 "strings" 7 8 "github.com/anchore/syft/syft/artifact" 9 "github.com/anchore/syft/syft/file" 10 "github.com/anchore/syft/syft/pkg" 11 "github.com/anchore/syft/syft/pkg/cataloger/generic" 12 "github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader" 13 ) 14 15 const modinfoName = ".modinfo" 16 17 func parseLinuxKernelModuleFile(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 18 unionReader, err := unionreader.GetUnionReader(reader) 19 if err != nil { 20 return nil, nil, fmt.Errorf("unable to get union reader for file: %w", err) 21 } 22 metadata, err := parseLinuxKernelModuleMetadata(unionReader) 23 if err != nil { 24 return nil, nil, fmt.Errorf("unable to parse kernel module metadata: %w", err) 25 } 26 if metadata == nil || metadata.KernelVersion == "" { 27 return nil, nil, nil 28 } 29 30 metadata.Path = reader.Location.RealPath 31 32 return []pkg.Package{ 33 newLinuxKernelModulePackage( 34 *metadata, 35 reader.Location, 36 ), 37 }, nil, nil 38 } 39 40 func parseLinuxKernelModuleMetadata(r unionreader.UnionReader) (p *pkg.LinuxKernelModuleMetadata, err error) { 41 // filename: /lib/modules/5.15.0-1031-aws/kernel/zfs/zzstd.ko 42 // version: 1.4.5a 43 // license: Dual BSD/GPL 44 // description: ZSTD Compression for ZFS 45 // srcversion: F1F818A6E016499AB7F826E 46 // depends: spl 47 // retpoline: Y 48 // name: zzstd 49 // vermagic: 5.15.0-1031-aws SMP mod_unload modversions 50 // sig_id: PKCS#7 51 // signer: Build time autogenerated kernel key 52 // sig_key: 49:A9:55:87:90:5B:33:41:AF:C0:A7:BE:2A:71:6C:D2:CA:34:E0:AE 53 // sig_hashalgo: sha512 54 // 55 // OR 56 // 57 // filename: /home/ubuntu/eve/rootfs/lib/modules/5.10.121-linuxkit/kernel/drivers/net/wireless/realtek/rtl8821cu/8821cu.ko 58 // version: v5.4.1_28754.20180921_COEX20180712-3232 59 // author: Realtek Semiconductor Corp. 60 // description: Realtek Wireless Lan Driver 61 // license: GPL 62 // srcversion: 960CCC648A0E0369171A2C9 63 // depends: cfg80211 64 // retpoline: Y 65 // name: 8821cu 66 // vermagic: 5.10.121-linuxkit SMP mod_unload 67 p = &pkg.LinuxKernelModuleMetadata{ 68 Parameters: make(map[string]pkg.LinuxKernelModuleParameter), 69 } 70 f, err := elf.NewFile(r) 71 if err != nil { 72 return nil, err 73 } 74 defer f.Close() 75 modinfo := f.Section(modinfoName) 76 if modinfo == nil { 77 return nil, fmt.Errorf("no section %s", modinfoName) 78 } 79 b, err := modinfo.Data() 80 if err != nil { 81 return nil, fmt.Errorf("error reading secion %s: %w", modinfoName, err) 82 } 83 var ( 84 entry []byte 85 ) 86 for _, b2 := range b { 87 if b2 == 0 { 88 if err := addLinuxKernelModuleEntry(p, entry); err != nil { 89 return nil, fmt.Errorf("error parsing entry %s: %w", string(entry), err) 90 } 91 entry = []byte{} 92 continue 93 } 94 entry = append(entry, b2) 95 } 96 if err := addLinuxKernelModuleEntry(p, entry); err != nil { 97 return nil, fmt.Errorf("error parsing entry %s: %w", string(entry), err) 98 } 99 100 return p, nil 101 } 102 103 func addLinuxKernelModuleEntry(k *pkg.LinuxKernelModuleMetadata, entry []byte) error { 104 if len(entry) == 0 { 105 return nil 106 } 107 var key, value string 108 parts := strings.SplitN(string(entry), "=", 2) 109 if len(parts) > 0 { 110 key = parts[0] 111 } 112 if len(parts) > 1 { 113 value = parts[1] 114 } 115 116 switch key { 117 case "version": 118 k.Version = value 119 case "license": 120 k.License = value 121 case "author": 122 k.Author = value 123 case "name": 124 k.Name = value 125 case "vermagic": 126 k.VersionMagic = value 127 fields := strings.Fields(value) 128 if len(fields) > 0 { 129 k.KernelVersion = fields[0] 130 } 131 case "srcversion": 132 k.SourceVersion = value 133 case "description": 134 k.Description = value 135 case "parm": 136 parts := strings.SplitN(value, ":", 2) 137 if len(parts) != 2 { 138 return fmt.Errorf("invalid parm entry: %s", value) 139 } 140 if m, ok := k.Parameters[parts[0]]; !ok { 141 k.Parameters[parts[0]] = pkg.LinuxKernelModuleParameter{Description: parts[1]} 142 } else { 143 m.Description = parts[1] 144 } 145 case "parmtype": 146 parts := strings.SplitN(value, ":", 2) 147 if len(parts) != 2 { 148 return fmt.Errorf("invalid parmtype entry: %s", value) 149 } 150 if m, ok := k.Parameters[parts[0]]; !ok { 151 k.Parameters[parts[0]] = pkg.LinuxKernelModuleParameter{Type: parts[1]} 152 } else { 153 m.Type = parts[1] 154 } 155 } 156 return nil 157 }