From 566024fc8fd6ebacb0956de2d4caacda64db2ded Mon Sep 17 00:00:00 2001 From: Lorenzo Susini Date: Tue, 1 Aug 2023 15:12:16 +0000 Subject: [PATCH] update: allow to extract directories for asset files Signed-off-by: Lorenzo Susini --- cmd/artifact/install/install.go | 2 +- internal/follower/follower.go | 2 +- internal/utils/extract.go | 29 +++++++++++++++++++++++------ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/cmd/artifact/install/install.go b/cmd/artifact/install/install.go index 62dfd2e46..688d76c2c 100644 --- a/cmd/artifact/install/install.go +++ b/cmd/artifact/install/install.go @@ -333,7 +333,7 @@ func (o *artifactInstallOptions) RunArtifactInstall(ctx context.Context, args [] } // Extract artifact and move it to its destination directory - _, err = utils.ExtractTarGz(f, destDir) + _, err = utils.ExtractTarGz(f, destDir, result.Type) if err != nil { return fmt.Errorf("cannot extract %q to %q: %w", result.Filename, destDir, err) } diff --git a/internal/follower/follower.go b/internal/follower/follower.go index 6eed041fd..8c8a19e05 100644 --- a/internal/follower/follower.go +++ b/internal/follower/follower.go @@ -282,7 +282,7 @@ func (f *Follower) pull(ctx context.Context) (filePaths []string, res *oci.Regis } // Extract artifact and move it to its destination directory - filePaths, err = utils.ExtractTarGz(file, f.tmpDir) + filePaths, err = utils.ExtractTarGz(file, f.tmpDir, res.Type) if err != nil { return filePaths, res, fmt.Errorf("unable to extract %q to %q: %w", res.Filename, f.tmpDir, err) } diff --git a/internal/utils/extract.go b/internal/utils/extract.go index 70be8e725..93fc5ea49 100644 --- a/internal/utils/extract.go +++ b/internal/utils/extract.go @@ -23,11 +23,13 @@ import ( "os" "path/filepath" "strings" + + "github.com/falcosecurity/falcoctl/pkg/oci" ) // ExtractTarGz extracts a *.tar.gz compressed archive and moves its content to destDir. // Returns a slice containing the full path of the extracted files. -func ExtractTarGz(gzipStream io.Reader, destDir string) ([]string, error) { +func ExtractTarGz(gzipStream io.Reader, destDir string, artifactType oci.ArtifactType) ([]string, error) { var files []string uncompressedStream, err := gzip.NewReader(gzipStream) @@ -37,6 +39,7 @@ func ExtractTarGz(gzipStream io.Reader, destDir string) ([]string, error) { tarReader := tar.NewReader(uncompressedStream) + dirs := 0 for { header, err := tarReader.Next() @@ -48,14 +51,28 @@ func ExtractTarGz(gzipStream io.Reader, destDir string) ([]string, error) { return nil, err } + if strings.Contains(header.Name, "..") { + return nil, fmt.Errorf("not allowed relative path in tar archive") + } + switch header.Typeflag { case tar.TypeDir: - return nil, fmt.Errorf("unexepected dir inside the archive, expected to find only files without any tree structure") - case tar.TypeReg: - if strings.Contains(header.Name, "..") { - return nil, fmt.Errorf("not allowed relative path in tar archive") + if artifactType == oci.Plugin || artifactType == oci.Rulesfile { + return nil, fmt.Errorf("unexepected dir inside the archive, "+ + "expected to find only files without any tree structure for %q artifacts", artifactType.String()) + } else if artifactType == oci.Asset { + if dirs > 1 { + return nil, fmt.Errorf("malformed tar archive, expected to " + + "find only one directory containing all the assets files, not multiple directories") + } + destDir = filepath.Join(destDir, filepath.Clean(header.Name)) + err = os.Mkdir(destDir, header.FileInfo().Mode().Perm()) + if err != nil && !errors.Is(err, os.ErrExist) { + return nil, fmt.Errorf("unable to extract dir from the archive: %w", err) + } + dirs++ } - + case tar.TypeReg: f := filepath.Join(destDir, filepath.Clean(header.Name)) outFile, err := os.Create(filepath.Clean(f)) if err != nil {