diff --git a/cmd/oci-runtime-tool/generate.go b/cmd/oci-runtime-tool/generate.go index b8afb019b..110e49f68 100644 --- a/cmd/oci-runtime-tool/generate.go +++ b/cmd/oci-runtime-tool/generate.go @@ -13,6 +13,7 @@ import ( rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/runtime-tools/generate/seccomp" + "github.com/opencontainers/runtime-tools/utils" "github.com/urfave/cli" ) @@ -495,11 +496,10 @@ func setupSpec(g *generate.Generator, context *cli.Context) error { } if context.IsSet("linux-cpus") { - if err := uintListValid(context.String("linux-cpus")); err != nil { + if err := utils.UnitListValid(context.String("linux-cpus")); err != nil { return err - } else { - g.SetLinuxResourcesCPUCpus(context.String("linux-cpus")) } + g.SetLinuxResourcesCPUCpus(context.String("linux-cpus")) } if context.IsSet("linux-hugepage-limits-add") { @@ -521,11 +521,10 @@ func setupSpec(g *generate.Generator, context *cli.Context) error { } if context.IsSet("linux-mems") { - if err := uintListValid(context.String("linux-mems")); err != nil { + if err := utils.UnitListValid(context.String("linux-mems")); err != nil { return err - } else { - g.SetLinuxResourcesCPUMems(context.String("linux-mems")) } + g.SetLinuxResourcesCPUMems(context.String("linux-mems")) } if context.IsSet("linux-mem-limit") { diff --git a/cmd/runtimetest/main.go b/cmd/runtimetest/main.go index 0f3fd4620..db526712a 100644 --- a/cmd/runtimetest/main.go +++ b/cmd/runtimetest/main.go @@ -23,6 +23,7 @@ import ( "github.com/opencontainers/runtime-tools/cmd/runtimetest/mount" rfc2119 "github.com/opencontainers/runtime-tools/error" + "github.com/opencontainers/runtime-tools/utils" "github.com/opencontainers/runtime-tools/validate" ) @@ -162,11 +163,7 @@ func validateLinuxProcess(spec *rspec.Spec) error { } func validateCapabilities(spec *rspec.Spec) error { - last := capability.CAP_LAST_CAP - // workaround for RHEL6 which has no /proc/sys/kernel/cap_last_cap - if last == capability.Cap(63) { - last = capability.CAP_BLOCK_SUSPEND - } + last := utils.LastCap() processCaps, err := capability.NewPid(0) if err != nil { diff --git a/generate/generate.go b/generate/generate.go index dc1c8f4bd..dfda91b12 100644 --- a/generate/generate.go +++ b/generate/generate.go @@ -10,6 +10,7 @@ import ( rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate/seccomp" + "github.com/opencontainers/runtime-tools/utils" "github.com/opencontainers/runtime-tools/validate" "github.com/syndtr/gocapability/capability" ) @@ -949,7 +950,7 @@ func (g *Generator) SetupPrivileged(privileged bool) { if privileged { // Add all capabilities in privileged mode. var finalCapList []string for _, cap := range capability.List() { - if g.HostSpecific && cap > validate.LastCap() { + if g.HostSpecific && cap > utils.LastCap() { continue } finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String()))) diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 000000000..a60446fa5 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,59 @@ +package utils + +import ( + "fmt" + "strconv" + "strings" + + "github.com/syndtr/gocapability/capability" +) + +// LastCap return last cap of system +func LastCap() capability.Cap { + last := capability.CAP_LAST_CAP + // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap + if last == capability.Cap(63) { + last = capability.CAP_BLOCK_SUSPEND + } + + return last +} + +// UnitListValid checks strings whether is valid for +// cpuset.cpus and cpuset.mems, duplicates are allowed +// Supported formats: +// 1 +// 0-3 +// 0-2,1,3 +// 0-2,1-3,4 +func UnitListValid(val string) error { + if val == "" { + return nil + } + + split := strings.Split(val, ",") + errInvalidFormat := fmt.Errorf("invalid format: %s", val) + + for _, r := range split { + if !strings.Contains(r, "-") { + _, err := strconv.Atoi(r) + if err != nil { + return errInvalidFormat + } + } else { + split := strings.SplitN(r, "-", 2) + min, err := strconv.Atoi(split[0]) + if err != nil { + return errInvalidFormat + } + max, err := strconv.Atoi(split[1]) + if err != nil { + return errInvalidFormat + } + if max < min { + return errInvalidFormat + } + } + } + return nil +} diff --git a/validate/validate.go b/validate/validate.go index 628d2070d..1e4f220b7 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -17,6 +17,7 @@ import ( "github.com/blang/semver" rspec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/utils" "github.com/sirupsen/logrus" "github.com/syndtr/gocapability/capability" ) @@ -633,6 +634,20 @@ func (v *Validator) CheckLinuxResources() (msgs []string) { logrus.Debugf("check linux resources") r := v.spec.Linux.Resources + + if r.CPU != nil { + if r.CPU.Cpus != "" { + if err := utils.UnitListValid(r.CPU.Cpus); err != nil { + msgs = append(msgs, err.Error()) + } + } + if r.CPU.Mems != "" { + if err := utils.UnitListValid(r.CPU.Mems); err != nil { + msgs = append(msgs, err.Error()) + } + } + } + if r.Memory != nil { if r.Memory.Limit != nil && r.Memory.Swap != nil && uint64(*r.Memory.Limit) > uint64(*r.Memory.Swap) { msgs = append(msgs, fmt.Sprintf("Minimum memoryswap should be larger than memory limit")) @@ -641,6 +656,7 @@ func (v *Validator) CheckLinuxResources() (msgs []string) { msgs = append(msgs, fmt.Sprintf("Minimum memory limit should be larger than memory reservation")) } } + if r.Network != nil && v.HostSpecific { var exist bool interfaces, err := net.Interfaces() @@ -715,7 +731,7 @@ func CapValid(c string, hostSpecific bool) error { } for _, cap := range capability.List() { if c == fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())) { - if hostSpecific && cap > LastCap() { + if hostSpecific && cap > utils.LastCap() { return fmt.Errorf("CAP_%s is not supported on the current host", c) } isValid = true @@ -729,17 +745,6 @@ func CapValid(c string, hostSpecific bool) error { return nil } -// LastCap return last cap of system -func LastCap() capability.Cap { - last := capability.CAP_LAST_CAP - // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap - if last == capability.Cap(63) { - last = capability.CAP_BLOCK_SUSPEND - } - - return last -} - func envValid(env string) bool { items := strings.Split(env, "=") if len(items) < 2 {