Skip to content

Commit

Permalink
validate: Soften unrecognized rlimit types to SHOULD violations
Browse files Browse the repository at this point in the history
The spec isn't particuarly clear on this, saying [1]:

  * Linux: valid values are defined in the
    [`getrlimit(2)`][getrlimit.2] man page, such as `RLIMIT_MSGQUEUE`.
  * Solaris: valid values are defined in the
    [`getrlimit(3)`][getrlimit.3] man page, such as `RLIMIT_CORE`.

and [2]:

  For each entry in `rlimits`, a [`getrlimit(3)`][getrlimit.3] on
  `type` MUST succeed.

It doesn't say:

  Linux: The value MUST be listed in the getrlimit(2) man page...

and it doesn't require the runtime to support the values listed in the
man page [3,4].  So there are three sets:

* Values listed in the man page
* Values supported by the host kernel
* Values supported by the runtime

And as the spec stands, these sets are only weakly coupled, and any of
them could be a sub- or superset of any other.  In practice, I expect
the sets to all coincide, with the kernel occasionally adding or
removing values, and the man page and runtimes trailing along behind.

To address that, this commit weakens the previous hard error to a
SHOULD-level error.  The PosixProcRlimitsValueError constant is new to
this commit, because the spec contains neither a MUST nor a SHOULD for
this condition, although I expect a SHOULD-level suggestion was
implied by [1].  The posixProcRef constant is cherry-picked from
27503c5 (complete spec errors of config.md, 2017-09-05, opencontainers#458).

[1]: https://github.com/opencontainers/runtime-spec/blame/v1.0.0/config.md#L168-L169
[2]: https://github.com/opencontainers/runtime-spec/blame/v1.0.0/config.md#L168-L169
[3]: opencontainers/runtime-spec#813
[4]: https://github.com/opencontainers/runtime-spec/blame/v1.0.0/config.md#L463

Signed-off-by: W. Trevor King <wking@tremily.us>
  • Loading branch information
wking committed Sep 21, 2017
1 parent 894cae7 commit 0e28021
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 2 deletions.
8 changes: 8 additions & 0 deletions specerror/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const (
// ReadonlyOnWindows represents the error code of readonly setting test on Windows
ReadonlyOnWindows

// PosixProcRlimitsValueError represents "valid values are defined in the ... man page"
PosixProcRlimitsValueError

// DefaultFilesystems represents the error code of default filesystems test
DefaultFilesystems

Expand Down Expand Up @@ -79,6 +82,9 @@ var (
rootRef = func(version string) (reference string, err error) {
return fmt.Sprintf(referenceTemplate, version, "config.md#root"), nil
}
posixProcRef = func(version string) (reference string, err error) {
return fmt.Sprintf(referenceTemplate, version, "config.md#posix-process"), nil
}
defaultFSRef = func(version string) (reference string, err error) {
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-filesystems"), nil
}
Expand Down Expand Up @@ -106,6 +112,8 @@ var ociErrors = map[Code]errorTemplate{
ReadonlyFilesystem: {Level: rfc2119.Must, Reference: rootRef},
ReadonlyOnWindows: {Level: rfc2119.Must, Reference: rootRef},

PosixProcRlimitsValueError: {Level: rfc2119.Should, Reference: posixProcRef},

// Config-Linux.md
// Default Filesystems
DefaultFilesystems: {Level: rfc2119.Should, Reference: defaultFSRef},
Expand Down
8 changes: 6 additions & 2 deletions validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,10 @@ func (v *Validator) CheckCapabilities() (errs error) {

// CheckRlimits checks v.spec.Process.Rlimits
func (v *Validator) CheckRlimits() (errs error) {
if v.platform == "windows" {
return
}

process := v.spec.Process
for index, rlimit := range process.Rlimits {
for i := index + 1; i < len(process.Rlimits); i++ {
Expand Down Expand Up @@ -878,14 +882,14 @@ func (v *Validator) rlimitValid(rlimit rspec.POSIXRlimit) (errs error) {
return
}
}
errs = multierror.Append(errs, fmt.Errorf("rlimit type %q is invalid", rlimit.Type))
errs = multierror.Append(errs, specerror.NewError(specerror.PosixProcRlimitsValueError, fmt.Errorf("rlimit type %q may not be valid", rlimit.Type), v.spec.Version))
} else if v.platform == "solaris" {
for _, val := range posixRlimits {
if val == rlimit.Type {
return
}
}
errs = multierror.Append(errs, fmt.Errorf("rlimit type %q is invalid", rlimit.Type))
errs = multierror.Append(errs, specerror.NewError(specerror.PosixProcRlimitsValueError, fmt.Errorf("rlimit type %q may not be valid", rlimit.Type), v.spec.Version))
} else {
logrus.Warnf("process.rlimits validation not yet implemented for platform %q", v.platform)
}
Expand Down
102 changes: 102 additions & 0 deletions validate/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,105 @@ func TestCheckSemVer(t *testing.T) {
assert.Equal(t, c.expected, specerror.FindError(err, c.expected), "Fail to check SemVer "+c.val)
}
}

func TestCheckProcess(t *testing.T) {
cases := []struct {
val rspec.Spec
platform string
expected specerror.Code
}{
{
val: rspec.Spec{
Version: "1.0.0",
Process: &rspec.Process{
Args: []string{"sh"},
Cwd: "/",
},
},
platform: "linux",
expected: specerror.NonError,
},
{
val: rspec.Spec{
Version: "1.0.0",
Process: &rspec.Process{
Args: []string{"sh"},
Cwd: "/",
Rlimits: []rspec.POSIXRlimit{
{
Type: "RLIMIT_NOFILE",
Hard: 1024,
Soft: 1024,
},
{
Type: "RLIMIT_NPROC",
Hard: 512,
Soft: 512,
},
},
},
},
platform: "linux",
expected: specerror.NonError,
},
{
val: rspec.Spec{
Version: "1.0.0",
Process: &rspec.Process{
Args: []string{"sh"},
Cwd: "/",
Rlimits: []rspec.POSIXRlimit{
{
Type: "RLIMIT_NOFILE",
Hard: 1024,
Soft: 1024,
},
},
},
},
platform: "solaris",
expected: specerror.NonError,
},
{
val: rspec.Spec{
Version: "1.0.0",
Process: &rspec.Process{
Args: []string{"sh"},
Cwd: "/",
Rlimits: []rspec.POSIXRlimit{
{
Type: "RLIMIT_DOES_NOT_EXIST",
Hard: 512,
Soft: 512,
},
},
},
},
platform: "linux",
expected: specerror.PosixProcRlimitsValueError,
},
{
val: rspec.Spec{
Version: "1.0.0",
Process: &rspec.Process{
Args: []string{"sh"},
Cwd: "/",
Rlimits: []rspec.POSIXRlimit{
{
Type: "RLIMIT_NPROC",
Hard: 512,
Soft: 512,
},
},
},
},
platform: "solaris",
expected: specerror.PosixProcRlimitsValueError,
},
}
for _, c := range cases {
v := NewValidator(&c.val, ".", false, c.platform)
err := v.CheckProcess()
assert.Equal(t, c.expected, specerror.FindError(err, c.expected), fmt.Sprintf("failed CheckProcess: %v %d", err, c.expected))
}
}

0 comments on commit 0e28021

Please sign in to comment.