Skip to content

Commit

Permalink
add kernel handler
Browse files Browse the repository at this point in the history
Signed-off-by: Avi Deitcher <avi@deitcher.net>
  • Loading branch information
deitch committed Mar 24, 2023
1 parent 9fd5322 commit 1520164
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.3
github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8
github.com/anchore/stereoscope v0.0.0-20230317134707-7928713c391e
github.com/deitch/magic v0.0.0-20230323094151-ad691daf393c
github.com/docker/docker v23.0.1+incompatible
github.com/google/go-containerregistry v0.14.0
github.com/google/licensecheck v0.3.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deitch/magic v0.0.0-20230323094151-ad691daf393c h1:oV9G+Jq+pW7pll/BWcZjbWB9RpNsJQ7v9ynrW6Z6tE8=
github.com/deitch/magic v0.0.0-20230323094151-ad691daf393c/go.mod h1:D5iaOhreaX/4N2s6RVZ7N1HQmqCatksnJHtatAdeq3Q=
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
Expand Down
43 changes: 43 additions & 0 deletions syft/pkg/cataloger/binary/classifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
"github.com/anchore/syft/syft/source"
"github.com/deitch/magic/pkg/magic"
)

var emptyPURL = packageurl.PackageURL{}
Expand Down Expand Up @@ -124,6 +125,48 @@ func fileContentsVersionMatcher(pattern string) evidenceMatcher {
}
}

type versionFinder func([]string) string

func fileTypeMatcher(filetype string, finder versionFinder) evidenceMatcher {
return func(resolver source.FileResolver, classifier classifier, location source.Location) ([]pkg.Package, error) {
reader, err := resolver.FileContentsByLocation(location)
if err != nil {
return nil, err
}
unionReader, err := unionreader.GetUnionReader(reader)
if err != nil {
return nil, fmt.Errorf("unable to get union reader for file: %w", err)
}
magicType, err := magic.GetType(unionReader)
if err != nil {
return nil, fmt.Errorf("unable to get magic type for file: %w", err)
}
if len(magicType) < 1 || magicType[0] != filetype {
return nil, nil
}
var version string
if finder != nil {
version = finder(magicType)
}
matchMetadata := map[string]string{
"version": version,
}

return singlePackage(classifier, location, matchMetadata), nil
}
}

func prefixVersionFinder(prefix string) versionFinder {
return func(magicType []string) string {
for _, t := range magicType {
if strings.HasPrefix(t, prefix) {
return strings.TrimPrefix(t, prefix)
}
}
return ""
}
}

//nolint:gocognit
func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher evidenceMatcher) evidenceMatcher {
pat := regexp.MustCompile(sharedLibraryPattern)
Expand Down
3 changes: 3 additions & 0 deletions syft/pkg/cataloger/cataloger.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/haskell"
"github.com/anchore/syft/syft/pkg/cataloger/java"
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
"github.com/anchore/syft/syft/pkg/cataloger/php"
"github.com/anchore/syft/syft/pkg/cataloger/portage"
"github.com/anchore/syft/syft/pkg/cataloger/python"
Expand Down Expand Up @@ -85,6 +86,7 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
binary.NewCataloger(),
elixir.NewMixLockCataloger(),
erlang.NewRebarLockCataloger(),
kernel.NewKernelCataloger(cfg.Kernel()),
}, cfg.Catalogers)
}

Expand Down Expand Up @@ -121,6 +123,7 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
binary.NewCataloger(),
elixir.NewMixLockCataloger(),
erlang.NewRebarLockCataloger(),
kernel.NewKernelCataloger(cfg.Kernel()),
}, cfg.Catalogers)
}

Expand Down
6 changes: 6 additions & 0 deletions syft/pkg/cataloger/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package cataloger
import (
"github.com/anchore/syft/syft/pkg/cataloger/golang"
"github.com/anchore/syft/syft/pkg/cataloger/java"
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
)

type Config struct {
Search SearchConfig
Golang golang.GoCatalogerOpts
KernelOpts kernel.KernelCatalogerOpts
Catalogers []string
Parallelism int
}
Expand All @@ -29,3 +31,7 @@ func (c Config) Java() java.Config {
func (c Config) Go() golang.GoCatalogerOpts {
return c.Golang
}

func (c Config) Kernel() kernel.KernelCatalogerOpts {
return c.KernelOpts
}
34 changes: 34 additions & 0 deletions syft/pkg/cataloger/kernel/cataloger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Package kernel provides a concrete Cataloger implementation for linux kernel and module files.
*/
package kernel

import (
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)

type KernelCatalogerOpts struct {
FilenameAppends []string
}

var kernelFiles = []string{
"kernel",
"kernel-*",
"vmlinux",
"vmlinux-*",
"vmlinuz",
"vmlinuz-*",
}

// NewKernelCataloger returns a new kernel files cataloger object.
func NewKernelCataloger(opts KernelCatalogerOpts) *generic.Cataloger {
var fileList []string
for _, file := range kernelFiles {
fileList = append(fileList, "**/"+file)
}
for _, file := range opts.FilenameAppends {
fileList = append(fileList, "**/"+file)
}
return generic.NewCataloger("linux-kernel-cataloger").
WithParserByGlobs(parseKernelFile, fileList...)
}
7 changes: 7 additions & 0 deletions syft/pkg/cataloger/kernel/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kernel

const (
linuxKernelName = "Linux kernel"
linuxKernelVersionPrefix = "version "
packageName = "linux-kernel"
)
27 changes: 27 additions & 0 deletions syft/pkg/cataloger/kernel/package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package kernel

import (
"strings"

"github.com/anchore/packageurl-go"
)

// packageURL returns the PURL for the specific Kernel package (see https://github.com/package-url/purl-spec)
func packageURL(name, version string) string {
var namespace string

fields := strings.SplitN(name, "/", 2)
if len(fields) > 1 {
namespace = fields[0]
name = fields[1]
}

return packageurl.NewPackageURL(
packageName,
namespace,
name,
version,
nil,
"",
).ToString()
}
96 changes: 96 additions & 0 deletions syft/pkg/cataloger/kernel/parse_kernel_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package kernel

import (
"fmt"
"strconv"
"strings"

"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
"github.com/anchore/syft/syft/source"
"github.com/deitch/magic/pkg/magic"
)

func parseKernelFile(resolver source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
unionReader, err := unionreader.GetUnionReader(reader)
if err != nil {
return nil, nil, fmt.Errorf("unable to get union reader for file: %w", err)
}
magicType, err := magic.GetType(unionReader)
if err != nil {
return nil, nil, fmt.Errorf("unable to get magic type for file: %w", err)
}
if len(magicType) < 1 || magicType[0] != linuxKernelName {
return nil, nil, nil
}
metadata := parseKernelMetadata(magicType)
if metadata.Version == "" {
return nil, nil, nil
}
p := pkg.Package{
Name: packageName,
Version: metadata.ExtendedVersion,
PURL: packageURL(packageName, metadata.Version),
Type: pkg.KernelPkg,
MetadataType: pkg.KernelPackageMetadataType,
Metadata: metadata,
}

p.SetID()
return []pkg.Package{p}, nil, nil
}

func parseKernelMetadata(magicType []string) (p pkg.KernelPackageMetadata) {
// Linux kernel x86 boot executable bzImage,
// version 5.10.121-linuxkit (root@buildkitsandbox) #1 SMP Fri Dec 2 10:35:42 UTC 2022,
// RO-rootFS,
// swap_dev 0XA,
// Normal VGA
for _, t := range magicType {
switch {
case strings.HasPrefix(t, "x86 "):
p.Architecture = "x86"
case strings.Contains(t, "ARM64 "):
p.Architecture = "arm64"
case strings.Contains(t, "ARM "):
p.Architecture = "arm"
case t == "bzImage":
p.Format = "bzImage"
case t == "zImage":
p.Format = "zImage"
case strings.HasPrefix(t, "version "):
p.ExtendedVersion = strings.TrimPrefix(t, "version ")
fields := strings.Fields(p.ExtendedVersion)
if len(fields) > 0 {
p.Version = fields[0]
}
case strings.Contains(t, "rootFS") && strings.HasPrefix(t, "RW-"):
p.RWRootFS = true
case strings.HasPrefix(t, "swap_dev "):
swapDevStr := strings.TrimPrefix(t, "swap_dev ")
swapDev, err := strconv.ParseInt(swapDevStr, 16, 32)
if err != nil {
log.Warnf("unable to parse swap device: %s", err)
continue
}
p.SwapDevice = int(swapDev)
case strings.HasPrefix(t, "root_dev "):
rootDevStr := strings.TrimPrefix(t, "root_dev ")
rootDev, err := strconv.ParseInt(rootDevStr, 16, 32)
if err != nil {
log.Warnf("unable to parse root device: %s", err)
continue
}
p.SwapDevice = int(rootDev)
case strings.Contains(t, "VGA") || strings.Contains(t, "Video"):
p.VideoMode = t
}
}
return
}

// PURL: mustPURL("pkg:generic/linux-kernel@version"),
// CPEs: singleCPE("cpe:2.3:a:linux-kernel:kernel:*:*:*:*:*:*:*:*"),
16 changes: 16 additions & 0 deletions syft/pkg/kernel_package_metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package pkg

// KernelPackageMetadata represents all captured data for a Linux kernel
type KernelPackageMetadata struct {
Name string `mapstructure:"name" json:"name"`
Architecture string `mapstructure:"architecture" json:"architecture"`
Version string `mapstructure:"version" json:"version"`
ExtendedVersion string `mapstructure:"extendedVersion" json:"extendedVersion,omitempty"`
BuildTime string `mapstructure:"buildTime" json:"buildTime,omitempty"`
Author string `mapstructure:"author" json:"author,omitempty"`
Format string `mapstructure:"format" json:"format,omitempty"`
RWRootFS bool `mapstructure:"rwRootFS" json:"rwRootFS,omitempty"`
SwapDevice int `mapstructure:"swapDevice" json:"swapDevice,omitempty"`
RootDevice int `mapstructure:"rootDevice" json:"rootDevice,omitempty"`
VideoMode string `mapstructure:"videoMode" json:"videoMode,omitempty"`
}
3 changes: 3 additions & 0 deletions syft/pkg/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
HackageMetadataType MetadataType = "HackageMetadataType"
JavaMetadataType MetadataType = "JavaMetadata"
KbPackageMetadataType MetadataType = "KbPackageMetadata"
KernelPackageMetadataType MetadataType = "KernelPackageMetadata"
MixLockMetadataType MetadataType = "MixLockMetadataType"
NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata"
NpmPackageLockJSONMetadataType MetadataType = "NpmPackageLockJsonMetadata"
Expand Down Expand Up @@ -53,6 +54,7 @@ var AllMetadataTypes = []MetadataType{
HackageMetadataType,
JavaMetadataType,
KbPackageMetadataType,
KernelPackageMetadataType,
MixLockMetadataType,
NpmPackageJSONMetadataType,
NpmPackageLockJSONMetadataType,
Expand Down Expand Up @@ -81,6 +83,7 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
JavaMetadataType: reflect.TypeOf(JavaMetadata{}),
KbPackageMetadataType: reflect.TypeOf(KbPackageMetadata{}),
KernelPackageMetadataType: reflect.TypeOf(KernelPackageMetadata{}),
MixLockMetadataType: reflect.TypeOf(MixLockMetadata{}),
NpmPackageJSONMetadataType: reflect.TypeOf(NpmPackageJSONMetadata{}),
NpmPackageLockJSONMetadataType: reflect.TypeOf(NpmPackageLockJSONMetadata{}),
Expand Down
6 changes: 6 additions & 0 deletions syft/pkg/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
JavaPkg Type = "java-archive"
JenkinsPluginPkg Type = "jenkins-plugin"
KbPkg Type = "msrc-kb"
KernelPkg Type = "linux-kernel"
NpmPkg Type = "npm"
PhpComposerPkg Type = "php-composer"
PortagePkg Type = "portage"
Expand All @@ -51,6 +52,7 @@ var AllPkgs = []Type{
JavaPkg,
JenkinsPluginPkg,
KbPkg,
KernelPkg,
NpmPkg,
PhpComposerPkg,
PortagePkg,
Expand Down Expand Up @@ -86,6 +88,8 @@ func (t Type) PackageURLType() string {
return packageurl.TypeHackage
case JavaPkg, JenkinsPluginPkg:
return packageurl.TypeMaven
case KernelPkg:
return "linux-kernel"
case PhpComposerPkg:
return packageurl.TypeComposer
case PythonPkg:
Expand Down Expand Up @@ -151,6 +155,8 @@ func TypeByName(name string) Type {
return PortagePkg
case packageurl.TypeHex:
return HexPkg
case "linux-kernel":
return KernelPkg
default:
return UnknownPkg
}
Expand Down

0 comments on commit 1520164

Please sign in to comment.