Skip to content

Commit

Permalink
Add comment
Browse files Browse the repository at this point in the history
  • Loading branch information
gammazero committed Aug 7, 2024
1 parent 4f392d5 commit 4120ad4
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 16 deletions.
34 changes: 20 additions & 14 deletions tar/extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"fmt"
"io"
"os"
fp "path/filepath"
"path/filepath"
"runtime"
"strings"
"time"
Expand Down Expand Up @@ -83,7 +83,7 @@ func (te *Extractor) Extract(reader io.Reader) error {
rootName := header.Name

Check failure

Code scanning / CodeQL

Arbitrary file write extracting an archive containing symbolic links High

Unresolved path from an archive header, which may point outside the archive root, is used in
symlink creation
.

// Get the platform-specific output path
rootOutputPath := fp.Clean(te.Path)
rootOutputPath := filepath.Clean(te.Path)
if err := validatePlatformPath(rootOutputPath); err != nil {
return err
}
Expand Down Expand Up @@ -131,7 +131,7 @@ func (te *Extractor) Extract(reader io.Reader) error {
}

// If the output path directory exists then put the file/symlink into the directory.
outputPath = fp.Join(rootOutputPath, rootName)
outputPath = filepath.Join(rootOutputPath, rootName)
}

// If an object with the target name already exists overwrite it
Expand All @@ -142,7 +142,7 @@ func (te *Extractor) Extract(reader io.Reader) error {
if err := updateMeta(outputPath, header.Mode, header.ModTime); err != nil {
return err
}
} else if err := te.extractSymlink(outputPath, header); err != nil {
} else if err := te.extractSymlink(outputPath, rootOutputPath, header); err != nil {
return err
}
default:
Expand Down Expand Up @@ -183,11 +183,11 @@ func (te *Extractor) Extract(reader io.Reader) error {
// This check should already be covered by previous validation, but may catch bugs that slip through.
// Checks if the relative path matches or exceeds the root
// We check for matching because the outputPath function strips the original root
rel, err := fp.Rel(rootOutputPath, outputPath)
rel, err := filepath.Rel(rootOutputPath, outputPath)
if err != nil || rel == "." {
return errInvalidRootMultipleRoots
}
for _, e := range strings.Split(fp.ToSlash(rel), "/") {
for _, e := range strings.Split(filepath.ToSlash(rel), "/") {
if e == ".." {
return errors.New("relative path contains '..'")
}
Expand All @@ -209,7 +209,7 @@ func (te *Extractor) Extract(reader io.Reader) error {
return err
}
case tar.TypeSymlink:
if err := te.extractSymlink(outputPath, header); err != nil {
if err := te.extractSymlink(outputPath, rootOutputPath, header); err != nil {
return err
}
default:
Expand Down Expand Up @@ -257,7 +257,7 @@ func (te *Extractor) outputPath(basePlatformPath, relativeTarPath string) (strin
if err := validatePathComponent(e); err != nil {
return "", err
}
platformPath = fp.Join(platformPath, e)
platformPath = filepath.Join(platformPath, e)

// Last element is not checked since it will be removed (if it exists) by any of the extraction functions.
// For more details see:
Expand Down Expand Up @@ -290,20 +290,25 @@ func (te *Extractor) extractDir(path string) error {
return err
}

if stat, err := os.Lstat(path); err != nil {
stat, err := os.Lstat(path)
if err != nil {
return err
} else if !stat.IsDir() {
}
if !stat.IsDir() {
return errExtractedDirToSymlink
}
return nil
}

func (te *Extractor) extractSymlink(path string, h *tar.Header) error {
func (te *Extractor) extractSymlink(path, rootPath string, h *tar.Header) error {
err := os.Remove(path)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}

// Before extracting a file or other symlink, the old path is removed to
// prevent a simlink being created that causes a subsequent extraction to
// escape the root.
err = os.Symlink(h.Linkname, path)

Check failure

Code scanning / CodeQL

Arbitrary file write extracting an archive containing symbolic links High

Unresolved path from an archive header, which may point outside the archive root, is used in
symlink creation
.
if err != nil {
return err
Expand All @@ -324,9 +329,10 @@ func (te *Extractor) extractFile(path string, r *tar.Reader) error {
return err
}

// Create a temporary file in the target directory and then rename the temporary file to the target to better deal
// with races on the file system.
base := fp.Dir(path)
// Create a temporary file in the target directory and then rename the
// temporary file to the target to better deal with races on the file
// system.
base := filepath.Dir(path)
tmpfile, err := os.CreateTemp(base, "")
if err != nil {
return err
Expand Down
5 changes: 3 additions & 2 deletions tar/extractor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,9 @@ func TestLastElementOverwrite(t *testing.T) {
&fileTarEntry{path: "root/symlink", buf: []byte("overwrite content")},
},
func(t *testing.T, extractDir string) {
// Check that outside-ref still exists but has not been
// overwritten or truncated (still size the same).
// Check that outside-ref still exists but has not been overwritten
// or truncated (still size the same). The symlink itself have been
// overwritten by the extracted file.
info, err := os.Stat(fp.Join(extractDir, "..", "outside-ref"))
assert.NoError(t, err)

Expand Down

0 comments on commit 4120ad4

Please sign in to comment.