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