Fix panic in TestExecSetPlatformOpt, TestExecSetPlatformOptPrivileged

These tests would panic;

- in WithRLimits(), because HostConfig was not set;
  470ae8422f/daemon/oci_linux.go (L46-L47)
- in daemon.mergeUlimits(), because daemon.configStore was not set;
  470ae8422f/daemon/oci_linux.go (L1069)

This panic was not discovered because the current version of runc/libcontainer that we vendor
would not always return false for `apparmor.IsEnabled()` when running docker-in-docker or if
`apparmor_parser` is not found. Starting with v1.0.0-rc93 of libcontainer, this is no longer
the case (changed in bfb4ea1b1b)

This patch;

- changes the tests to initialize Daemon.configStore and Container.HostConfig
- Combines TestExecSetPlatformOpt and TestExecSetPlatformOptPrivileged into a new test
  (TestExecSetPlatformOptAppArmor)
- Runs the test both if AppArmor is enabled and if not (in which case it tests
  that the container's AppArmor profile is left empty).
- Adds a FIXME comment for a possible bug in execSetPlatformOpts, which currently
  prefers custom profiles over "privileged".

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2021-03-13 21:41:32 +01:00
parent 369d0dc092
commit 6d1eceb509
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
1 changed files with 70 additions and 33 deletions

View File

@ -8,46 +8,83 @@ import (
"github.com/containerd/containerd/pkg/apparmor"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/daemon/exec"
specs "github.com/opencontainers/runtime-spec/specs-go"
"gotest.tools/v3/assert"
)
func TestExecSetPlatformOpt(t *testing.T) {
if !apparmor.HostSupports() {
t.Skip("requires AppArmor to be enabled")
func TestExecSetPlatformOptAppArmor(t *testing.T) {
appArmorEnabled := apparmor.HostSupports()
tests := []struct {
doc string
privileged bool
appArmorProfile string
expectedProfile string
}{
{
doc: "default options",
expectedProfile: defaultAppArmorProfile,
},
{
doc: "custom profile",
appArmorProfile: "my-custom-profile",
expectedProfile: "my-custom-profile",
},
{
doc: "privileged container",
privileged: true,
expectedProfile: unconfinedAppArmorProfile,
},
{
doc: "privileged container, custom profile",
privileged: true,
appArmorProfile: "my-custom-profile",
expectedProfile: "my-custom-profile",
// FIXME: execSetPlatformOpts prefers custom profiles over "privileged",
// which looks like a bug (--privileged on the container should
// disable apparmor, seccomp, and selinux); see the code at:
// https://github.com/moby/moby/blob/46cdcd206c56172b95ba5c77b827a722dab426c5/daemon/exec_linux.go#L32-L40
// expectedProfile: unconfinedAppArmorProfile,
},
}
d := &Daemon{}
c := &container.Container{AppArmorProfile: "my-custom-profile"}
ec := &exec.Config{}
p := &specs.Process{}
err := d.execSetPlatformOpt(c, ec, p)
assert.NilError(t, err)
assert.Equal(t, "my-custom-profile", p.ApparmorProfile)
}
d := &Daemon{configStore: &config.Config{}}
// TestExecSetPlatformOptPrivileged verifies that `docker exec --privileged`
// does not disable AppArmor profiles. Exec currently inherits the `Privileged`
// configuration of the container. See https://github.com/moby/moby/pull/31773#discussion_r105586900
//
// This behavior may change in future, but test for the behavior to prevent it
// from being changed accidentally.
func TestExecSetPlatformOptPrivileged(t *testing.T) {
if !apparmor.HostSupports() {
t.Skip("requires AppArmor to be enabled")
// Currently, `docker exec --privileged` inherits the Privileged configuration
// of the container, and does not disable AppArmor.
// See https://github.com/moby/moby/pull/31773#discussion_r105586900
//
// This behavior may change in future, but to verify the current behavior,
// we run the test both with "exec" and "exec --privileged", which should
// both give the same result.
for _, execPrivileged := range []bool{false, true} {
for _, tc := range tests {
tc := tc
doc := tc.doc
if !appArmorEnabled {
// no profile should be set if the host does not support AppArmor
doc += " (apparmor disabled)"
tc.expectedProfile = ""
}
if execPrivileged {
doc += " (exec privileged)"
}
t.Run(doc, func(t *testing.T) {
c := &container.Container{
AppArmorProfile: tc.appArmorProfile,
HostConfig: &containertypes.HostConfig{
Privileged: tc.privileged,
},
}
ec := &exec.Config{Privileged: execPrivileged}
p := &specs.Process{}
err := d.execSetPlatformOpt(c, ec, p)
assert.NilError(t, err)
assert.Equal(t, p.ApparmorProfile, tc.expectedProfile)
})
}
}
d := &Daemon{}
c := &container.Container{AppArmorProfile: "my-custom-profile"}
ec := &exec.Config{Privileged: true}
p := &specs.Process{}
err := d.execSetPlatformOpt(c, ec, p)
assert.NilError(t, err)
assert.Equal(t, "my-custom-profile", p.ApparmorProfile)
c.HostConfig = &containertypes.HostConfig{Privileged: true}
err = d.execSetPlatformOpt(c, ec, p)
assert.NilError(t, err)
assert.Equal(t, unconfinedAppArmorProfile, p.ApparmorProfile)
}