diff --git a/contrib/apparmor/template.go b/contrib/apparmor/template.go index 34ff99246b4d..da006957bd0b 100644 --- a/contrib/apparmor/template.go +++ b/contrib/apparmor/template.go @@ -1,6 +1,8 @@ // +build linux /* + Copyright The docker Authors. + Copyright The Moby Authors. Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +24,7 @@ import ( "bufio" "fmt" "io" + "io/ioutil" "os" "os/exec" "path" @@ -32,6 +35,10 @@ import ( "github.com/pkg/errors" ) +// NOTE: This code is copied from . +// If you plan to make any changes, please make sure they are also sent +// upstream. + const dir = "/etc/apparmor.d" const defaultTemplate = ` @@ -48,6 +55,14 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { capability, file, umount, +{{if ge .Version 208096}} + # Host (privileged) processes may send signals to container processes. + signal (receive) peer=unconfined, + # Manager may send signals to container processes. + signal (receive) peer={{.DaemonProfile}}, + # Container processes may send signals amongst themselves. + signal (send,receive) peer={{.Name}}, +{{end}} deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir) # deny write to files not in /proc//** or /proc/sys/** @@ -76,10 +91,23 @@ profile {{.Name}} flags=(attach_disconnected,mediate_deleted) { ` type data struct { - Name string - Imports []string - InnerImports []string - Version int + Name string + Imports []string + InnerImports []string + DaemonProfile string + Version int +} + +func cleanProfileName(profile string) string { + // Normally profiles are suffixed by " (enforce)". AppArmor profiles cannot + // contain spaces so this doesn't restrict daemon profile names. + if parts := strings.SplitN(profile, " ", 2); len(parts) >= 1 { + profile = parts[0] + } + if profile == "" { + profile = "unconfined" + } + return profile } func loadData(name string) (*data, error) { @@ -100,6 +128,16 @@ func loadData(name string) (*data, error) { return nil, errors.Wrap(err, "get apparmor_parser version") } p.Version = ver + + // Figure out the daemon profile. + currentProfile, err := ioutil.ReadFile("/proc/self/attr/current") + if err != nil { + // If we couldn't get the daemon profile, assume we are running + // unconfined which is generally the default. + currentProfile = nil + } + p.DaemonProfile = cleanProfileName(string(currentProfile)) + return &p, nil } diff --git a/contrib/apparmor/template_test.go b/contrib/apparmor/template_test.go new file mode 100644 index 000000000000..c49306a27e37 --- /dev/null +++ b/contrib/apparmor/template_test.go @@ -0,0 +1,18 @@ +// +build linux + +package apparmor + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestCleanProfileName(t *testing.T) { + assert.Equal(t, cleanProfileName(""), "unconfined") + assert.Equal(t, cleanProfileName("unconfined"), "unconfined") + assert.Equal(t, cleanProfileName("unconfined (enforce)"), "unconfined") + assert.Equal(t, cleanProfileName("docker-default"), "docker-default") + assert.Equal(t, cleanProfileName("foo"), "foo") + assert.Equal(t, cleanProfileName("foo (enforce)"), "foo") +}