api/types/container: fix validation for UTSMode, UsernsMode, PidMode

The IPCMode type was added in 497fc8876e, and from
that patch, the intent was to allow `host` (without `:`), `""` (empty, default)
or `container:<container ID>`, but the `Valid()` function seems to be too relaxed
and accepting both `:`, as well as `host:<anything>`. No unit-tests were added
in that patch, and integration-tests only tested for valid values.

Later on, `PidMode`, and `UTSMode` were added in 23feaaa240
and f2e5207fc9, both of which were implemented as
a straight copy of the `IPCMode` implementation, copying the same bug.

Finally, commit d4aec5f0a6 implemented unit-tests
for these types, but testing for the wrong behavior of the implementation.

This patch updates the validation to correctly invalidate `host[:<anything>]`
and empty (`:`) types.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2022-11-01 16:04:57 +01:00
parent 1bd486666b
commit e7d75c8db7
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
2 changed files with 25 additions and 32 deletions

View file

@ -175,21 +175,12 @@ func (n UsernsMode) IsHost() bool {
// IsPrivate indicates whether the container uses the a private userns.
func (n UsernsMode) IsPrivate() bool {
return !(n.IsHost())
return !n.IsHost()
}
// Valid indicates whether the userns is valid.
func (n UsernsMode) Valid() bool {
if string(n) == "" {
return true
}
switch mode, _, _ := strings.Cut(string(n), ":"); mode {
case "host":
return true
default:
return false
}
return n == "" || n.IsHost()
}
// CgroupSpec represents the cgroup to use for the container.
@ -217,7 +208,7 @@ type UTSMode string
// IsPrivate indicates whether the container uses its private UTS namespace.
func (n UTSMode) IsPrivate() bool {
return !(n.IsHost())
return !n.IsHost()
}
// IsHost indicates whether the container uses the host's UTS namespace.
@ -227,13 +218,7 @@ func (n UTSMode) IsHost() bool {
// Valid indicates whether the UTS namespace is valid.
func (n UTSMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
case "", "host":
default:
return false
}
return true
return n == "" || n.IsHost()
}
// PidMode represents the pid namespace of the container.
@ -257,15 +242,7 @@ func (n PidMode) IsContainer() bool {
// Valid indicates whether the pid namespace is valid.
func (n PidMode) Valid() bool {
mode, v, ok := strings.Cut(string(n), ":")
switch mode {
case "", "host":
return true
case "container":
return ok && v != ""
default:
return false
}
return n == "" || n.IsHost() || n.IsContainer()
}
// Container returns the name of the container whose pid namespace is going to be used.

View file

@ -15,7 +15,10 @@ func TestCgroupnsMode(t *testing.T) {
"": {private: false, host: false, empty: true, valid: true},
"something:weird": {private: false, host: false, empty: false, valid: false},
"host": {private: false, host: true, empty: false, valid: true},
"host:name": {private: false, host: false, empty: false, valid: false},
"host:": {valid: false},
"host:name": {valid: false},
":name": {valid: false},
":": {valid: false},
"private": {private: true, host: false, empty: false, valid: true},
"private:name": {private: false, host: false, empty: false, valid: false},
}
@ -70,6 +73,10 @@ func TestIpcMode(t *testing.T) {
"something:weird": {},
":weird": {},
"host": {host: true, valid: true},
"host:": {valid: false},
"host:name": {valid: false},
":name": {valid: false},
":": {valid: false},
"container": {},
"container:": {container: true, valid: true, ctrName: ""},
"container:name": {container: true, valid: true, ctrName: "name"},
@ -94,7 +101,10 @@ func TestUTSMode(t *testing.T) {
"": {private: true, host: false, valid: true},
"something:weird": {private: true, host: false, valid: false},
"host": {private: false, host: true, valid: true},
"host:name": {private: true, host: false, valid: true},
"host:": {private: true, valid: false},
"host:name": {private: true, valid: false},
":name": {private: true, valid: false},
":": {private: true, valid: false},
}
for mode, expected := range modes {
t.Run("mode="+string(mode), func(t *testing.T) {
@ -111,7 +121,10 @@ func TestUsernsMode(t *testing.T) {
"": {private: true, host: false, valid: true},
"something:weird": {private: true, host: false, valid: false},
"host": {private: false, host: true, valid: true},
"host:name": {private: true, host: false, valid: true},
"host:": {private: true, valid: false},
"host:name": {private: true, valid: false},
":name": {private: true, valid: false},
":": {private: true, valid: false},
}
for mode, expected := range modes {
t.Run("mode="+string(mode), func(t *testing.T) {
@ -127,7 +140,10 @@ func TestPidMode(t *testing.T) {
"": {private: true, host: false, valid: true},
"something:weird": {private: true, host: false, valid: false},
"host": {private: false, host: true, valid: true},
"host:name": {private: true, host: false, valid: true},
"host:": {private: true, valid: false},
"host:name": {private: true, valid: false},
":name": {private: true, valid: false},
":": {private: true, valid: false},
}
for mode, expected := range modes {
t.Run("mode="+string(mode), func(t *testing.T) {