瀏覽代碼

Fix AppArmor not being applied to Exec processes

Exec processes do not automatically inherit AppArmor
profiles from the container.

This patch sets the AppArmor profile for the exec
process.

Before this change:

    apparmor_parser -q -r <<EOF
    #include <tunables/global>
    profile deny-write flags=(attach_disconnected) {
      #include <abstractions/base>
      file,
      network,
      deny /tmp/** w,
      capability,
    }
    EOF

    docker run -dit --security-opt "apparmor=deny-write" --name aa busybox

    docker exec aa sh -c 'mkdir /tmp/test'
    (no error)

With this change applied:

    docker exec aa sh -c 'mkdir /tmp/test'
    mkdir: can't create directory '/tmp/test': Permission denied

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 7 年之前
父節點
當前提交
8f3308ae10
共有 2 個文件被更改,包括 56 次插入0 次删除
  1. 3 0
      daemon/exec_linux.go
  2. 53 0
      daemon/exec_linux_test.go

+ 3 - 0
daemon/exec_linux.go

@@ -34,6 +34,8 @@ func (daemon *Daemon) execSetPlatformOpt(c *container.Container, ec *exec.Config
 		if c.AppArmorProfile != "" {
 			appArmorProfile = c.AppArmorProfile
 		} else if c.HostConfig.Privileged {
+			// `docker exec --privileged` does not currently disable AppArmor
+			// profiles. Privileged configuration of the container is inherited
 			appArmorProfile = "unconfined"
 		} else {
 			appArmorProfile = "docker-default"
@@ -50,6 +52,7 @@ func (daemon *Daemon) execSetPlatformOpt(c *container.Container, ec *exec.Config
 				return err
 			}
 		}
+		p.ApparmorProfile = appArmorProfile
 	}
 	daemon.setRlimits(&specs.Spec{Process: p}, c)
 	return nil

+ 53 - 0
daemon/exec_linux_test.go

@@ -0,0 +1,53 @@
+// +build linux
+
+package daemon
+
+import (
+	"testing"
+
+	containertypes "github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/container"
+	"github.com/docker/docker/daemon/exec"
+	"github.com/gotestyourself/gotestyourself/assert"
+	"github.com/opencontainers/runc/libcontainer/apparmor"
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func TestExecSetPlatformOpt(t *testing.T) {
+	if !apparmor.IsEnabled() {
+		t.Skip("requires AppArmor to be enabled")
+	}
+	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)
+}
+
+// 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.IsEnabled() {
+		t.Skip("requires AppArmor to be enabled")
+	}
+	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, "unconfined", p.ApparmorProfile)
+}