diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 843fdbeddd..10732582c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,13 +170,15 @@ jobs: containerd-shim-runhcs-v1.exe runhcs.exe tar2ext4.exe - device-util.exe wclayer.exe + device-util.exe + ncproxy.exe + dmverity-vhd.exe grantvmgroupaccess.exe networkagent.exe + securitypolicy.exe uvmboot.exe zapdir.exe - ncproxy.exe build_gcs: runs-on: ubuntu-latest diff --git a/internal/safefile/safeopen.go b/internal/safefile/safeopen.go index 8770bf5627..6d2a14a4e6 100644 --- a/internal/safefile/safeopen.go +++ b/internal/safefile/safeopen.go @@ -340,6 +340,35 @@ func MkdirRelative(path string, root *os.File) error { return err } +// MkdirAllRelative creates each directory in the path relative to a root, failing if +// any existing intermediate path components are reparse points. +func MkdirAllRelative(path string, root *os.File) error { + pathParts := strings.Split(filepath.Clean(path), (string)(filepath.Separator)) + for index := range pathParts { + + partialPath := filepath.Join(pathParts[0 : index+1]...) + stat, err := LstatRelative(partialPath, root) + + if err != nil && os.IsNotExist(err) { + if err := MkdirRelative(partialPath, root); err != nil { + return err + } + continue + } + + if err != nil { + return err + } + + if !stat.IsDir() { + fullPath := filepath.Join(root.Name(), partialPath) + return &os.PathError{Op: "mkdir", Path: fullPath, Err: syscall.ENOTDIR} + } + } + + return nil +} + // LstatRelative performs a stat operation on a file relative to a root, failing // if any intermediate path components are reparse points. func LstatRelative(path string, root *os.File) (os.FileInfo, error) { diff --git a/internal/safefile/safeopen_admin_test.go b/internal/safefile/safeopen_admin_test.go index fba451c8f6..448dc64d97 100644 --- a/internal/safefile/safeopen_admin_test.go +++ b/internal/safefile/safeopen_admin_test.go @@ -36,6 +36,12 @@ func TestOpenRelative(t *testing.T) { t.Fatal(err) } + // Create a directory stack + err = MkdirAllRelative("dir/and/then/some/subdir", root) + if err != nil { + t.Fatal(err) + } + // Create a file in the bad root f, err = os.Create(filepath.Join(badroot.Name(), "badfile")) if err != nil { @@ -63,6 +69,13 @@ func TestOpenRelative(t *testing.T) { } t.Log(err) + // Make sure directory stacks cannot pass through a symlink + err = MkdirAllRelative("dsymlink/and/then/some/subdir", root) + if err == nil { + t.Fatal("created a directory tree through a symlink") + } + t.Log(err) + // Check again using EnsureNotReparsePointRelative err = EnsureNotReparsePointRelative("dsymlink", root) if err == nil { diff --git a/internal/wclayer/legacy.go b/internal/wclayer/legacy.go index 5d8a0773e3..3e431877f8 100644 --- a/internal/wclayer/legacy.go +++ b/internal/wclayer/legacy.go @@ -731,7 +731,7 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error { return errors.New("invalid hard link in layer") } - // Find to try the target of the link in a previously added file. If that + // Try to find the target of the link in a previously added file. If that // fails, search in parent layers. var selectedRoot *os.File if _, ok := w.addedFiles[target]; ok { diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go b/test/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go index 8770bf5627..6d2a14a4e6 100644 --- a/test/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go @@ -340,6 +340,35 @@ func MkdirRelative(path string, root *os.File) error { return err } +// MkdirAllRelative creates each directory in the path relative to a root, failing if +// any existing intermediate path components are reparse points. +func MkdirAllRelative(path string, root *os.File) error { + pathParts := strings.Split(filepath.Clean(path), (string)(filepath.Separator)) + for index := range pathParts { + + partialPath := filepath.Join(pathParts[0 : index+1]...) + stat, err := LstatRelative(partialPath, root) + + if err != nil && os.IsNotExist(err) { + if err := MkdirRelative(partialPath, root); err != nil { + return err + } + continue + } + + if err != nil { + return err + } + + if !stat.IsDir() { + fullPath := filepath.Join(root.Name(), partialPath) + return &os.PathError{Op: "mkdir", Path: fullPath, Err: syscall.ENOTDIR} + } + } + + return nil +} + // LstatRelative performs a stat operation on a file relative to a root, failing // if any intermediate path components are reparse points. func LstatRelative(path string, root *os.File) (os.FileInfo, error) { diff --git a/test/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go b/test/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go index 5d8a0773e3..3e431877f8 100644 --- a/test/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go +++ b/test/vendor/github.com/Microsoft/hcsshim/internal/wclayer/legacy.go @@ -731,7 +731,7 @@ func (w *legacyLayerWriter) AddLink(name string, target string) error { return errors.New("invalid hard link in layer") } - // Find to try the target of the link in a previously added file. If that + // Try to find the target of the link in a previously added file. If that // fails, search in parent layers. var selectedRoot *os.File if _, ok := w.addedFiles[target]; ok {