Skip to content

Commit 9e0e42d

Browse files
authored
Merge pull request #256 from Mashimiao/validate-add-mounts-nested-check
validate: add mounts whether nested check
2 parents b2d36fa + 4dcd484 commit 9e0e42d

File tree

1 file changed

+92
-7
lines changed

1 file changed

+92
-7
lines changed

validate/validate.go

Lines changed: 92 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os"
1010
"path/filepath"
1111
"reflect"
12+
"regexp"
1213
"runtime"
1314
"strings"
1415
"syscall"
@@ -402,15 +403,40 @@ func (v *Validator) CheckMounts() (msgs []string) {
402403
return
403404
}
404405

405-
for _, mount := range v.spec.Mounts {
406-
if supportedTypes != nil {
407-
if !supportedTypes[mount.Type] {
408-
msgs = append(msgs, fmt.Sprintf("Unsupported mount type %q", mount.Type))
406+
for i, mountA := range v.spec.Mounts {
407+
if supportedTypes != nil && !supportedTypes[mountA.Type] {
408+
msgs = append(msgs, fmt.Sprintf("Unsupported mount type %q", mountA.Type))
409+
}
410+
if v.platform == "windows" {
411+
if err := pathValid(v.platform, mountA.Destination); err != nil {
412+
msgs = append(msgs, err.Error())
413+
}
414+
if err := pathValid(v.platform, mountA.Source); err != nil {
415+
msgs = append(msgs, err.Error())
416+
}
417+
} else {
418+
if err := pathValid(v.platform, mountA.Destination); err != nil {
419+
msgs = append(msgs, err.Error())
409420
}
410421
}
411-
412-
if !filepath.IsAbs(mount.Destination) {
413-
msgs = append(msgs, fmt.Sprintf("destination %v is not an absolute path", mount.Destination))
422+
for j, mountB := range v.spec.Mounts {
423+
if i == j {
424+
continue
425+
}
426+
// whether B.Desination is nested within A.Destination
427+
nested, err := nestedValid(v.platform, mountA.Destination, mountB.Destination)
428+
if err != nil {
429+
msgs = append(msgs, err.Error())
430+
continue
431+
}
432+
if nested {
433+
if v.platform == "windows" && i < j {
434+
msgs = append(msgs, fmt.Sprintf("On Windows, %v nested within %v is forbidden", mountB.Destination, mountA.Destination))
435+
}
436+
if i > j {
437+
logrus.Warnf("%v will be covered by %v", mountB.Destination, mountA.Destination)
438+
}
439+
}
414440
}
415441
}
416442

@@ -795,6 +821,65 @@ func namespaceValid(ns rspec.LinuxNamespace) bool {
795821
return true
796822
}
797823

824+
func pathValid(os, path string) error {
825+
if os == "windows" {
826+
matched, err := regexp.MatchString("^[a-zA-Z]:(\\\\[^\\\\/<>|:*?\"]+)+$", path)
827+
if err != nil {
828+
return err
829+
}
830+
if !matched {
831+
return fmt.Errorf("invalid windows path %v", path)
832+
}
833+
return nil
834+
}
835+
if !filepath.IsAbs(path) {
836+
return fmt.Errorf("%v is not an absolute path", path)
837+
}
838+
return nil
839+
}
840+
841+
// Check whether pathB is nested whithin pathA
842+
func nestedValid(os, pathA, pathB string) (bool, error) {
843+
if pathA == pathB {
844+
return false, nil
845+
}
846+
if pathA == "/" && pathB != "" {
847+
return true, nil
848+
}
849+
850+
var sep string
851+
if os == "windows" {
852+
sep = "\\"
853+
} else {
854+
sep = "/"
855+
}
856+
857+
splitedPathA := strings.Split(filepath.Clean(pathA), sep)
858+
splitedPathB := strings.Split(filepath.Clean(pathB), sep)
859+
lenA := len(splitedPathA)
860+
lenB := len(splitedPathB)
861+
862+
if lenA > lenB {
863+
if (lenA - lenB) == 1 {
864+
// if pathA is longer but not end with separator
865+
if splitedPathA[lenA-1] != "" {
866+
return false, nil
867+
}
868+
splitedPathA = splitedPathA[:lenA-1]
869+
} else {
870+
return false, nil
871+
}
872+
}
873+
874+
for i, partA := range splitedPathA {
875+
if partA != splitedPathB[i] {
876+
return false, nil
877+
}
878+
}
879+
880+
return true, nil
881+
}
882+
798883
func deviceValid(d rspec.LinuxDevice) bool {
799884
switch d.Type {
800885
case "b", "c", "u":

0 commit comments

Comments
 (0)