From 97b2e0d3afc0291b8cf012241b0fee1c95802766 Mon Sep 17 00:00:00 2001 From: Ma Shimiao Date: Fri, 30 Dec 2016 11:29:32 +0800 Subject: [PATCH 1/2] validate: enhance linux devices validation duplicated device path is invalid duplicated type and major:minor is not recommended Signed-off-by: Ma Shimiao --- validate/validate.go | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/validate/validate.go b/validate/validate.go index 53a6fc4f8..1a5a1dce7 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -386,9 +386,47 @@ func (v *Validator) CheckLinux() (msgs []string) { msgs = append(msgs, fmt.Sprintf("On Linux, hostname requires a new UTS namespace to be specified as well")) } + // Linux devices validation + devList := make(map[string]bool) + typeList := make(map[string]bool) for index := 0; index < len(v.spec.Linux.Devices); index++ { - if !deviceValid(v.spec.Linux.Devices[index]) { - msgs = append(msgs, fmt.Sprintf("device %v is invalid.", v.spec.Linux.Devices[index])) + device := v.spec.Linux.Devices[index] + if !deviceValid(device) { + msgs = append(msgs, fmt.Sprintf("device %v is invalid.", device)) + } + + if _, exists := devList[device.Path]; exists { + msgs = append(msgs, fmt.Sprintf("device %s is duplicated", device.Path)) + } else { + var rootfsPath string + if filepath.IsAbs(v.spec.Root.Path) { + rootfsPath = v.spec.Root.Path + } else { + rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path) + } + absPath := filepath.Join(rootfsPath, device.Path) + _, err := os.Stat(absPath) + if os.IsNotExist(err) { + devList[device.Path] = true + } else if err != nil { + msgs = append(msgs, err.Error()) + } else { + msgs = append(msgs, fmt.Sprintf("%s already exists in filesystem", device.Path)) + } + } + + // unify u->c when comparing, they are synonyms + var devID string + if device.Type == "u" { + devID = fmt.Sprintf("%s:%d:%d", "c", device.Major, device.Minor) + } else { + devID = fmt.Sprintf("%s:%d:%d", device.Type, device.Major, device.Minor) + } + + if _, exists := typeList[devID]; exists { + logrus.Warnf("type:%s, major:%d and minor:%d for linux devices is duplicated", device.Type, device.Major, device.Minor) + } else { + typeList[devID] = true } } From 119353e66c9474d597eb981732f3c925bee8119a Mon Sep 17 00:00:00 2001 From: Ma Shimiao Date: Mon, 13 Feb 2017 16:25:48 +0800 Subject: [PATCH 2/2] validate: add unmatched device validation Signed-off-by: Ma Shimiao --- validate/validate.go | 53 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/validate/validate.go b/validate/validate.go index 1a5a1dce7..72ad49420 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -9,6 +9,7 @@ import ( "path/filepath" "reflect" "strings" + "syscall" "unicode" "unicode/utf8" @@ -405,13 +406,61 @@ func (v *Validator) CheckLinux() (msgs []string) { rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path) } absPath := filepath.Join(rootfsPath, device.Path) - _, err := os.Stat(absPath) + fi, err := os.Stat(absPath) if os.IsNotExist(err) { devList[device.Path] = true } else if err != nil { msgs = append(msgs, err.Error()) } else { - msgs = append(msgs, fmt.Sprintf("%s already exists in filesystem", device.Path)) + fStat, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + msgs = append(msgs, fmt.Sprintf("cannot determine state for device %s", device.Path)) + continue + } + var devType string + switch fStat.Mode & syscall.S_IFMT { + case syscall.S_IFCHR: + devType = "c" + case syscall.S_IFBLK: + devType = "b" + case syscall.S_IFIFO: + devType = "p" + default: + devType = "unmatched" + } + if devType != device.Type || (devType == "c" && device.Type == "u") { + msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path)) + continue + } + if devType != "p" { + dev := fStat.Rdev + major := (dev >> 8) & 0xfff + minor := (dev & 0xff) | ((dev >> 12) & 0xfff00) + if int64(major) != device.Major || int64(minor) != device.Minor { + msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path)) + continue + } + } + if device.FileMode != nil { + expectedPerm := *device.FileMode & os.ModePerm + actualPerm := fi.Mode() & os.ModePerm + if expectedPerm != actualPerm { + msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path)) + continue + } + } + if device.UID != nil { + if *device.UID != fStat.Uid { + msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path)) + continue + } + } + if device.GID != nil { + if *device.GID != fStat.Gid { + msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path)) + continue + } + } } }