github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/pkg/cataloger/kernel/parse_linux_kernel_file.go (about)

     1  package kernel
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/deitch/magic/pkg/magic"
     9  	"github.com/nextlinux/gosbom/gosbom/artifact"
    10  	"github.com/nextlinux/gosbom/gosbom/file"
    11  	"github.com/nextlinux/gosbom/gosbom/pkg"
    12  	"github.com/nextlinux/gosbom/gosbom/pkg/cataloger/generic"
    13  	"github.com/nextlinux/gosbom/gosbom/pkg/cataloger/internal/unionreader"
    14  	"github.com/nextlinux/gosbom/internal/log"
    15  )
    16  
    17  const linuxKernelMagicName = "Linux kernel"
    18  
    19  func parseLinuxKernelFile(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]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  	magicType, err := magic.GetType(unionReader)
    25  	if err != nil {
    26  		return nil, nil, fmt.Errorf("unable to get magic type for file: %w", err)
    27  	}
    28  	if len(magicType) < 1 || magicType[0] != linuxKernelMagicName {
    29  		return nil, nil, nil
    30  	}
    31  	metadata := parseLinuxKernelMetadata(magicType)
    32  	if metadata.Version == "" {
    33  		return nil, nil, nil
    34  	}
    35  
    36  	return []pkg.Package{
    37  		newLinuxKernelPackage(
    38  			metadata,
    39  			reader.Location,
    40  		),
    41  	}, nil, nil
    42  }
    43  
    44  func parseLinuxKernelMetadata(magicType []string) (p pkg.LinuxKernelMetadata) {
    45  	// Linux kernel x86 boot executable bzImage,
    46  	// version 5.10.121-linuxkit (root@buildkitsandbox) #1 SMP Fri Dec 2 10:35:42 UTC 2022,
    47  	// RO-rootFS,
    48  	// swap_dev 0XA,
    49  	// Normal VGA
    50  	for _, t := range magicType {
    51  		switch {
    52  		case strings.HasPrefix(t, "x86 "):
    53  			p.Architecture = "x86"
    54  		case strings.Contains(t, "ARM64 "):
    55  			p.Architecture = "arm64"
    56  		case strings.Contains(t, "ARM "):
    57  			p.Architecture = "arm"
    58  		case t == "bzImage":
    59  			p.Format = "bzImage"
    60  		case t == "zImage":
    61  			p.Format = "zImage"
    62  		case strings.HasPrefix(t, "version "):
    63  			p.ExtendedVersion = strings.TrimPrefix(t, "version ")
    64  			fields := strings.Fields(p.ExtendedVersion)
    65  			if len(fields) > 0 {
    66  				p.Version = fields[0]
    67  			}
    68  		case strings.Contains(t, "rootFS") && strings.HasPrefix(t, "RW-"):
    69  			p.RWRootFS = true
    70  		case strings.HasPrefix(t, "swap_dev "):
    71  			swapDevStr := strings.TrimPrefix(t, "swap_dev ")
    72  			swapDev, err := strconv.ParseInt(swapDevStr, 16, 32)
    73  			if err != nil {
    74  				log.Warnf("unable to parse swap device: %s", err)
    75  				continue
    76  			}
    77  			p.SwapDevice = int(swapDev)
    78  		case strings.HasPrefix(t, "root_dev "):
    79  			rootDevStr := strings.TrimPrefix(t, "root_dev ")
    80  			rootDev, err := strconv.ParseInt(rootDevStr, 16, 32)
    81  			if err != nil {
    82  				log.Warnf("unable to parse root device: %s", err)
    83  				continue
    84  			}
    85  			p.SwapDevice = int(rootDev)
    86  		case strings.Contains(t, "VGA") || strings.Contains(t, "Video"):
    87  			p.VideoMode = t
    88  		}
    89  	}
    90  	return p
    91  }