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:
@@ -2,6 +2,7 @@ package archive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -61,6 +62,27 @@ func (r *Resolver) put(b *blob, content io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// drain reads the rest of a streaming entry without keeping it, charging the decompression budget for
|
||||
// every byte, so skipping an entry is not a way around the budget. A read error ends the drain quietly;
|
||||
// the archive reader reports a broken stream at the next entry.
|
||||
func (r *Resolver) drain(ctx context.Context, content io.Reader) error {
|
||||
if r.chunk == nil {
|
||||
r.chunk = make([]byte, copyChunkSize)
|
||||
}
|
||||
for {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := content.Read(r.chunk)
|
||||
if n > 0 && !r.budget.take(int64(n)) {
|
||||
return errBudgetSpent
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write appends p to b: into memory while the memory limit admits it, otherwise into the spill file
|
||||
// after everything held in memory is moved there first.
|
||||
func (r *Resolver) write(b *blob, p []byte) error {
|
||||
|
||||
Reference in New Issue
Block a user