mirror of
https://github.com/anchore/syft.git
synced 2026-11-03 07:56:36 +01:00
feat: report unknowns in sbom (#2998)
Signed-off-by: Keith Zantow <kzantow@gmail.com> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
co-authored by
Alex Goodman
parent
4d7ed9f749
commit
ccbee94b87
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/mimetype"
|
||||
"github.com/anchore/syft/internal/unknown"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/internal/unionreader"
|
||||
@@ -45,6 +46,8 @@ func NewCataloger(cfg Config) *Cataloger {
|
||||
}
|
||||
|
||||
func (i *Cataloger) Catalog(resolver file.Resolver) (map[file.Coordinates]file.Executable, error) {
|
||||
var errs error
|
||||
|
||||
locs, err := resolver.FilesByMIMEType(i.config.MIMETypes...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get file locations for binaries: %w", err)
|
||||
@@ -61,7 +64,10 @@ func (i *Cataloger) Catalog(resolver file.Resolver) (map[file.Coordinates]file.E
|
||||
for _, loc := range locs {
|
||||
prog.AtomicStage.Set(loc.Path())
|
||||
|
||||
exec := processExecutableLocation(loc, resolver)
|
||||
exec, err := processExecutableLocation(loc, resolver)
|
||||
if err != nil {
|
||||
errs = unknown.Append(errs, loc, err)
|
||||
}
|
||||
|
||||
if exec != nil {
|
||||
prog.Increment()
|
||||
@@ -74,30 +80,24 @@ func (i *Cataloger) Catalog(resolver file.Resolver) (map[file.Coordinates]file.E
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s executables", humanize.Comma(prog.Current())))
|
||||
prog.SetCompleted()
|
||||
|
||||
return results, nil
|
||||
return results, errs
|
||||
}
|
||||
|
||||
func processExecutableLocation(loc file.Location, resolver file.Resolver) *file.Executable {
|
||||
func processExecutableLocation(loc file.Location, resolver file.Resolver) (*file.Executable, error) {
|
||||
reader, err := resolver.FileContentsByLocation(loc)
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Warnf("unable to get file contents for %q", loc.RealPath)
|
||||
return nil
|
||||
return nil, fmt.Errorf("unable to get file contents: %w", err)
|
||||
}
|
||||
defer internal.CloseAndLogError(reader, loc.RealPath)
|
||||
|
||||
uReader, err := unionreader.GetUnionReader(reader)
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Warnf("unable to get union reader for %q", loc.RealPath)
|
||||
return nil
|
||||
return nil, fmt.Errorf("unable to get union reader: %w", err)
|
||||
}
|
||||
|
||||
exec, err := processExecutable(loc, uReader)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Warnf("unable to process executable %q", loc.RealPath)
|
||||
}
|
||||
return exec
|
||||
return processExecutable(loc, uReader)
|
||||
}
|
||||
|
||||
func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
|
||||
@@ -153,10 +153,12 @@ func processExecutable(loc file.Location, reader unionreader.UnionReader) (*file
|
||||
|
||||
format, err := findExecutableFormat(reader)
|
||||
if err != nil {
|
||||
log.Debugf("unable to determine executable kind for %v: %v", loc.RealPath, err)
|
||||
return nil, fmt.Errorf("unable to determine executable kind: %w", err)
|
||||
}
|
||||
|
||||
if format == "" {
|
||||
// this is not an "unknown", so just log -- this binary does not have parseable data in it
|
||||
log.Debugf("unable to determine executable format for %q", loc.RealPath)
|
||||
return nil, nil
|
||||
}
|
||||
@@ -165,16 +167,19 @@ func processExecutable(loc file.Location, reader unionreader.UnionReader) (*file
|
||||
|
||||
switch format {
|
||||
case file.ELF:
|
||||
if err := findELFFeatures(&data, reader); err != nil {
|
||||
if err = findELFFeatures(&data, reader); err != nil {
|
||||
log.WithFields("error", err).Tracef("unable to determine ELF features for %q", loc.RealPath)
|
||||
err = fmt.Errorf("unable to determine ELF features: %w", err)
|
||||
}
|
||||
case file.PE:
|
||||
if err := findPEFeatures(&data, reader); err != nil {
|
||||
if err = findPEFeatures(&data, reader); err != nil {
|
||||
log.WithFields("error", err).Tracef("unable to determine PE features for %q", loc.RealPath)
|
||||
err = fmt.Errorf("unable to determine PE features: %w", err)
|
||||
}
|
||||
case file.MachO:
|
||||
if err := findMachoFeatures(&data, reader); err != nil {
|
||||
if err = findMachoFeatures(&data, reader); err != nil {
|
||||
log.WithFields("error", err).Tracef("unable to determine Macho features for %q", loc.RealPath)
|
||||
err = fmt.Errorf("unable to determine Macho features: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +188,7 @@ func processExecutable(loc file.Location, reader unionreader.UnionReader) (*file
|
||||
data.ImportedLibraries = []string{}
|
||||
}
|
||||
|
||||
return &data, nil
|
||||
return &data, err
|
||||
}
|
||||
|
||||
func findExecutableFormat(reader unionreader.UnionReader) (file.ExecutableFormat, error) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/unknown"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/internal/unionreader"
|
||||
)
|
||||
@@ -20,8 +21,8 @@ func findELFFeatures(data *file.Executable, reader unionreader.UnionReader) erro
|
||||
|
||||
libs, err := f.ImportedLibraries()
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Trace("unable to read imported libraries from elf file")
|
||||
err = unknown.Joinf(err, "unable to read imported libraries from elf file: %w", err)
|
||||
libs = nil
|
||||
}
|
||||
|
||||
@@ -34,7 +35,7 @@ func findELFFeatures(data *file.Executable, reader unionreader.UnionReader) erro
|
||||
data.HasEntrypoint = elfHasEntrypoint(f)
|
||||
data.HasExports = elfHasExports(f)
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func findELFSecurityFeatures(f *elf.File) *file.ELFSecurityFeatures {
|
||||
@@ -62,7 +63,6 @@ func checkElfStackCanary(file *elf.File) *bool {
|
||||
func hasAnyDynamicSymbols(file *elf.File, symbolNames ...string) *bool {
|
||||
dynSyms, err := file.DynamicSymbols()
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Trace("unable to read dynamic symbols from elf file")
|
||||
return nil
|
||||
}
|
||||
@@ -129,7 +129,6 @@ func hasBindNowDynTagOrFlag(f *elf.File) bool {
|
||||
func hasElfDynFlag(f *elf.File, flag elf.DynFlag) bool {
|
||||
vals, err := f.DynValue(elf.DT_FLAGS)
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Trace("unable to read DT_FLAGS from elf file")
|
||||
return false
|
||||
}
|
||||
@@ -144,7 +143,6 @@ func hasElfDynFlag(f *elf.File, flag elf.DynFlag) bool {
|
||||
func hasElfDynFlag1(f *elf.File, flag elf.DynFlag1) bool {
|
||||
vals, err := f.DynValue(elf.DT_FLAGS_1)
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Trace("unable to read DT_FLAGS_1 from elf file")
|
||||
return false
|
||||
}
|
||||
@@ -203,7 +201,6 @@ func checkLLVMControlFlowIntegrity(file *elf.File) *bool {
|
||||
// look for any symbols that are functions and end with ".cfi"
|
||||
dynSyms, err := file.Symbols()
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Trace("unable to read symbols from elf file")
|
||||
return nil
|
||||
}
|
||||
@@ -225,7 +222,6 @@ var fortifyPattern = regexp.MustCompile(`__\w+_chk@.+`)
|
||||
func checkClangFortifySource(file *elf.File) *bool {
|
||||
dynSyms, err := file.Symbols()
|
||||
if err != nil {
|
||||
// TODO: known-unknowns
|
||||
log.WithFields("error", err).Trace("unable to read symbols from elf file")
|
||||
return nil
|
||||
}
|
||||
@@ -254,7 +250,7 @@ func elfHasExports(f *elf.File) bool {
|
||||
// really anything that is not marked with 'U' (undefined) is considered an export.
|
||||
symbols, err := f.DynamicSymbols()
|
||||
if err != nil {
|
||||
// TODO: known-unknowns?
|
||||
log.WithFields("error", err).Trace("unable to get ELF dynamic symbols")
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ func Test_findELFSecurityFeatures(t *testing.T) {
|
||||
name string
|
||||
fixture string
|
||||
want *file.ELFSecurityFeatures
|
||||
wantErr require.ErrorAssertionFunc
|
||||
wantStripped bool
|
||||
}{
|
||||
{
|
||||
@@ -221,6 +222,7 @@ func Test_elfHasExports(t *testing.T) {
|
||||
f, err := elf.NewFile(readerForFixture(t, tt.fixture))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, elfHasExports(f))
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/unknown"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
@@ -46,6 +47,7 @@ func NewCataloger(cfg Config) *Cataloger {
|
||||
func (i *Cataloger) Catalog(_ context.Context, resolver file.Resolver) (map[file.Coordinates]string, error) {
|
||||
results := make(map[file.Coordinates]string)
|
||||
var locations []file.Location
|
||||
var errs error
|
||||
|
||||
locations, err := resolver.FilesByGlob(i.globs...)
|
||||
if err != nil {
|
||||
@@ -59,8 +61,9 @@ func (i *Cataloger) Catalog(_ context.Context, resolver file.Resolver) (map[file
|
||||
|
||||
metadata, err := resolver.FileMetadataByLocation(location)
|
||||
if err != nil {
|
||||
errs = unknown.Append(errs, location, err)
|
||||
prog.SetError(err)
|
||||
return nil, err
|
||||
continue
|
||||
}
|
||||
|
||||
if i.skipFilesAboveSizeInBytes > 0 && metadata.Size() > i.skipFilesAboveSizeInBytes {
|
||||
@@ -69,12 +72,12 @@ func (i *Cataloger) Catalog(_ context.Context, resolver file.Resolver) (map[file
|
||||
|
||||
result, err := i.catalogLocation(resolver, location)
|
||||
if internal.IsErrPathPermission(err) {
|
||||
log.Debugf("file contents cataloger skipping - %+v", err)
|
||||
errs = unknown.Append(errs, location, fmt.Errorf("permission error reading file contents: %w", err))
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
prog.SetError(err)
|
||||
return nil, err
|
||||
errs = unknown.Append(errs, location, err)
|
||||
continue
|
||||
}
|
||||
|
||||
prog.Increment()
|
||||
@@ -87,7 +90,7 @@ func (i *Cataloger) Catalog(_ context.Context, resolver file.Resolver) (map[file
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s files", humanize.Comma(prog.Current())))
|
||||
prog.SetCompleted()
|
||||
|
||||
return results, nil
|
||||
return results, errs
|
||||
}
|
||||
|
||||
func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Location) (string, error) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/unknown"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
intCataloger "github.com/anchore/syft/syft/file/cataloger/internal"
|
||||
@@ -33,6 +34,7 @@ func NewCataloger(hashes []crypto.Hash) *Cataloger {
|
||||
func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordinates ...file.Coordinates) (map[file.Coordinates][]file.Digest, error) {
|
||||
results := make(map[file.Coordinates][]file.Digest)
|
||||
var locations []file.Location
|
||||
var errs error
|
||||
|
||||
if len(coordinates) == 0 {
|
||||
locations = intCataloger.AllRegularFiles(ctx, resolver)
|
||||
@@ -58,12 +60,14 @@ func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordin
|
||||
|
||||
if internal.IsErrPathPermission(err) {
|
||||
log.Debugf("file digests cataloger skipping %q: %+v", location.RealPath, err)
|
||||
errs = unknown.Append(errs, location, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
prog.SetError(err)
|
||||
return nil, fmt.Errorf("failed to process file %q: %w", location.RealPath, err)
|
||||
errs = unknown.Append(errs, location, err)
|
||||
continue
|
||||
}
|
||||
|
||||
prog.Increment()
|
||||
@@ -76,7 +80,7 @@ func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordin
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s files", humanize.Comma(prog.Current())))
|
||||
prog.SetCompleted()
|
||||
|
||||
return results, nil
|
||||
return results, errs
|
||||
}
|
||||
|
||||
func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Location) ([]file.Digest, error) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/unknown"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
@@ -20,6 +21,7 @@ func NewCataloger() *Cataloger {
|
||||
}
|
||||
|
||||
func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordinates ...file.Coordinates) (map[file.Coordinates]file.Metadata, error) {
|
||||
var errs error
|
||||
results := make(map[file.Coordinates]file.Metadata)
|
||||
var locations <-chan file.Location
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
@@ -34,7 +36,7 @@ func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordin
|
||||
for _, c := range coordinates {
|
||||
locs, err := resolver.FilesByPath(c.RealPath)
|
||||
if err != nil {
|
||||
log.Warn("unable to get file locations for path %q: %w", c.RealPath, err)
|
||||
errs = unknown.Append(errs, c, err)
|
||||
continue
|
||||
}
|
||||
for _, loc := range locs {
|
||||
@@ -71,7 +73,7 @@ func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordin
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s locations", humanize.Comma(prog.Current())))
|
||||
prog.SetCompleted()
|
||||
|
||||
return results, nil
|
||||
return results, errs
|
||||
}
|
||||
|
||||
func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
|
||||
|
||||
@@ -39,3 +39,7 @@ func (c Coordinates) String() string {
|
||||
}
|
||||
return fmt.Sprintf("Location<%s>", str)
|
||||
}
|
||||
|
||||
func (c Coordinates) GetCoordinates() Coordinates {
|
||||
return c
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user