Vendor containerd 2386062 and runtime-tools e29f3ca.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu
2017-07-31 17:32:17 +00:00
parent 73748840da
commit a4f7f7127b
360 changed files with 54116 additions and 28629 deletions

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"io"
"os"
"runtime"
"strings"
rspec "github.com/opencontainers/runtime-spec/specs-go"
@@ -35,15 +34,11 @@ type ExportOptions struct {
func New() Generator {
spec := rspec.Spec{
Version: rspec.Version,
Platform: rspec.Platform{
OS: runtime.GOOS,
Arch: runtime.GOARCH,
},
Root: rspec.Root{
Root: &rspec.Root{
Path: "",
Readonly: false,
},
Process: rspec.Process{
Process: &rspec.Process{
Terminal: false,
User: rspec.User{},
Args: []string{
@@ -136,7 +131,7 @@ func New() Generator {
"CAP_AUDIT_WRITE",
},
},
Rlimits: []rspec.LinuxRlimit{
Rlimits: []rspec.POSIXRlimit{
{
Type: "RLIMIT_NOFILE",
Hard: uint64(1024),
@@ -308,13 +303,13 @@ func (g *Generator) SetVersion(version string) {
// SetRootPath sets g.spec.Root.Path.
func (g *Generator) SetRootPath(path string) {
g.initSpec()
g.initSpecRoot()
g.spec.Root.Path = path
}
// SetRootReadonly sets g.spec.Root.Readonly.
func (g *Generator) SetRootReadonly(b bool) {
g.initSpec()
g.initSpecRoot()
g.spec.Root.Readonly = b
}
@@ -346,57 +341,45 @@ func (g *Generator) RemoveAnnotation(key string) {
delete(g.spec.Annotations, key)
}
// SetPlatformOS sets g.spec.Process.OS.
func (g *Generator) SetPlatformOS(os string) {
g.initSpec()
g.spec.Platform.OS = os
}
// SetPlatformArch sets g.spec.Platform.Arch.
func (g *Generator) SetPlatformArch(arch string) {
g.initSpec()
g.spec.Platform.Arch = arch
}
// SetProcessUID sets g.spec.Process.User.UID.
func (g *Generator) SetProcessUID(uid uint32) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.User.UID = uid
}
// SetProcessGID sets g.spec.Process.User.GID.
func (g *Generator) SetProcessGID(gid uint32) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.User.GID = gid
}
// SetProcessCwd sets g.spec.Process.Cwd.
func (g *Generator) SetProcessCwd(cwd string) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.Cwd = cwd
}
// SetProcessNoNewPrivileges sets g.spec.Process.NoNewPrivileges.
func (g *Generator) SetProcessNoNewPrivileges(b bool) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.NoNewPrivileges = b
}
// SetProcessTerminal sets g.spec.Process.Terminal.
func (g *Generator) SetProcessTerminal(b bool) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.Terminal = b
}
// SetProcessApparmorProfile sets g.spec.Process.ApparmorProfile.
func (g *Generator) SetProcessApparmorProfile(prof string) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.ApparmorProfile = prof
}
// SetProcessArgs sets g.spec.Process.Args.
func (g *Generator) SetProcessArgs(args []string) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.Args = args
}
@@ -411,7 +394,7 @@ func (g *Generator) ClearProcessEnv() {
// AddProcessEnv adds name=value into g.spec.Process.Env, or replaces an
// existing entry with the given name.
func (g *Generator) AddProcessEnv(name, value string) {
g.initSpec()
g.initSpecProcess()
env := fmt.Sprintf("%s=%s", name, value)
for idx := range g.spec.Process.Env {
@@ -425,7 +408,7 @@ func (g *Generator) AddProcessEnv(name, value string) {
// AddProcessRlimits adds rlimit into g.spec.Process.Rlimits.
func (g *Generator) AddProcessRlimits(rType string, rHard uint64, rSoft uint64) {
g.initSpec()
g.initSpecProcess()
for i, rlimit := range g.spec.Process.Rlimits {
if rlimit.Type == rType {
g.spec.Process.Rlimits[i].Hard = rHard
@@ -434,7 +417,7 @@ func (g *Generator) AddProcessRlimits(rType string, rHard uint64, rSoft uint64)
}
}
newRlimit := rspec.LinuxRlimit{
newRlimit := rspec.POSIXRlimit{
Type: rType,
Hard: rHard,
Soft: rSoft,
@@ -461,7 +444,7 @@ func (g *Generator) ClearProcessRlimits() {
if g.spec == nil {
return
}
g.spec.Process.Rlimits = []rspec.LinuxRlimit{}
g.spec.Process.Rlimits = []rspec.POSIXRlimit{}
}
// ClearProcessAdditionalGids clear g.spec.Process.AdditionalGids.
@@ -474,7 +457,7 @@ func (g *Generator) ClearProcessAdditionalGids() {
// AddProcessAdditionalGid adds an additional gid into g.spec.Process.AdditionalGids.
func (g *Generator) AddProcessAdditionalGid(gid uint32) {
g.initSpec()
g.initSpecProcess()
for _, group := range g.spec.Process.User.AdditionalGids {
if group == gid {
return
@@ -485,7 +468,7 @@ func (g *Generator) AddProcessAdditionalGid(gid uint32) {
// SetProcessSelinuxLabel sets g.spec.Process.SelinuxLabel.
func (g *Generator) SetProcessSelinuxLabel(label string) {
g.initSpec()
g.initSpecProcess()
g.spec.Process.SelinuxLabel = label
}
@@ -501,16 +484,10 @@ func (g *Generator) SetLinuxMountLabel(label string) {
g.spec.Linux.MountLabel = label
}
// SetLinuxResourcesDisableOOMKiller sets g.spec.Linux.Resources.DisableOOMKiller.
func (g *Generator) SetLinuxResourcesDisableOOMKiller(disable bool) {
g.initSpecLinuxResources()
g.spec.Linux.Resources.DisableOOMKiller = &disable
}
// SetLinuxResourcesOOMScoreAdj sets g.spec.Linux.Resources.OOMScoreAdj.
func (g *Generator) SetLinuxResourcesOOMScoreAdj(adj int) {
g.initSpecLinuxResources()
g.spec.Linux.Resources.OOMScoreAdj = &adj
// SetProcessOOMScoreAdj sets g.spec.Process.OOMScoreAdj.
func (g *Generator) SetProcessOOMScoreAdj(adj int) {
g.initSpecProcess()
g.spec.Process.OOMScoreAdj = &adj
}
// SetLinuxResourcesCPUShares sets g.spec.Linux.Resources.CPU.Shares.
@@ -555,32 +532,62 @@ func (g *Generator) SetLinuxResourcesCPUMems(mems string) {
g.spec.Linux.Resources.CPU.Mems = mems
}
// AddLinuxResourcesHugepageLimit adds or sets g.spec.Linux.Resources.HugepageLimits.
func (g *Generator) AddLinuxResourcesHugepageLimit(pageSize string, limit uint64) {
hugepageLimit := rspec.LinuxHugepageLimit{
Pagesize: pageSize,
Limit: limit,
}
g.initSpecLinuxResources()
for i, pageLimit := range g.spec.Linux.Resources.HugepageLimits {
if pageLimit.Pagesize == pageSize {
g.spec.Linux.Resources.HugepageLimits[i].Limit = limit
return
}
}
g.spec.Linux.Resources.HugepageLimits = append(g.spec.Linux.Resources.HugepageLimits, hugepageLimit)
}
// DropLinuxResourcesHugepageLimit drops a hugepage limit from g.spec.Linux.Resources.HugepageLimits.
func (g *Generator) DropLinuxResourcesHugepageLimit(pageSize string) error {
g.initSpecLinuxResources()
for i, pageLimit := range g.spec.Linux.Resources.HugepageLimits {
if pageLimit.Pagesize == pageSize {
g.spec.Linux.Resources.HugepageLimits = append(g.spec.Linux.Resources.HugepageLimits[:i], g.spec.Linux.Resources.HugepageLimits[i+1:]...)
return nil
}
}
return nil
}
// SetLinuxResourcesMemoryLimit sets g.spec.Linux.Resources.Memory.Limit.
func (g *Generator) SetLinuxResourcesMemoryLimit(limit uint64) {
func (g *Generator) SetLinuxResourcesMemoryLimit(limit int64) {
g.initSpecLinuxResourcesMemory()
g.spec.Linux.Resources.Memory.Limit = &limit
}
// SetLinuxResourcesMemoryReservation sets g.spec.Linux.Resources.Memory.Reservation.
func (g *Generator) SetLinuxResourcesMemoryReservation(reservation uint64) {
func (g *Generator) SetLinuxResourcesMemoryReservation(reservation int64) {
g.initSpecLinuxResourcesMemory()
g.spec.Linux.Resources.Memory.Reservation = &reservation
}
// SetLinuxResourcesMemorySwap sets g.spec.Linux.Resources.Memory.Swap.
func (g *Generator) SetLinuxResourcesMemorySwap(swap uint64) {
func (g *Generator) SetLinuxResourcesMemorySwap(swap int64) {
g.initSpecLinuxResourcesMemory()
g.spec.Linux.Resources.Memory.Swap = &swap
}
// SetLinuxResourcesMemoryKernel sets g.spec.Linux.Resources.Memory.Kernel.
func (g *Generator) SetLinuxResourcesMemoryKernel(kernel uint64) {
func (g *Generator) SetLinuxResourcesMemoryKernel(kernel int64) {
g.initSpecLinuxResourcesMemory()
g.spec.Linux.Resources.Memory.Kernel = &kernel
}
// SetLinuxResourcesMemoryKernelTCP sets g.spec.Linux.Resources.Memory.KernelTCP.
func (g *Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP uint64) {
func (g *Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP int64) {
g.initSpecLinuxResourcesMemory()
g.spec.Linux.Resources.Memory.KernelTCP = &kernelTCP
}
@@ -591,6 +598,12 @@ func (g *Generator) SetLinuxResourcesMemorySwappiness(swappiness uint64) {
g.spec.Linux.Resources.Memory.Swappiness = &swappiness
}
// SetLinuxResourcesMemoryDisableOOMKiller sets g.spec.Linux.Resources.Memory.DisableOOMKiller.
func (g *Generator) SetLinuxResourcesMemoryDisableOOMKiller(disable bool) {
g.initSpecLinuxResourcesMemory()
g.spec.Linux.Resources.Memory.DisableOOMKiller = &disable
}
// SetLinuxResourcesNetworkClassID sets g.spec.Linux.Resources.Network.ClassID.
func (g *Generator) SetLinuxResourcesNetworkClassID(classid uint32) {
g.initSpecLinuxResourcesNetwork()
@@ -714,12 +727,15 @@ func (g *Generator) ClearPreStartHooks() {
if g.spec == nil {
return
}
if g.spec.Hooks == nil {
return
}
g.spec.Hooks.Prestart = []rspec.Hook{}
}
// AddPreStartHook add a prestart hook into g.spec.Hooks.Prestart.
func (g *Generator) AddPreStartHook(path string, args []string) {
g.initSpec()
g.initSpecHooks()
hook := rspec.Hook{Path: path, Args: args}
g.spec.Hooks.Prestart = append(g.spec.Hooks.Prestart, hook)
}
@@ -729,12 +745,15 @@ func (g *Generator) ClearPostStopHooks() {
if g.spec == nil {
return
}
if g.spec.Hooks == nil {
return
}
g.spec.Hooks.Poststop = []rspec.Hook{}
}
// AddPostStopHook adds a poststop hook into g.spec.Hooks.Poststop.
func (g *Generator) AddPostStopHook(path string, args []string) {
g.initSpec()
g.initSpecHooks()
hook := rspec.Hook{Path: path, Args: args}
g.spec.Hooks.Poststop = append(g.spec.Hooks.Poststop, hook)
}
@@ -744,12 +763,15 @@ func (g *Generator) ClearPostStartHooks() {
if g.spec == nil {
return
}
if g.spec.Hooks == nil {
return
}
g.spec.Hooks.Poststart = []rspec.Hook{}
}
// AddPostStartHook adds a poststart hook into g.spec.Hooks.Poststart.
func (g *Generator) AddPostStartHook(path string, args []string) {
g.initSpec()
g.initSpecHooks()
hook := rspec.Hook{Path: path, Args: args}
g.spec.Hooks.Poststart = append(g.spec.Hooks.Poststart, hook)
}
@@ -830,6 +852,7 @@ func (g *Generator) SetupPrivileged(privileged bool) {
finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())))
}
g.initSpecLinux()
g.initSpecProcessCapabilities()
g.spec.Process.Capabilities.Bounding = finalCapList
g.spec.Process.Capabilities.Effective = finalCapList
g.spec.Process.Capabilities.Inheritable = finalCapList
@@ -860,7 +883,7 @@ func (g *Generator) AddProcessCapability(c string) error {
return err
}
g.initSpec()
g.initSpecProcessCapabilities()
for _, cap := range g.spec.Process.Capabilities.Bounding {
if strings.ToUpper(cap) == cp {
@@ -907,7 +930,7 @@ func (g *Generator) DropProcessCapability(c string) error {
return err
}
g.initSpec()
g.initSpecProcessCapabilities()
for i, cap := range g.spec.Process.Capabilities.Bounding {
if strings.ToUpper(cap) == cp {
@@ -959,7 +982,7 @@ func mapStrToNamespace(ns string, path string) (rspec.LinuxNamespace, error) {
case "cgroup":
return rspec.LinuxNamespace{Type: rspec.CgroupNamespace, Path: path}, nil
default:
return rspec.LinuxNamespace{}, fmt.Errorf("Should not reach here!")
return rspec.LinuxNamespace{}, fmt.Errorf("unrecognized namespace %q", ns)
}
}

View File

@@ -30,8 +30,9 @@ func ParseSyscallFlag(args SyscallOpts, config *rspec.LinuxSeccomp) error {
}
action, _ := parseAction(arguments[0])
if action == config.DefaultAction {
return fmt.Errorf("default action already set as %s", action)
if action == config.DefaultAction && args.argsAreEmpty() {
// default already set, no need to make changes
return nil
}
var newSyscall rspec.LinuxSyscall
@@ -96,7 +97,7 @@ func ParseDefaultAction(action string, config *rspec.LinuxSeccomp) error {
return err
}
config.DefaultAction = defaultAction
err = RemoveAllMatchingRules(config, action)
err = RemoveAllMatchingRules(config, defaultAction)
if err != nil {
return err
}
@@ -125,3 +126,10 @@ func newSyscallStruct(name string, action rspec.LinuxSeccompAction, args []rspec
}
return syscallStruct
}
func (s SyscallOpts) argsAreEmpty() bool {
return (s.Index == "" &&
s.Value == "" &&
s.ValueTwo == "" &&
s.Operator == "")
}

View File

@@ -15,12 +15,7 @@ func RemoveAction(arguments string, config *rspec.LinuxSeccomp) error {
return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
}
var syscallsToRemove []string
if strings.Contains(arguments, ",") {
syscallsToRemove = strings.Split(arguments, ",")
} else {
syscallsToRemove = append(syscallsToRemove, arguments)
}
syscallsToRemove := strings.Split(arguments, ",")
for counter, syscallStruct := range config.Syscalls {
if reflect.DeepEqual(syscallsToRemove, syscallStruct.Names) {
@@ -42,16 +37,11 @@ func RemoveAllSeccompRules(config *rspec.LinuxSeccomp) error {
}
// RemoveAllMatchingRules will remove any syscall rules that match the specified action
func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, action string) error {
func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, seccompAction rspec.LinuxSeccompAction) error {
if config == nil {
return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
}
seccompAction, err := parseAction(action)
if err != nil {
return err
}
for _, syscall := range config.Syscalls {
if reflect.DeepEqual(syscall.Action, seccompAction) {
RemoveAction(strings.Join(syscall.Names, ","), config)

View File

@@ -370,26 +370,25 @@ func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp {
var sysCloneFlagsIndex uint
capSysAdmin := false
var cap string
var caps []string
caps := make(map[string]bool)
for _, cap = range rs.Process.Capabilities.Bounding {
caps = append(caps, cap)
for _, cap := range rs.Process.Capabilities.Bounding {
caps[cap] = true
}
for _, cap = range rs.Process.Capabilities.Effective {
caps = append(caps, cap)
for _, cap := range rs.Process.Capabilities.Effective {
caps[cap] = true
}
for _, cap = range rs.Process.Capabilities.Inheritable {
caps = append(caps, cap)
for _, cap := range rs.Process.Capabilities.Inheritable {
caps[cap] = true
}
for _, cap = range rs.Process.Capabilities.Permitted {
caps = append(caps, cap)
for _, cap := range rs.Process.Capabilities.Permitted {
caps[cap] = true
}
for _, cap = range rs.Process.Capabilities.Ambient {
caps = append(caps, cap)
for _, cap := range rs.Process.Capabilities.Ambient {
caps[cap] = true
}
for _, cap = range caps {
for cap := range caps {
switch cap {
case "CAP_DAC_READ_SEARCH":
syscalls = append(syscalls, []rspec.LinuxSyscall{

View File

@@ -10,6 +10,27 @@ func (g *Generator) initSpec() {
}
}
func (g *Generator) initSpecProcess() {
g.initSpec()
if g.spec.Process == nil {
g.spec.Process = &rspec.Process{}
}
}
func (g *Generator) initSpecProcessCapabilities() {
g.initSpecProcess()
if g.spec.Process.Capabilities == nil {
g.spec.Process.Capabilities = &rspec.LinuxCapabilities{}
}
}
func (g *Generator) initSpecRoot() {
g.initSpec()
if g.spec.Root == nil {
g.spec.Root = &rspec.Root{}
}
}
func (g *Generator) initSpecAnnotations() {
g.initSpec()
if g.spec.Annotations == nil {
@@ -17,6 +38,13 @@ func (g *Generator) initSpecAnnotations() {
}
}
func (g *Generator) initSpecHooks() {
g.initSpec()
if g.spec.Hooks == nil {
g.spec.Hooks = &rspec.Hooks{}
}
}
func (g *Generator) initSpecLinux() {
g.initSpec()
if g.spec.Linux == nil {

View File

@@ -0,0 +1,110 @@
package validate
import (
"errors"
"fmt"
"strings"
rspec "github.com/opencontainers/runtime-spec/specs-go"
)
// ComplianceLevel represents the OCI compliance levels
type ComplianceLevel int
const (
// MAY-level
// ComplianceMay represents 'MAY' in RFC2119
ComplianceMay ComplianceLevel = iota
// ComplianceOptional represents 'OPTIONAL' in RFC2119
ComplianceOptional
// SHOULD-level
// ComplianceShould represents 'SHOULD' in RFC2119
ComplianceShould
// ComplianceShouldNot represents 'SHOULD NOT' in RFC2119
ComplianceShouldNot
// ComplianceRecommended represents 'RECOMMENDED' in RFC2119
ComplianceRecommended
// ComplianceNotRecommended represents 'NOT RECOMMENDED' in RFC2119
ComplianceNotRecommended
// MUST-level
// ComplianceMust represents 'MUST' in RFC2119
ComplianceMust
// ComplianceMustNot represents 'MUST NOT' in RFC2119
ComplianceMustNot
// ComplianceShall represents 'SHALL' in RFC2119
ComplianceShall
// ComplianceShallNot represents 'SHALL NOT' in RFC2119
ComplianceShallNot
// ComplianceRequired represents 'REQUIRED' in RFC2119
ComplianceRequired
)
// ErrorCode represents the compliance content
type ErrorCode int
const (
// DefaultFilesystems represents the error code of default filesystems test
DefaultFilesystems ErrorCode = iota
)
// Error represents an error with compliance level and OCI reference
type Error struct {
Level ComplianceLevel
Reference string
Err error
}
const referencePrefix = "https://github.com/opencontainers/runtime-spec/blob"
var ociErrors = map[ErrorCode]Error{
DefaultFilesystems: Error{Level: ComplianceShould, Reference: "config-linux.md#default-filesystems"},
}
// ParseLevel takes a string level and returns the OCI compliance level constant
func ParseLevel(level string) (ComplianceLevel, error) {
switch strings.ToUpper(level) {
case "MAY":
fallthrough
case "OPTIONAL":
return ComplianceMay, nil
case "SHOULD":
fallthrough
case "SHOULDNOT":
fallthrough
case "RECOMMENDED":
fallthrough
case "NOTRECOMMENDED":
return ComplianceShould, nil
case "MUST":
fallthrough
case "MUSTNOT":
fallthrough
case "SHALL":
fallthrough
case "SHALLNOT":
fallthrough
case "REQUIRED":
return ComplianceMust, nil
}
var l ComplianceLevel
return l, fmt.Errorf("%q is not a valid compliance level", level)
}
// NewError creates an Error by ErrorCode and message
func NewError(code ErrorCode, msg string) error {
err := ociErrors[code]
err.Err = errors.New(msg)
return &err
}
// Error returns the error message with OCI reference
func (oci *Error) Error() string {
return fmt.Sprintf("%s\nRefer to: %s/v%s/%s", oci.Err.Error(), referencePrefix, rspec.Version, oci.Reference)
}

View File

@@ -9,13 +9,14 @@ import (
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"unicode"
"unicode/utf8"
"github.com/Sirupsen/logrus"
"github.com/blang/semver"
rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"github.com/syndtr/gocapability/capability"
)
@@ -47,15 +48,27 @@ type Validator struct {
spec *rspec.Spec
bundlePath string
HostSpecific bool
platform string
}
// NewValidator creates a Validator
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool) Validator {
return Validator{spec: spec, bundlePath: bundlePath, HostSpecific: hostSpecific}
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool, platform string) Validator {
if hostSpecific && platform != runtime.GOOS {
platform = runtime.GOOS
}
return Validator{
spec: spec,
bundlePath: bundlePath,
HostSpecific: hostSpecific,
platform: platform,
}
}
// NewValidatorFromPath creates a Validator with specified bundle path
func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, error) {
func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string) (Validator, error) {
if hostSpecific && platform != runtime.GOOS {
platform = runtime.GOOS
}
if bundlePath == "" {
return Validator{}, fmt.Errorf("Bundle path shouldn't be empty")
}
@@ -77,20 +90,21 @@ func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, erro
return Validator{}, err
}
return NewValidator(&spec, bundlePath, hostSpecific), nil
return NewValidator(&spec, bundlePath, hostSpecific, platform), nil
}
// CheckAll checks all parts of runtime bundle
func (v *Validator) CheckAll() (msgs []string) {
msgs = append(msgs, v.CheckPlatform()...)
msgs = append(msgs, v.CheckRootfsPath()...)
msgs = append(msgs, v.CheckMandatoryFields()...)
msgs = append(msgs, v.CheckSemVer()...)
msgs = append(msgs, v.CheckMounts()...)
msgs = append(msgs, v.CheckPlatform()...)
msgs = append(msgs, v.CheckProcess()...)
msgs = append(msgs, v.CheckOS()...)
msgs = append(msgs, v.CheckLinux()...)
msgs = append(msgs, v.CheckHooks()...)
if v.spec.Linux != nil {
msgs = append(msgs, v.CheckLinux()...)
}
return
}
@@ -129,8 +143,13 @@ func (v *Validator) CheckRootfsPath() (msgs []string) {
msgs = append(msgs, fmt.Sprintf("root.path is %q, but it MUST be a child of %q", v.spec.Root.Path, absBundlePath))
}
return
if v.platform == "windows" {
if v.spec.Root.Readonly {
msgs = append(msgs, "root.readonly field MUST be omitted or false when target platform is windows")
}
}
return
}
// CheckSemVer checks v.spec.Version
@@ -149,37 +168,6 @@ func (v *Validator) CheckSemVer() (msgs []string) {
return
}
// CheckPlatform checks v.spec.Platform
func (v *Validator) CheckPlatform() (msgs []string) {
logrus.Debugf("check platform")
validCombins := map[string][]string{
"android": {"arm"},
"darwin": {"386", "amd64", "arm", "arm64"},
"dragonfly": {"amd64"},
"freebsd": {"386", "amd64", "arm"},
"linux": {"386", "amd64", "arm", "arm64", "ppc64", "ppc64le", "mips64", "mips64le", "s390x"},
"netbsd": {"386", "amd64", "arm"},
"openbsd": {"386", "amd64", "arm"},
"plan9": {"386", "amd64"},
"solaris": {"amd64"},
"windows": {"386", "amd64"}}
platform := v.spec.Platform
for os, archs := range validCombins {
if os == platform.OS {
for _, arch := range archs {
if arch == platform.Arch {
return nil
}
}
msgs = append(msgs, fmt.Sprintf("Combination of %q and %q is invalid.", platform.OS, platform.Arch))
}
}
msgs = append(msgs, fmt.Sprintf("Operation system %q of the bundle is not supported yet.", platform.OS))
return
}
// CheckHooks check v.spec.Hooks
func (v *Validator) CheckHooks() (msgs []string) {
logrus.Debugf("check hooks")
@@ -259,11 +247,12 @@ func (v *Validator) CheckProcess() (msgs []string) {
}
}
msgs = append(msgs, v.CheckCapabilities()...)
if v.spec.Process.Capabilities != nil {
msgs = append(msgs, v.CheckCapabilities()...)
}
msgs = append(msgs, v.CheckRlimits()...)
if v.spec.Platform.OS == "linux" {
if v.platform == "linux" {
if len(process.ApparmorProfile) > 0 {
profilePath := filepath.Join(v.bundlePath, v.spec.Root.Path, "/etc/apparmor.d", process.ApparmorProfile)
_, err := os.Stat(profilePath)
@@ -279,32 +268,55 @@ func (v *Validator) CheckProcess() (msgs []string) {
// CheckCapabilities checks v.spec.Process.Capabilities
func (v *Validator) CheckCapabilities() (msgs []string) {
process := v.spec.Process
if v.spec.Platform.OS == "linux" {
var caps []string
if v.platform == "linux" {
var effective, permitted, inheritable, ambient bool
caps := make(map[string][]string)
for _, cap := range process.Capabilities.Bounding {
caps = append(caps, cap)
caps[cap] = append(caps[cap], "bounding")
}
for _, cap := range process.Capabilities.Effective {
caps = append(caps, cap)
caps[cap] = append(caps[cap], "effective")
}
for _, cap := range process.Capabilities.Inheritable {
caps = append(caps, cap)
caps[cap] = append(caps[cap], "inheritable")
}
for _, cap := range process.Capabilities.Permitted {
caps = append(caps, cap)
caps[cap] = append(caps[cap], "permitted")
}
for _, cap := range process.Capabilities.Ambient {
caps = append(caps, cap)
caps[cap] = append(caps[cap], "ambient")
}
for _, capability := range caps {
for capability, owns := range caps {
if err := CapValid(capability, v.HostSpecific); err != nil {
msgs = append(msgs, fmt.Sprintf("capability %q is not valid, man capabilities(7)", capability))
}
effective, permitted, ambient, inheritable = false, false, false, false
for _, set := range owns {
if set == "effective" {
effective = true
}
if set == "inheritable" {
inheritable = true
}
if set == "permitted" {
permitted = true
}
if set == "ambient" {
ambient = true
}
}
if effective && !permitted {
msgs = append(msgs, fmt.Sprintf("effective capability %q is not allowed, as it's not permitted", capability))
}
if ambient && !(effective && inheritable) {
msgs = append(msgs, fmt.Sprintf("ambient capability %q is not allowed, as it's not permitted and inheribate", capability))
}
}
} else {
logrus.Warnf("process.capabilities validation not yet implemented for OS %q", v.spec.Platform.OS)
logrus.Warnf("process.capabilities validation not yet implemented for OS %q", v.platform)
}
return
@@ -319,14 +331,7 @@ func (v *Validator) CheckRlimits() (msgs []string) {
msgs = append(msgs, fmt.Sprintf("rlimit can not contain the same type %q.", process.Rlimits[index].Type))
}
}
if v.spec.Platform.OS == "linux" {
if err := rlimitValid(rlimit); err != nil {
msgs = append(msgs, err.Error())
}
} else {
logrus.Warnf("process.rlimits validation not yet implemented for OS %q", v.spec.Platform.OS)
}
msgs = append(msgs, v.rlimitValid(rlimit)...)
}
return
@@ -377,46 +382,39 @@ func supportedMountTypes(OS string, hostSpecific bool) (map[string]bool, error)
func (v *Validator) CheckMounts() (msgs []string) {
logrus.Debugf("check mounts")
supportedTypes, err := supportedMountTypes(v.spec.Platform.OS, v.HostSpecific)
supportedTypes, err := supportedMountTypes(v.platform, v.HostSpecific)
if err != nil {
msgs = append(msgs, err.Error())
return
}
if supportedTypes != nil {
for _, mount := range v.spec.Mounts {
for _, mount := range v.spec.Mounts {
if supportedTypes != nil {
if !supportedTypes[mount.Type] {
msgs = append(msgs, fmt.Sprintf("Unsupported mount type %q", mount.Type))
}
}
if !filepath.IsAbs(mount.Destination) {
msgs = append(msgs, fmt.Sprintf("destination %v is not an absolute path", mount.Destination))
}
if !filepath.IsAbs(mount.Destination) {
msgs = append(msgs, fmt.Sprintf("destination %v is not an absolute path", mount.Destination))
}
}
return
}
// CheckOS checks v.spec.Platform.OS
func (v *Validator) CheckOS() (msgs []string) {
logrus.Debugf("check os")
// CheckPlatform checks v.platform
func (v *Validator) CheckPlatform() (msgs []string) {
logrus.Debugf("check platform")
if v.spec.Platform.OS != "linux" {
if v.spec.Linux != nil {
msgs = append(msgs, fmt.Sprintf("'linux' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
}
if v.platform != "linux" && v.platform != "solaris" && v.platform != "windows" {
msgs = append(msgs, fmt.Sprintf("platform %q is not supported", v.platform))
return
}
if v.spec.Platform.OS != "solaris" {
if v.spec.Solaris != nil {
msgs = append(msgs, fmt.Sprintf("'solaris' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
}
}
if v.spec.Platform.OS != "windows" {
if v.spec.Windows != nil {
msgs = append(msgs, fmt.Sprintf("'windows' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
if v.platform == "windows" {
if v.spec.Windows == nil {
msgs = append(msgs, "'windows' MUST be set when platform is `windows`")
}
}
@@ -477,7 +475,7 @@ func (v *Validator) CheckLinux() (msgs []string) {
}
}
if v.spec.Platform.OS == "linux" && !typeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
if v.platform == "linux" && !typeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
msgs = append(msgs, fmt.Sprintf("On Linux, hostname requires a new UTS namespace to be specified as well"))
}
@@ -505,19 +503,21 @@ func (v *Validator) CheckLinux() (msgs []string) {
case "rslave":
case "shared":
case "rshared":
case "unbindable":
case "runbindable":
default:
msgs = append(msgs, "rootfsPropagation must be empty or one of \"private|rprivate|slave|rslave|shared|rshared\"")
msgs = append(msgs, "rootfsPropagation must be empty or one of \"private|rprivate|slave|rslave|shared|rshared|unbindable|runbindable\"")
}
for _, maskedPath := range v.spec.Linux.MaskedPaths {
if !strings.HasPrefix(maskedPath, "/") {
msgs = append(msgs, "maskedPath %v is not an absolute path", maskedPath)
msgs = append(msgs, fmt.Sprintf("maskedPath %v is not an absolute path", maskedPath))
}
}
for _, readonlyPath := range v.spec.Linux.ReadonlyPaths {
if !strings.HasPrefix(readonlyPath, "/") {
msgs = append(msgs, "readonlyPath %v is not an absolute path", readonlyPath)
msgs = append(msgs, fmt.Sprintf("readonlyPath %v is not an absolute path", readonlyPath))
}
}
@@ -652,16 +652,23 @@ func envValid(env string) bool {
return true
}
func rlimitValid(rlimit rspec.LinuxRlimit) error {
func (v *Validator) rlimitValid(rlimit rspec.POSIXRlimit) (msgs []string) {
if rlimit.Hard < rlimit.Soft {
return fmt.Errorf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type)
msgs = append(msgs, fmt.Sprintf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type))
}
for _, val := range defaultRlimits {
if val == rlimit.Type {
return nil
if v.platform == "linux" {
for _, val := range defaultRlimits {
if val == rlimit.Type {
return
}
}
msgs = append(msgs, fmt.Sprintf("rlimit type %q is invalid", rlimit.Type))
} else {
logrus.Warnf("process.rlimits validation not yet implemented for platform %q", v.platform)
}
return fmt.Errorf("rlimit type %q is invalid", rlimit.Type)
return
}
func namespaceValid(ns rspec.LinuxNamespace) bool {