diff --git a/pkg/action/archive.go b/pkg/action/archive.go index c94ac9e4b..c52cf1236 100644 --- a/pkg/action/archive.go +++ b/pkg/action/archive.go @@ -5,6 +5,7 @@ import ( "archive/zip" "compress/bzip2" "compress/gzip" + "compress/zlib" "context" "errors" "fmt" @@ -19,6 +20,7 @@ import ( "github.com/cavaliergopher/cpio" "github.com/cavaliergopher/rpm" "github.com/chainguard-dev/clog" + "github.com/chainguard-dev/malcontent/pkg/programkind" "github.com/egibs/go-debian/deb" @@ -225,7 +227,6 @@ func extractTar(ctx context.Context, d string, f string) error { // extractGzip extracts .gz archives. func extractGzip(ctx context.Context, d string, f string) error { logger := clog.FromContext(ctx).With("dir", d, "file", f) - logger.Debug("extracting gzip") // Check if the file is valid _, err := os.Stat(f) @@ -239,23 +240,50 @@ func extractGzip(ctx context.Context, d string, f string) error { } defer gf.Close() - gr, err := gzip.NewReader(gf) + // Determine if we're extracting a gzip- or zlib-compressed file + ft, err := programkind.File(f) if err != nil { - return fmt.Errorf("failed to create gzip reader: %w", err) + return fmt.Errorf("failed to determine file type: %w", err) } - defer gr.Close() + + logger.Debugf("extracting %s", ft.Ext) base := filepath.Base(f) target := filepath.Join(d, base[:len(base)-len(filepath.Ext(base))]) - ef, err := os.Create(target) - if err != nil { - return fmt.Errorf("failed to create extracted file: %w", err) - } - defer ef.Close() + switch ft.Ext { + case "gzip": + gr, err := gzip.NewReader(gf) + if err != nil { + return fmt.Errorf("failed to create gzip reader: %w", err) + } + defer gr.Close() - if _, err := io.Copy(ef, io.LimitReader(gr, maxBytes)); err != nil { - return fmt.Errorf("failed to copy file: %w", err) + ef, err := os.Create(target) + if err != nil { + return fmt.Errorf("failed to create extracted file: %w", err) + } + defer ef.Close() + + if _, err := io.Copy(ef, io.LimitReader(gr, maxBytes)); err != nil { + return fmt.Errorf("failed to copy file: %w", err) + } + case "Z": + zr, err := zlib.NewReader(gf) + if err != nil { + return fmt.Errorf("failed to create zlib reader: %w", err) + } + defer zr.Close() + + ef, err := os.Create(target) + if err != nil { + return fmt.Errorf("failed to create extracted file: %w", err) + } + defer ef.Close() + + if _, err := io.Copy(ef, io.LimitReader(zr, maxBytes)); err != nil { + return fmt.Errorf("failed to copy file: %w", err) + } } return nil diff --git a/pkg/programkind/programkind.go b/pkg/programkind/programkind.go index 923f9f4fa..e0fe6e153 100644 --- a/pkg/programkind/programkind.go +++ b/pkg/programkind/programkind.go @@ -18,6 +18,7 @@ import ( // file extension to MIME type, if it's a good scanning target. var supportedKind = map[string]string{ "7z": "", + "Z": "application/zlib", "asm": "", "bash": "application/x-bsh", "bat": "application/bat", @@ -39,6 +40,7 @@ var supportedKind = map[string]string{ "expect": "text/x-expect", "fish": "text/x-fish", "go": "text/x-go", + "gzip": "application/gzip", "h": "text/x-h", "hh": "text/x-h", "html": "", @@ -57,9 +59,9 @@ var supportedKind = map[string]string{ "pyc": "application/x-python-code", "rb": "text/x-ruby", "rs": "text/x-rust", - "script": "text/x-generic-script", "scpt": "application/x-applescript", "scptd": "application/x-applescript", + "script": "text/x-generic-script", "service": "text/x-systemd", "sh": "application/x-sh", "so": "application/x-sharedlib", @@ -101,6 +103,8 @@ func makeFileType(path string, ext string, mime string) *FileType { } // File detects what kind of program this file might be. +// +//nolint:cyclop // ignore complexity of 38 func File(path string) (*FileType, error) { // Follow symlinks and return cleanly if the target does not exist _, err := filepath.EvalSymlinks(path) @@ -176,6 +180,10 @@ func File(path string) (*FileType, error) { return Path(".c"), nil case strings.Contains(s, "BEAMAtU8"): return Path(".beam"), nil + case hdr[0] == '\x1f' && hdr[1] == '\x8b': + return Path(".gzip"), nil + case hdr[0] == '\x78' && hdr[1] == '\x5E': + return Path(".Z"), nil } return nil, nil }