diff --git a/validate/validate.go b/validate/validate.go index 1030099df..35ddd281d 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -13,7 +13,6 @@ import ( "regexp" "runtime" "strings" - "syscall" "unicode" "unicode/utf8" @@ -641,6 +640,38 @@ func (v *Validator) CheckLinux() (errs error) { errs = multierror.Append(errs, fmt.Errorf("on Linux, hostname requires a new UTS namespace to be specified as well")) } + errs = multierror.Append(errs, v.CheckLinuxDevices()) + + if v.spec.Linux.Resources != nil { + errs = multierror.Append(errs, v.CheckLinuxResources()) + } + + for _, maskedPath := range v.spec.Linux.MaskedPaths { + if !strings.HasPrefix(maskedPath, "/") { + errs = multierror.Append(errs, + specerror.NewError( + specerror.MaskedPathsAbs, + fmt.Errorf("maskedPath %v is not an absolute path", maskedPath), + rspec.Version)) + } + } + + for _, readonlyPath := range v.spec.Linux.ReadonlyPaths { + if !strings.HasPrefix(readonlyPath, "/") { + errs = multierror.Append(errs, + specerror.NewError( + specerror.ReadonlyPathsAbs, + fmt.Errorf("readonlyPath %v is not an absolute path", readonlyPath), + rspec.Version)) + } + } + + return +} + +// CheckLinuxDevices checks v.spec.LinuxDevices. +func (v *Validator) CheckLinuxDevices() (errs error) { + logrus.Debugf("check linux.devices") // Linux devices validation devList := make(map[string]bool) devTypeList := make(map[string]bool) @@ -654,6 +685,7 @@ func (v *Validator) CheckLinux() (errs error) { errs = multierror.Append(errs, fmt.Errorf("device %s is duplicated", device.Path)) } else { var rootfsPath string + // FIXME: use osFilepath for this if filepath.IsAbs(v.spec.Root.Path) { rootfsPath = v.spec.Root.Path } else { @@ -666,61 +698,7 @@ func (v *Validator) CheckLinux() (errs error) { } else if err != nil { errs = multierror.Append(errs, err) } else { - fStat, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - errs = multierror.Append(errs, specerror.NewError(specerror.DevicesAvailable, - fmt.Errorf("cannot determine state for device %s", device.Path), rspec.Version)) - 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") { - errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, - fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) - 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 { - errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, - fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) - continue - } - } - if device.FileMode != nil { - expectedPerm := *device.FileMode & os.ModePerm - actualPerm := fi.Mode() & os.ModePerm - if expectedPerm != actualPerm { - errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, - fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) - continue - } - } - if device.UID != nil { - if *device.UID != fStat.Uid { - errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, - fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) - continue - } - } - if device.GID != nil { - if *device.GID != fStat.Gid { - errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, - fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) - continue - } - } + errs = multierror.Append(errs, v.checkPosixFilesystemDevice(&device, fi)) } } @@ -739,31 +717,7 @@ func (v *Validator) CheckLinux() (errs error) { } } - if v.spec.Linux.Resources != nil { - errs = multierror.Append(errs, v.CheckLinuxResources()) - } - - for _, maskedPath := range v.spec.Linux.MaskedPaths { - if !strings.HasPrefix(maskedPath, "/") { - errs = multierror.Append(errs, - specerror.NewError( - specerror.MaskedPathsAbs, - fmt.Errorf("maskedPath %v is not an absolute path", maskedPath), - rspec.Version)) - } - } - - for _, readonlyPath := range v.spec.Linux.ReadonlyPaths { - if !strings.HasPrefix(readonlyPath, "/") { - errs = multierror.Append(errs, - specerror.NewError( - specerror.ReadonlyPathsAbs, - fmt.Errorf("readonlyPath %v is not an absolute path", readonlyPath), - rspec.Version)) - } - } - - return + return errs } // CheckLinuxResources checks v.spec.Linux.Resources diff --git a/validate/validate_posix.go b/validate/validate_posix.go new file mode 100644 index 000000000..d2c264f9e --- /dev/null +++ b/validate/validate_posix.go @@ -0,0 +1,67 @@ +// +build linux solaris + +package validate + +import ( + "fmt" + "os" + "syscall" + + "github.com/hashicorp/go-multierror" + rspec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/specerror" +) + +func (v *Validator) checkPosixFilesystemDevice(device *rspec.LinuxDevice, info os.FileInfo) (err error) { + fStat, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return multierror.Append(err, specerror.NewError(specerror.DevicesAvailable, + fmt.Errorf("cannot determine state for device %s", device.Path), rspec.Version)) + } + 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") { + err = multierror.Append(err, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + } + 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 { + err = multierror.Append(err, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + } + } + if device.FileMode != nil { + expectedPerm := *device.FileMode & os.ModePerm + actualPerm := info.Mode() & os.ModePerm + if expectedPerm != actualPerm { + err = multierror.Append(err, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + } + } + if device.UID != nil { + if *device.UID != fStat.Uid { + err = multierror.Append(err, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + } + } + if device.GID != nil { + if *device.GID != fStat.Gid { + err = multierror.Append(err, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + } + } + + return err +} diff --git a/validate/validate_windows.go b/validate/validate_windows.go new file mode 100644 index 000000000..f87479c7c --- /dev/null +++ b/validate/validate_windows.go @@ -0,0 +1,12 @@ +package validate + +import ( + "runtime" + + "github.com/sirupsen/logrus" +) + +func (v *Validator) checkPosixFilesystemDevice(device *rspec.LinuxDevice, info os.FileInfo) (err error) { + logrus.Warnf("checking POSIX devices is not supported on %s", runtime.GOOS) + return nil +}