Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions registry-library/library/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func decompress(targetDir string, tarFile string, excludeFiles []string) error {
continue
}

target := path.Join(targetDir, filepath.Clean(header.Name))
target := CleanFilepath(targetDir, header.Name)
switch header.Typeflag {
case tar.TypeDir:
err = os.MkdirAll(target, os.FileMode(header.Mode))
Expand All @@ -122,7 +122,6 @@ func decompress(targetDir string, tarFile string, excludeFiles []string) error {
return returnedErr
}
case tar.TypeReg:
/* #nosec G304 -- target is produced using path.Join which cleans the dir path */
w, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
if err != nil {
returnedErr = multierror.Append(returnedErr, err)
Expand Down Expand Up @@ -192,3 +191,10 @@ func getHTTPClient(options RegistryOptions) *http.Client {
Timeout: overriddenTimeout,
}
}

// Cleans a child path to ensure that there is no escaping from the parent directory with the use of ../ escape methods
// Ensures that the child path is always contained and absolutely pathed from the parent
func CleanFilepath(parent string, child string)string{
target := path.Join(parent, filepath.Clean("/"+child))
return target
}
80 changes: 80 additions & 0 deletions registry-library/library/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package library
import (
"reflect"
"testing"
"strings"
)

func TestValidateStackVersionTag(t *testing.T) {
Expand Down Expand Up @@ -130,3 +131,82 @@ func TestSplitVersionFromStack(t *testing.T) {
})
}
}

func TestCleanFilepath(t *testing.T) {
tests := []struct {
name string
parentPath string
childPath string
expectedPath string
}{
{
name: "Absolute child path with leading slash",
parentPath: ".",
childPath: "/test/tmp",
expectedPath: "test/tmp",
},
{
name: "Absolute child path without leading slash",
parentPath: ".",
childPath: "test/tmp",
expectedPath: "test/tmp",
},
{
name: "Relative child path without leading slash",
parentPath: ".",
childPath: "../../../../test/tmp",
expectedPath: "test/tmp",
},
{
name: "Relative child path with leading slash",
parentPath: ".",
childPath: "/../../../../test/tmp",
expectedPath: "test/tmp",
},
{
name: "Absolute child path with leading slash and escape capabilities",
parentPath: ".",
childPath: "/home/../../../../test/tmp",
expectedPath: "test/tmp",
},
{
name: "Absolute child path with leading slash and escape capabilities (parent path not current dir)",
parentPath: "newHome/dir",
childPath: "/home/../../../../test/tmp",
expectedPath: "newHome/dir/test/tmp",
},
{
name: "Relative child path without leading slash and escape capabilities (parent path not current dir)",
parentPath: "newHome/dir",
childPath: "../home/../../../../test/tmp",
expectedPath: "newHome/dir/test/tmp",
},
{
name: "Blank child path",
parentPath: "dir",
childPath: "",
expectedPath: "dir",
},
{
name: "Child path only escape characters",
parentPath: "dir",
childPath: "../../../../../",
expectedPath: "dir",
},
{
name: "Single file as child path",
parentPath: "dir",
childPath: "test.txt",
expectedPath: "dir/test.txt",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
path:= CleanFilepath(test.parentPath, test.childPath)
if !strings.EqualFold(test.expectedPath, path) {
t.Errorf("Expected: %s, Got: %s", test.expectedPath, path)
}
})
}
}