Skip to content

Commit

Permalink
ROX-12238: Add node analysis package (#911)
Browse files Browse the repository at this point in the history
  • Loading branch information
jvdm authored Sep 9, 2022
1 parent c2f1f75 commit ce27aff
Show file tree
Hide file tree
Showing 15 changed files with 697 additions and 83 deletions.
8 changes: 4 additions & 4 deletions cmd/clair/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/stackrox/rox/pkg/utils"
"github.com/stackrox/scanner/api"
"github.com/stackrox/scanner/database"
"github.com/stackrox/scanner/pkg/tarutil"
"github.com/stackrox/scanner/pkg/analyzer"
"github.com/stackrox/scanner/pkg/updater"
"gopkg.in/yaml.v2"
)
Expand Down Expand Up @@ -64,9 +64,9 @@ func DefaultConfig() Config {
GRPCPort: 8443,
},
LogLevel: "info",
MaxExtractableFileSizeMB: tarutil.DefaultMaxExtractableFileSizeMB,
MaxELFExecutableFileSizeMB: tarutil.DefaultMaxELFExecutableFileSizeMB,
MaxImageFileReaderBufferSizeMB: tarutil.DefaultMaxLazyReaderBufferSizeMB,
MaxExtractableFileSizeMB: analyzer.DefaultMaxExtractableFileSizeMB,
MaxELFExecutableFileSizeMB: analyzer.DefaultMaxELFExecutableFileSizeMB,
MaxImageFileReaderBufferSizeMB: analyzer.DefaultMaxLazyReaderBufferSizeMB,
CentralEndpoint: "https://central.stackrox.svc",
SensorEndpoint: "https://sensor.stackrox.svc",
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/clair/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"time"

"github.com/stackrox/scanner/api"
"github.com/stackrox/scanner/pkg/tarutil"
"github.com/stackrox/scanner/pkg/analyzer"
"github.com/stretchr/testify/assert"
)

Expand All @@ -23,7 +23,7 @@ func TestLoadConfig(t *testing.T) {
}, cfg.API)

assert.Equal(t, 5*time.Minute, cfg.Updater.Interval)
assert.Equal(t, int64(tarutil.DefaultMaxExtractableFileSizeMB), cfg.MaxExtractableFileSizeMB)
assert.Equal(t, int64(analyzer.DefaultMaxExtractableFileSizeMB), cfg.MaxExtractableFileSizeMB)
assert.Equal(t, int64(400), cfg.MaxELFExecutableFileSizeMB)
assert.Equal(t, int64(150), cfg.MaxImageFileReaderBufferSizeMB)
assert.Equal(t, "https://central.stackrox.svc", cfg.CentralEndpoint)
Expand Down
8 changes: 4 additions & 4 deletions cmd/clair/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ import (
"github.com/stackrox/scanner/cpe/nvdtoolscache"
"github.com/stackrox/scanner/database"
k8scache "github.com/stackrox/scanner/k8s/cache"
"github.com/stackrox/scanner/pkg/analyzer"
"github.com/stackrox/scanner/pkg/clairify/metrics"
"github.com/stackrox/scanner/pkg/clairify/server"
"github.com/stackrox/scanner/pkg/env"
"github.com/stackrox/scanner/pkg/formatter"
"github.com/stackrox/scanner/pkg/ioutils"
"github.com/stackrox/scanner/pkg/repo2cpe"
"github.com/stackrox/scanner/pkg/tarutil"
"github.com/stackrox/scanner/pkg/updater"
"github.com/stackrox/scanner/pkg/version"
"golang.org/x/sys/unix"
Expand Down Expand Up @@ -227,19 +227,19 @@ func main() {

// Set the max extractable file size from the config.
if config.MaxExtractableFileSizeMB > 0 {
tarutil.SetMaxExtractableFileSize(config.MaxExtractableFileSizeMB * 1024 * 1024)
analyzer.SetMaxExtractableFileSize(config.MaxExtractableFileSizeMB * 1024 * 1024)
log.Infof("Max extractable file size set to %d MB", config.MaxExtractableFileSizeMB)
}

// Set the max ELF executable file size from the config.
if config.MaxELFExecutableFileSizeMB > 0 {
tarutil.SetMaxELFExecutableFileSize(config.MaxELFExecutableFileSizeMB * 1024 * 1024)
analyzer.SetMaxELFExecutableFileSize(config.MaxELFExecutableFileSizeMB * 1024 * 1024)
log.Infof("Max ELF executable file size set to %d MB", config.MaxELFExecutableFileSizeMB)
}

// Set the max lazy reader buffer size from the config.
if config.MaxImageFileReaderBufferSizeMB > 0 {
tarutil.SetMaxLazyReaderBufferSize(config.MaxImageFileReaderBufferSizeMB * 1024 * 1024)
analyzer.SetMaxLazyReaderBufferSize(config.MaxImageFileReaderBufferSizeMB * 1024 * 1024)
log.Infof("Max image file reader buffer size set to %d MB", config.MaxImageFileReaderBufferSizeMB)
}

Expand Down
5 changes: 3 additions & 2 deletions localdev/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/stackrox/scanner/cpe/nvdtoolscache"
"github.com/stackrox/scanner/database"
"github.com/stackrox/scanner/ext/imagefmt"
"github.com/stackrox/scanner/pkg/analyzer"
"github.com/stackrox/scanner/pkg/component"
"github.com/stackrox/scanner/pkg/tarutil"
"github.com/stackrox/scanner/singletons/requiredfilenames"
Expand Down Expand Up @@ -78,8 +79,8 @@ func analyzeLocalImage(path string) {

// Extract
var matcher manifestMatcher
tarutil.SetMaxExtractableFileSize(1024 * 1024 * 1024)
tarutil.SetMaxELFExecutableFileSize(1024 * 1024 * 1024)
analyzer.SetMaxExtractableFileSize(1024 * 1024 * 1024)
analyzer.SetMaxELFExecutableFileSize(1024 * 1024 * 1024)
filemap, err := tarutil.ExtractFiles(f, &matcher)
if err != nil {
panic(err)
Expand Down
67 changes: 65 additions & 2 deletions pkg/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,79 @@ import (
"github.com/stackrox/scanner/pkg/elf"
)

const (
// DefaultMaxELFExecutableFileSizeMB is the default value for the max ELF executable file we analyze.
DefaultMaxELFExecutableFileSizeMB = 800

// DefaultMaxLazyReaderBufferSizeMB is the default maximum lazy reader buffer size. Any file data beyond this
// limit is backed by temporary files on disk.
DefaultMaxLazyReaderBufferSizeMB = 100

// DefaultMaxExtractableFileSizeMB is the default value for the max extractable file size.
DefaultMaxExtractableFileSizeMB = 200

// ElfHeaderSize is the size of an ELF header based on https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html.
ElfHeaderSize = 16
)

var (
maxExtractableFileSize int64 = DefaultMaxExtractableFileSizeMB * 1024 * 1024
maxELFExecutableFileSize int64 = DefaultMaxELFExecutableFileSizeMB * 1024 * 1024
maxLazyReaderBufferSize int64 = DefaultMaxLazyReaderBufferSizeMB * 1024 * 1024
)

// SetMaxExtractableFileSize sets the max extractable file size. It is NOT
// thread-safe, and callers must ensure that it is called only when no scans are
// in progress (ex: during initialization). See comments on the
// maxExtractableFileSize variable for more details on its purpose.
func SetMaxExtractableFileSize(val int64) {
maxExtractableFileSize = val
}

// GetMaxExtractableFileSize returns the maximum size of a single file within a
// tarball that will be extracted. This protects against malicious files that may
// be used in an attempt to perform a Denial of Service attack.
func GetMaxExtractableFileSize() int64 {
return maxExtractableFileSize
}

// GetMaxLazyReaderBufferSize returns the maximum lazy reader buffer size. Any
// file data beyond this limit is backed by temporary files on disk.
func GetMaxLazyReaderBufferSize() int64 {
return maxLazyReaderBufferSize
}

// SetMaxLazyReaderBufferSize sets the max lazy reader buffer size. It is NOT
// thread-safe, and callers must ensure that it is called only when no scans are
// in progress (ex: during initialization). See comments on the
// maxLazyReaderBufferSize variable for more details on its purpose.
func SetMaxLazyReaderBufferSize(val int64) {
maxLazyReaderBufferSize = val
}

// GetMaxELFExecutableFileSize returns the maximum size of an ELF executable file
// tarball that will be analyzed.
func GetMaxELFExecutableFileSize() int64 {
return maxELFExecutableFileSize
}

// SetMaxELFExecutableFileSize sets the max ELF executable file size. It is NOT
// thread-safe, and callers must ensure that it is called only when no scans are
// in progress (ex: during initialization). See comments on the
// maxELFExecutableFileSize variable for more details on its purpose.
func SetMaxELFExecutableFileSize(val int64) {
maxELFExecutableFileSize = val
}

// Analyzer defines the functions for analyzing images and extracting the components present in them.
type Analyzer interface {
ProcessFile(filePath string, fi os.FileInfo, contents io.ReaderAt) []*component.Component
}

// Files stores information on a sub-set of files being analyzed from an image.
// Files stores information on a sub-set of files being analyzed.
// It provides methods to retrieve information from individual files, or list
// them based on some prefix.
type Files interface {

// Get returns the data about a file if it exists, otherwise set exists to false.
Get(path string) (data FileData, exists bool)

Expand Down
6 changes: 4 additions & 2 deletions pkg/analyzer/analyzertest/fake_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@ type FakeFile interface {
}

// NewFakeFile creates a new fake file from the given path and contents.
func NewFakeFile(fullPath string, contents []byte) FakeFile {
func NewFakeFile(fullPath string, contents []byte, mode os.FileMode) FakeFile {
return fakeFile{
fullPath: fullPath,
contents: contents,
mode: mode,
}
}

type fakeFile struct {
fullPath string
contents []byte
mode os.FileMode
}

func (f fakeFile) FullPath() string {
Expand All @@ -45,7 +47,7 @@ func (f fakeFile) Name() string {
}

func (f fakeFile) Mode() os.FileMode {
return 0644
return f.mode
}

func (f fakeFile) IsDir() bool {
Expand Down
2 changes: 1 addition & 1 deletion pkg/analyzer/gem/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func TestMatching(t *testing.T) {
a := Analyzer()
f := analyzertest.NewFakeFile("usr/local/bundle/specifications/rails-4.2.5.1.gemspec", []byte(validRailsSpec))
f := analyzertest.NewFakeFile("usr/local/bundle/specifications/rails-4.2.5.1.gemspec", []byte(validRailsSpec), 0644)
cs := a.ProcessFile(f.FullPath(), f.FileInfo(), f.Contents())
assert.Len(t, cs, 1)
}
Loading

0 comments on commit ce27aff

Please sign in to comment.