Skip to content

Commit

Permalink
Merge pull request aquasecurity#9 from DataDog/paulcacheux/new-dpkg-s…
Browse files Browse the repository at this point in the history
…canner-opt

memory improvements in dpkg scanner
  • Loading branch information
paulcacheux authored Jul 1, 2024
2 parents 0c355f8 + 1cebfbc commit 3090480
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 20 deletions.
58 changes: 40 additions & 18 deletions pkg/fanal/analyzer/pkg/dpkg/dpkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,34 +61,56 @@ func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis
log.Logger.Debugf("Unable to parse %q file: %s", availableFile, err)
}

required := func(path string, d fs.DirEntry) bool {
return path != availableFile
}

packageFiles := make(map[string][]string)

// parse other files
err = fsutils.WalkDir(input.FS, "var/lib/dpkg", required, func(path string, d fs.DirEntry, r io.Reader) error {
// parse list files
if a.isListFile(filepath.Split(path)) {
scanner := bufio.NewScanner(r)
systemFiles, err := a.parseDpkgInfoList(scanner)
if err != nil {
return err
// parse list files
err = fsutils.WalkDir(input.FS, infoDir, fsutils.RequiredExt(".list"), func(path string, d fs.DirEntry, r io.Reader) error {
scanner := bufio.NewScanner(r)
systemFiles, err := a.parseDpkgInfoList(scanner)
if err != nil {
return err
}
packageFiles[strings.TrimSuffix(filepath.Base(path), ".list")] = systemFiles
systemInstalledFiles = append(systemInstalledFiles, systemFiles...)
return nil
})
if err != nil && !os.IsNotExist(err) {
return nil, xerrors.Errorf("dpkg walk error: %w", err)
}

// parse root status file
parseRootStatusFile := func() ([]types.PackageInfo, error) {
f, err := input.FS.Open(statusFile)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil, nil
}
packageFiles[strings.TrimSuffix(filepath.Base(path), ".list")] = systemFiles
systemInstalledFiles = append(systemInstalledFiles, systemFiles...)
return nil
return nil, xerrors.Errorf("failed to open %s: %w", statusFile, err)
}
// parse status files
defer f.Close()

infos, err := a.parseDpkgStatus(statusFile, f, digests)
if err != nil {
return nil, xerrors.Errorf("dpkg status parse error: %w", err)
}
return infos, nil
}
rootStatusInfos, err := parseRootStatusFile()
if err != nil {
return nil, err
}
packageInfos = append(packageInfos, rootStatusInfos...)

// parse status files
err = fsutils.WalkDir(input.FS, statusDir, fsutils.RequiredAll(), func(path string, d fs.DirEntry, r io.Reader) error {
infos, err := a.parseDpkgStatus(path, r, digests)
if err != nil {
return err
}
packageInfos = append(packageInfos, infos...)
return nil
})
if err != nil {
if err != nil && !os.IsNotExist(err) {
return nil, xerrors.Errorf("dpkg walk error: %w", err)
}

Expand Down Expand Up @@ -171,7 +193,7 @@ func (a dpkgAnalyzer) parseDpkgAvailable(fsys fs.FS) (map[string]digest.Digest,
return pkgs, nil
}

// parseDpkgStatus parses /var/lib/dpkg/status or /var/lib/dpkg/status/*
// parseDpkgStatus parses /var/lib/dpkg/status or /var/lib/dpkg/status.d/*
func (a dpkgAnalyzer) parseDpkgStatus(filePath string, r io.Reader, digests map[string]digest.Digest) ([]types.PackageInfo, error) {
var pkg *types.Package
pkgs := make(map[string]*types.Package)
Expand Down
3 changes: 1 addition & 2 deletions pkg/fanal/analyzer/pkg/dpkg/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"bytes"
"io"
"net/textproto"
"strings"
)

type dpkgScanner struct {
Expand Down Expand Up @@ -42,7 +41,7 @@ func emptyLineSplit(data []byte, atEOF bool) (advance int, token []byte, err err
return 0, nil, nil
}

if i := strings.Index(string(data), "\n\n"); i >= 0 {
if i := bytes.Index(data, []byte("\n\n")); i >= 0 {
// We have a full empty line terminated block.
return i + 2, data[0:i], nil
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/utils/fsutils/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,9 @@ func RequiredFile(fileNames ...string) WalkDirRequiredFunc {
return slices.Contains(fileNames, filepath.Base(filePath))
}
}

func RequiredAll() WalkDirRequiredFunc {
return func(_ string, _ fs.DirEntry) bool {
return true
}
}

0 comments on commit 3090480

Please sign in to comment.