mirror of
https://github.com/anchore/syft.git
synced 2026-11-04 00:16:38 +01:00
fix: charge the budget for compressed tar bytes that are skipped, not just kept
The tree decompression budget was only spent as entry content was stored. A compressed tar reader still decompresses whatever an entry leaves unread to reach the next header, so an excluded entry, a file/directory clash, or the rest of one over the 2 GB per-entry cap decompressed with nothing charged and no ctx check. A small `.tar.zst` could force hundreds of GB of work past the budget. - in compressed tars the rest of every regular entry is now drained through the budget, with ctx checked per chunk - zip and plain tar are unchanged: they seek past skipped entries, so those cost nothing Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -139,14 +139,21 @@ func (r *Resolver) extract(ctx context.Context, format archives.Extractor, conte
|
||||
if _, err := content.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
// a compressed tar decompresses whatever an entry leaves unread to reach the next header, so there the
|
||||
// bytes of skipped entries cost as much as kept ones. A zip or a plain tar seeks past them for free
|
||||
_, drains := format.(archives.CompressedArchive)
|
||||
err := format.Extract(ctx, content, func(_ context.Context, f archives.FileInfo) error {
|
||||
hdr, ok := r.entryHeader(f)
|
||||
if !ok || exclusions.Excludes(hdr.Name) {
|
||||
return nil
|
||||
}
|
||||
skip := !ok || exclusions.Excludes(hdr.Name)
|
||||
if !f.Mode().IsRegular() {
|
||||
if skip {
|
||||
return nil
|
||||
}
|
||||
return r.add(hdr, nil)
|
||||
}
|
||||
if skip && !drains {
|
||||
return nil
|
||||
}
|
||||
entry, err := f.Open()
|
||||
if err != nil {
|
||||
log.WithFields("entry", hdr.Name, "error", err).Trace("unable to open archive entry, skipping it")
|
||||
@@ -157,7 +164,16 @@ func (r *Resolver) extract(ctx context.Context, format archives.Extractor, conte
|
||||
log.WithFields("entry", hdr.Name, "error", err).Trace("unable to close archive entry")
|
||||
}
|
||||
}()
|
||||
return r.add(hdr, entry)
|
||||
if !skip {
|
||||
if err := r.add(hdr, entry); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !drains {
|
||||
return nil
|
||||
}
|
||||
// what add left unread (the rest of an entry over the size cap, or one skipped whole) is charged here
|
||||
return r.drain(ctx, entry)
|
||||
})
|
||||
r.finish()
|
||||
if errors.Is(err, ErrDiskLimitReached) {
|
||||
|
||||
Reference in New Issue
Block a user