[lxc-devel] [lxd/master] Fix AppArmor stack handling with nesting
stgraber on Github
lxc-bot at linuxcontainers.org
Thu Apr 20 04:21:04 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 844 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170420/e90f8f6f/attachment.bin>
-------------- next part --------------
From 546e2a60809a108a1f505b99c6edbda52b12c739 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Thu, 20 Apr 2017 00:17:42 -0400
Subject: [PATCH] Fix AppArmor stack handling with nesting
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This does the following
- Re-work detection code to always fill all the various AppArmor variables
- Add detection of LXD being run in an AppArmor stacked configuration
- If running stacked (nesting), then load a per-container profile but
don't attempt to setup a second level of stacking as this isn't
supported by AppArmor.
- Treat a security.privileged=true container inside an unprivileged
container the same as running an unprivileged container.
Closes #3172
Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
lxd/apparmor.go | 11 +++--
lxd/container_lxc.go | 4 +-
lxd/daemon.go | 132 ++++++++++++++++++++++++++-------------------------
3 files changed, 75 insertions(+), 72 deletions(-)
diff --git a/lxd/apparmor.go b/lxd/apparmor.go
index f4563b2..47a1881 100644
--- a/lxd/apparmor.go
+++ b/lxd/apparmor.go
@@ -319,7 +319,7 @@ func getAAProfileContent(c container) string {
profile += " mount fstype=cgroup -> /sys/fs/cgroup/**,\n"
}
- if aaStacking {
+ if aaStacking && !aaStacked {
profile += "\n ### Feature: apparmor stacking\n"
profile += ` ### Configuration: apparmor profile loading (in namespace)
deny /sys/k[^e]*{,/**} wklx,
@@ -357,12 +357,12 @@ func getAAProfileContent(c container) string {
// Apply nesting bits
profile += "\n ### Configuration: nesting\n"
profile += strings.TrimLeft(AA_PROFILE_NESTING, "\n")
- if !aaStacking || c.IsPrivileged() {
+ if !aaStacking || aaStacked {
profile += fmt.Sprintf(" change_profile -> \"%s\",\n", AAProfileFull(c))
}
}
- if !c.IsPrivileged() {
+ if !c.IsPrivileged() || runningInUserns {
// Apply unprivileged bits
profile += "\n ### Configuration: unprivileged containers\n"
profile += strings.TrimLeft(AA_PROFILE_UNPRIVILEGED, "\n")
@@ -404,7 +404,7 @@ func runApparmor(command string, c container) error {
}
func mkApparmorNamespace(namespace string) error {
- if !aaStacking {
+ if !aaStacking || aaStacked {
return nil
}
@@ -470,7 +470,7 @@ func AADestroy(c container) error {
return nil
}
- if aaStacking {
+ if aaStacking && !aaStacked {
p := path.Join("/sys/kernel/security/apparmor/policy/namespaces", AANamespace(c))
if err := os.Remove(p); err != nil {
logger.Error("error removing apparmor namespace", log.Ctx{"err": err, "ns": p})
@@ -508,6 +508,7 @@ func aaProfile() string {
if err == nil {
return strings.TrimSpace(string(contents))
}
+
return ""
}
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 52dfbec..4ed8847 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -722,7 +722,7 @@ func (c *containerLXC) initLXC() error {
// Base config
toDrop := "sys_time sys_module sys_rawio"
- if !aaStacking {
+ if !aaStacking || aaStacked {
toDrop = toDrop + " mac_admin mac_override"
}
@@ -941,7 +941,7 @@ func (c *containerLXC) initLXC() error {
* the old way of nesting, i.e. using the parent's
* profile.
*/
- if aaStacking {
+ if aaStacking && !aaStacked {
profile = fmt.Sprintf("%s//&:%s:", profile, AANamespace(c))
}
diff --git a/lxd/daemon.go b/lxd/daemon.go
index cce17e7..ce0f12a 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -40,10 +40,11 @@ import (
)
// AppArmor
-var aaAdmin = true
-var aaAvailable = true
+var aaAvailable = false
+var aaAdmin = false
var aaConfined = false
var aaStacking = false
+var aaStacked = false
// CGroup
var cgBlkioController = false
@@ -545,90 +546,91 @@ func (d *Daemon) Init() error {
/* Detect user namespaces */
runningInUserns = shared.RunningInUserNS()
- /* Detect AppArmor support */
- if aaAvailable && os.Getenv("LXD_SECURITY_APPARMOR") == "false" {
- aaAvailable = false
- aaAdmin = false
+ /* Detect AppArmor availability */
+ _, err = exec.LookPath("apparmor_parser")
+ if os.Getenv("LXD_SECURITY_APPARMOR") == "false" {
logger.Warnf("AppArmor support has been manually disabled")
- }
-
- if aaAvailable && !shared.IsDir("/sys/kernel/security/apparmor") {
- aaAvailable = false
- aaAdmin = false
+ } else if !shared.IsDir("/sys/kernel/security/apparmor") {
logger.Warnf("AppArmor support has been disabled because of lack of kernel support")
- }
-
- _, err = exec.LookPath("apparmor_parser")
- if aaAvailable && err != nil {
- aaAvailable = false
- aaAdmin = false
+ } else if err != nil {
logger.Warnf("AppArmor support has been disabled because 'apparmor_parser' couldn't be found")
+ } else {
+ aaAvailable = true
}
- /* Detect AppArmor admin support */
- if aaAdmin && !haveMacAdmin() {
- aaAdmin = false
- logger.Warnf("Per-container AppArmor profiles are disabled because the mac_admin capability is missing.")
- }
+ /* Detect AppArmor stacking support */
+ aaCanStack := func() bool {
+ contentBytes, err := ioutil.ReadFile("/sys/kernel/security/apparmor/features/domain/stack")
+ if err != nil {
+ return false
+ }
- if aaAdmin && runningInUserns {
- aaAdmin = false
- logger.Warnf("Per-container AppArmor profiles are disabled because LXD is running in an unprivileged container.")
- }
+ if string(contentBytes) != "yes\n" {
+ return false
+ }
- /* Detect AppArmor confinment */
- if !aaConfined {
- profile := aaProfile()
- if profile != "unconfined" && profile != "" {
- aaConfined = true
- logger.Warnf("Per-container AppArmor profiles are disabled because LXD is already protected by AppArmor.")
+ contentBytes, err = ioutil.ReadFile("/sys/kernel/security/apparmor/features/domain/version")
+ if err != nil {
+ return false
}
- }
- if aaAvailable {
- canStack := func() bool {
- contentBytes, err := ioutil.ReadFile("/sys/kernel/security/apparmor/features/domain/stack")
- if err != nil {
- return false
- }
+ content := string(contentBytes)
- if string(contentBytes) != "yes\n" {
- return false
- }
+ parts := strings.Split(strings.TrimSpace(content), ".")
- contentBytes, err = ioutil.ReadFile("/sys/kernel/security/apparmor/features/domain/version")
- if err != nil {
- return false
- }
-
- content := string(contentBytes)
-
- parts := strings.Split(strings.TrimSpace(content), ".")
+ if len(parts) == 0 {
+ logger.Warn("unknown apparmor domain version", log.Ctx{"version": content})
+ return false
+ }
- if len(parts) == 0 {
- logger.Warn("unknown apparmor domain version", log.Ctx{"version": content})
- return false
- }
+ major, err := strconv.Atoi(parts[0])
+ if err != nil {
+ logger.Warn("unknown apparmor domain version", log.Ctx{"version": content})
+ return false
+ }
- major, err := strconv.Atoi(parts[0])
+ minor := 0
+ if len(parts) == 2 {
+ minor, err = strconv.Atoi(parts[1])
if err != nil {
logger.Warn("unknown apparmor domain version", log.Ctx{"version": content})
return false
}
+ }
- minor := 0
- if len(parts) == 2 {
- minor, err = strconv.Atoi(parts[1])
- if err != nil {
- logger.Warn("unknown apparmor domain version", log.Ctx{"version": content})
- return false
- }
- }
+ return major >= 1 && minor >= 2
+ }
+
+ aaStacking = aaCanStack()
+
+ /* Detect existing AppArmor stack */
+ if shared.PathExists("/sys/kernel/security/apparmor/.ns_stacked") {
+ contentBytes, err := ioutil.ReadFile("/sys/kernel/security/apparmor/.ns_stacked")
+ if err == nil && string(contentBytes) == "yes\n" {
+ aaStacked = true
+ }
+ }
- return major >= 1 && minor >= 2
+ /* Detect AppArmor admin support */
+ if !haveMacAdmin() {
+ if aaAvailable {
+ logger.Warnf("Per-container AppArmor profiles are disabled because the mac_admin capability is missing.")
}
+ } else if runningInUserns && !aaStacked {
+ if aaAvailable {
+ logger.Warnf("Per-container AppArmor profiles are disabled because LXD is running in an unprivileged container without stacking.")
+ }
+ } else {
+ aaAdmin = true
+ }
- aaStacking = canStack()
+ /* Detect AppArmor confinment */
+ profile := aaProfile()
+ if profile != "unconfined" && profile != "" {
+ if aaAvailable {
+ logger.Warnf("Per-container AppArmor profiles are disabled because LXD is already protected by AppArmor.")
+ }
+ aaConfined = true
}
/* Detect CGroup support */
More information about the lxc-devel
mailing list