Skip to content

Commit

Permalink
pkg/utils: try to avoid zipslip in tar extraction.
Browse files Browse the repository at this point in the history
Don't use os.MkdirAll in tar extraction. Expect the archive
to be self-contained in this regard. Sanitize directory and
file paths during archive extraction, trying to ensure that
entries do not escape the created top-level directory.

Signed-off-by: Krisztian Litkey <[email protected]>
  • Loading branch information
klihub committed Aug 14, 2023
1 parent 7c42836 commit 82461ae
Showing 1 changed file with 36 additions and 7 deletions.
43 changes: 36 additions & 7 deletions pkg/utils/tar.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ package utils
import (
"archive/tar"
"compress/bzip2"
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
)

func UncompressTbz2(archive string, dir string) error {
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("can't create directory %s for archive %s", dir, archive)
}

file, err := os.Open(archive)
if err != nil {
return err
Expand All @@ -40,14 +46,22 @@ func UncompressTbz2(archive string, dir string) error {
return err
}
if header.Typeflag == tar.TypeDir {
target, err := cleanTargetPath(dir, header.Name)
if err != nil {
return fmt.Errorf("refusing archive %s: %w", archive, err)
}
// Create a directory.
err = os.MkdirAll(path.Join(dir, header.Name), 0755)
err = os.Mkdir(target, 0755)
if err != nil {
return err
}
} else if header.Typeflag == tar.TypeReg {
target, err := cleanTargetPath(dir, header.Name)
if err != nil {
return fmt.Errorf("refusing archive %s: %w", archive, err)
}
// Create a regular file.
targetFile, err := os.Create(path.Join(dir, header.Name))
targetFile, err := os.Create(target)
if err != nil {
return err
}
Expand All @@ -57,15 +71,30 @@ func UncompressTbz2(archive string, dir string) error {
return err
}
} else if header.Typeflag == tar.TypeSymlink {
// Create a symlink and all the directories it needs.
err = os.MkdirAll(path.Dir(path.Join(dir, header.Name)), 0755)
dst, err := cleanTargetPath(dir, header.Name)
if err != nil {
return err
return fmt.Errorf("refusing archive %s: %w", archive, err)
}
err := os.Symlink(header.Linkname, path.Join(dir, header.Name))
// Create a symlink.
err = os.Symlink(header.Linkname, dst)
if err != nil {
return err
}
}
}
}

func cleanTargetPath(dir, entry string) (string, error) {
target := filepath.Join(dir, entry)
rel, err := filepath.Rel(dir, target)
if err != nil {
return "", fmt.Errorf("failed to sanitize archive target %s for dir %s: %v",
entry, dir, err)
}
if rel == ".." || strings.HasPrefix(rel, "../") {
return "", fmt.Errorf("archive target %s would escape base dir %s (%s)",
entry, dir, rel)
}

return target, nil
}

0 comments on commit 82461ae

Please sign in to comment.