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  }