[lxc-devel] [lxd/master] AppArmor text templating

stgraber on Github lxc-bot at linuxcontainers.org
Wed Jul 15 22:59:00 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200715/921a5a1b/attachment-0001.bin>
-------------- next part --------------
From a582ace38deb84b89141149cf5a6c746ce1dda87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Jul 2020 16:42:06 -0400
Subject: [PATCH 1/2] lxd/apparmor: Use templating
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/apparmor/apparmor.go  | 598 ++------------------------------------
 lxd/apparmor/container.go | 573 ++++++++++++++++++++++++++++++++++++
 2 files changed, 593 insertions(+), 578 deletions(-)
 create mode 100644 lxd/apparmor/container.go

diff --git a/lxd/apparmor/apparmor.go b/lxd/apparmor/apparmor.go
index ceec2dece0..d49ab15851 100644
--- a/lxd/apparmor/apparmor.go
+++ b/lxd/apparmor/apparmor.go
@@ -25,505 +25,6 @@ const (
 
 var aaPath = shared.VarPath("security", "apparmor")
 
-const profileBase = `
-  ### Base profile
-  capability,
-  dbus,
-  file,
-  network,
-  umount,
-
-  # Hide common denials
-  deny mount options=(ro, remount) -> /,
-  deny mount options=(ro, remount, silent) -> /,
-
-  # Allow normal signal handling
-  signal (receive),
-  signal peer=@{profile_name},
-
-  # Allow normal process handling
-  ptrace (readby),
-  ptrace (tracedby),
-  ptrace peer=@{profile_name},
-
-  # Handle binfmt
-  mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/,
-  deny /proc/sys/fs/binfmt_misc/{,**} rwklx,
-
-  # Handle cgroupfs
-  mount options=(ro, nosuid, nodev, noexec, remount, strictatime) -> /sys/fs/cgroup/,
-
-  # Handle configfs
-  mount fstype=configfs -> /sys/kernel/config/,
-  deny /sys/kernel/config/{,**} rwklx,
-
-  # Handle debugfs
-  mount fstype=debugfs -> /sys/kernel/debug/,
-  deny /sys/kernel/debug/{,**} rwklx,
-
-  # Handle efivarfs
-  mount fstype=efivarfs -> /sys/firmware/efi/efivars/,
-  deny /sys/firmware/efi/efivars/{,**} rwklx,
-
-  # Handle tracefs
-  mount fstype=tracefs -> /sys/kernel/tracing/,
-  deny /sys/kernel/tracing/{,**} rwklx,
-
-  # Handle fuse
-  mount fstype=fuse,
-  mount fstype=fuse.*,
-  mount fstype=fusectl -> /sys/fs/fuse/connections/,
-
-  # Handle hugetlbfs
-  mount fstype=hugetlbfs,
-
-  # Handle mqueue
-  mount fstype=mqueue,
-
-  # Handle proc
-  mount fstype=proc -> /proc/,
-  deny /proc/bus/** wklx,
-  deny /proc/kcore rwklx,
-  deny /proc/sysrq-trigger rwklx,
-  deny /proc/acpi/** rwklx,
-  deny /proc/sys/fs/** wklx,
-
-  # Handle securityfs (access handled separately)
-  mount fstype=securityfs -> /sys/kernel/security/,
-
-  # Handle sysfs (access handled below)
-  mount fstype=sysfs -> /sys/,
-  mount options=(rw, nosuid, nodev, noexec, remount) -> /sys/,
-
-  # Handle tmpfs
-  mount fstype=tmpfs,
-
-  # Allow limited modification of mount propagation
-  mount options=(rw,slave) -> /,
-  mount options=(rw,rslave) -> /,
-  mount options=(rw,shared) -> /,
-  mount options=(rw,rshared) -> /,
-  mount options=(rw,private) -> /,
-  mount options=(rw,rprivate) -> /,
-  mount options=(rw,unbindable) -> /,
-  mount options=(rw,runbindable) -> /,
-
-  # Allow various ro-bind-*re*-mounts
-  mount options=(ro,remount,bind) /[^spd]*{,/**},
-  mount options=(ro,remount,bind) /d[^e]*{,/**},
-  mount options=(ro,remount,bind) /de[^v]*{,/**},
-  mount options=(ro,remount,bind) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind) /dev?*{,/**},
-  mount options=(ro,remount,bind) /p[^r]*{,/**},
-  mount options=(ro,remount,bind) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind) /proc?*{,/**},
-  mount options=(ro,remount,bind) /s[^y]*{,/**},
-  mount options=(ro,remount,bind) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,nodev) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,nodev) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,nodev) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,nodev) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,nodev) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,nodev) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,nodev) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,nodev) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,nodev) /dev?*{,/**},
-  mount options=(ro,remount,bind,nodev) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,nodev) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,nodev) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,nodev) /proc?*{,/**},
-  mount options=(ro,remount,bind,nodev) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,nodev) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,nodev) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,nodev,nosuid) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /dev?*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /proc?*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,nodev,nosuid) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,noexec) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,noexec) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,noexec) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,noexec) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,noexec) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,noexec) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,noexec) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,noexec) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,noexec) /dev?*{,/**},
-  mount options=(ro,remount,bind,noexec) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,noexec) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,noexec) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,noexec) /proc?*{,/**},
-  mount options=(ro,remount,bind,noexec) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,noexec) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,noexec) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,noexec,nodev) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /dev?*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /proc?*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,noexec,nodev) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,noatime) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,noatime) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,noatime) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,noatime) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,noatime) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,noatime) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,noatime) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,noatime) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,noatime) /dev?*{,/**},
-  mount options=(ro,remount,bind,noatime) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,noatime) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,noatime) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,noatime) /proc?*{,/**},
-  mount options=(ro,remount,bind,noatime) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,noatime) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,noatime) /sys?*{,/**},
-
-  mount options=(ro,remount,noatime,bind) /[^spd]*{,/**},
-  mount options=(ro,remount,noatime,bind) /d[^e]*{,/**},
-  mount options=(ro,remount,noatime,bind) /de[^v]*{,/**},
-  mount options=(ro,remount,noatime,bind) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,noatime,bind) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,noatime,bind) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,noatime,bind) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,noatime,bind) /dev/[^.]*{,/**},
-  mount options=(ro,remount,noatime,bind) /dev?*{,/**},
-  mount options=(ro,remount,noatime,bind) /p[^r]*{,/**},
-  mount options=(ro,remount,noatime,bind) /pr[^o]*{,/**},
-  mount options=(ro,remount,noatime,bind) /pro[^c]*{,/**},
-  mount options=(ro,remount,noatime,bind) /proc?*{,/**},
-  mount options=(ro,remount,noatime,bind) /s[^y]*{,/**},
-  mount options=(ro,remount,noatime,bind) /sy[^s]*{,/**},
-  mount options=(ro,remount,noatime,bind) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,nosuid) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,nosuid) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /dev?*{,/**},
-  mount options=(ro,remount,bind,nosuid) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /proc?*{,/**},
-  mount options=(ro,remount,bind,nosuid) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,nosuid) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,nosuid,nodev) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /dev?*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /proc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,nosuid,nodev) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,nosuid,noexec) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /dev?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /proc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /proc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,nodev) /sys?*{,/**},
-
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /[^spd]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /d[^e]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /de[^v]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /p[^r]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /proc?*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /s[^y]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /sys?*{,/**},
-
-  # Allow bind-mounts of anything except /proc, /sys and /dev/.lxc
-  mount options=(rw,bind) /[^spd]*{,/**},
-  mount options=(rw,bind) /d[^e]*{,/**},
-  mount options=(rw,bind) /de[^v]*{,/**},
-  mount options=(rw,bind) /dev/.[^l]*{,/**},
-  mount options=(rw,bind) /dev/.l[^x]*{,/**},
-  mount options=(rw,bind) /dev/.lx[^c]*{,/**},
-  mount options=(rw,bind) /dev/.lxc?*{,/**},
-  mount options=(rw,bind) /dev/[^.]*{,/**},
-  mount options=(rw,bind) /dev?*{,/**},
-  mount options=(rw,bind) /p[^r]*{,/**},
-  mount options=(rw,bind) /pr[^o]*{,/**},
-  mount options=(rw,bind) /pro[^c]*{,/**},
-  mount options=(rw,bind) /proc?*{,/**},
-  mount options=(rw,bind) /s[^y]*{,/**},
-  mount options=(rw,bind) /sy[^s]*{,/**},
-  mount options=(rw,bind) /sys?*{,/**},
-
-  # Allow rbind-mounts of anything except /, /dev, /proc and /sys
-  mount options=(rw,rbind) /[^spd]*{,/**},
-  mount options=(rw,rbind) /d[^e]*{,/**},
-  mount options=(rw,rbind) /de[^v]*{,/**},
-  mount options=(rw,rbind) /dev?*{,/**},
-  mount options=(rw,rbind) /p[^r]*{,/**},
-  mount options=(rw,rbind) /pr[^o]*{,/**},
-  mount options=(rw,rbind) /pro[^c]*{,/**},
-  mount options=(rw,rbind) /proc?*{,/**},
-  mount options=(rw,rbind) /s[^y]*{,/**},
-  mount options=(rw,rbind) /sy[^s]*{,/**},
-  mount options=(rw,rbind) /sys?*{,/**},
-
-  # Allow read-only bind-mounts of anything except /proc, /sys and /dev/.lxc
-  mount options=(ro,remount,bind) /[^spd]*{,/**},
-  mount options=(ro,remount,bind) /d[^e]*{,/**},
-  mount options=(ro,remount,bind) /de[^v]*{,/**},
-  mount options=(ro,remount,bind) /dev/.[^l]*{,/**},
-  mount options=(ro,remount,bind) /dev/.l[^x]*{,/**},
-  mount options=(ro,remount,bind) /dev/.lx[^c]*{,/**},
-  mount options=(ro,remount,bind) /dev/.lxc?*{,/**},
-  mount options=(ro,remount,bind) /dev/[^.]*{,/**},
-  mount options=(ro,remount,bind) /dev?*{,/**},
-  mount options=(ro,remount,bind) /p[^r]*{,/**},
-  mount options=(ro,remount,bind) /pr[^o]*{,/**},
-  mount options=(ro,remount,bind) /pro[^c]*{,/**},
-  mount options=(ro,remount,bind) /proc?*{,/**},
-  mount options=(ro,remount,bind) /s[^y]*{,/**},
-  mount options=(ro,remount,bind) /sy[^s]*{,/**},
-  mount options=(ro,remount,bind) /sys?*{,/**},
-
-  # Allow moving mounts except for /proc, /sys and /dev/.lxc
-  mount options=(rw,move) /[^spd]*{,/**},
-  mount options=(rw,move) /d[^e]*{,/**},
-  mount options=(rw,move) /de[^v]*{,/**},
-  mount options=(rw,move) /dev/.[^l]*{,/**},
-  mount options=(rw,move) /dev/.l[^x]*{,/**},
-  mount options=(rw,move) /dev/.lx[^c]*{,/**},
-  mount options=(rw,move) /dev/.lxc?*{,/**},
-  mount options=(rw,move) /dev/[^.]*{,/**},
-  mount options=(rw,move) /dev?*{,/**},
-  mount options=(rw,move) /p[^r]*{,/**},
-  mount options=(rw,move) /pr[^o]*{,/**},
-  mount options=(rw,move) /pro[^c]*{,/**},
-  mount options=(rw,move) /proc?*{,/**},
-  mount options=(rw,move) /s[^y]*{,/**},
-  mount options=(rw,move) /sy[^s]*{,/**},
-  mount options=(rw,move) /sys?*{,/**},
-
-  # Block dangerous paths under /proc/sys
-  deny /proc/sys/[^kn]*{,/**} wklx,
-  deny /proc/sys/k[^e]*{,/**} wklx,
-  deny /proc/sys/ke[^r]*{,/**} wklx,
-  deny /proc/sys/ker[^n]*{,/**} wklx,
-  deny /proc/sys/kern[^e]*{,/**} wklx,
-  deny /proc/sys/kerne[^l]*{,/**} wklx,
-  deny /proc/sys/kernel/[^smhd]*{,/**} wklx,
-  deny /proc/sys/kernel/d[^o]*{,/**} wklx,
-  deny /proc/sys/kernel/do[^m]*{,/**} wklx,
-  deny /proc/sys/kernel/dom[^a]*{,/**} wklx,
-  deny /proc/sys/kernel/doma[^i]*{,/**} wklx,
-  deny /proc/sys/kernel/domai[^n]*{,/**} wklx,
-  deny /proc/sys/kernel/domain[^n]*{,/**} wklx,
-  deny /proc/sys/kernel/domainn[^a]*{,/**} wklx,
-  deny /proc/sys/kernel/domainna[^m]*{,/**} wklx,
-  deny /proc/sys/kernel/domainnam[^e]*{,/**} wklx,
-  deny /proc/sys/kernel/domainname?*{,/**} wklx,
-  deny /proc/sys/kernel/h[^o]*{,/**} wklx,
-  deny /proc/sys/kernel/ho[^s]*{,/**} wklx,
-  deny /proc/sys/kernel/hos[^t]*{,/**} wklx,
-  deny /proc/sys/kernel/host[^n]*{,/**} wklx,
-  deny /proc/sys/kernel/hostn[^a]*{,/**} wklx,
-  deny /proc/sys/kernel/hostna[^m]*{,/**} wklx,
-  deny /proc/sys/kernel/hostnam[^e]*{,/**} wklx,
-  deny /proc/sys/kernel/hostname?*{,/**} wklx,
-  deny /proc/sys/kernel/m[^s]*{,/**} wklx,
-  deny /proc/sys/kernel/ms[^g]*{,/**} wklx,
-  deny /proc/sys/kernel/msg*/** wklx,
-  deny /proc/sys/kernel/s[^he]*{,/**} wklx,
-  deny /proc/sys/kernel/se[^m]*{,/**} wklx,
-  deny /proc/sys/kernel/sem*/** wklx,
-  deny /proc/sys/kernel/sh[^m]*{,/**} wklx,
-  deny /proc/sys/kernel/shm*/** wklx,
-  deny /proc/sys/kernel?*{,/**} wklx,
-  deny /proc/sys/n[^e]*{,/**} wklx,
-  deny /proc/sys/ne[^t]*{,/**} wklx,
-  deny /proc/sys/net?*{,/**} wklx,
-
-  # Block dangerous paths under /sys
-  deny /sys/[^fdck]*{,/**} wklx,
-  deny /sys/c[^l]*{,/**} wklx,
-  deny /sys/cl[^a]*{,/**} wklx,
-  deny /sys/cla[^s]*{,/**} wklx,
-  deny /sys/clas[^s]*{,/**} wklx,
-  deny /sys/class/[^n]*{,/**} wklx,
-  deny /sys/class/n[^e]*{,/**} wklx,
-  deny /sys/class/ne[^t]*{,/**} wklx,
-  deny /sys/class/net?*{,/**} wklx,
-  deny /sys/class?*{,/**} wklx,
-  deny /sys/d[^e]*{,/**} wklx,
-  deny /sys/de[^v]*{,/**} wklx,
-  deny /sys/dev[^i]*{,/**} wklx,
-  deny /sys/devi[^c]*{,/**} wklx,
-  deny /sys/devic[^e]*{,/**} wklx,
-  deny /sys/device[^s]*{,/**} wklx,
-  deny /sys/devices/[^v]*{,/**} wklx,
-  deny /sys/devices/v[^i]*{,/**} wklx,
-  deny /sys/devices/vi[^r]*{,/**} wklx,
-  deny /sys/devices/vir[^t]*{,/**} wklx,
-  deny /sys/devices/virt[^u]*{,/**} wklx,
-  deny /sys/devices/virtu[^a]*{,/**} wklx,
-  deny /sys/devices/virtua[^l]*{,/**} wklx,
-  deny /sys/devices/virtual/[^n]*{,/**} wklx,
-  deny /sys/devices/virtual/n[^e]*{,/**} wklx,
-  deny /sys/devices/virtual/ne[^t]*{,/**} wklx,
-  deny /sys/devices/virtual/net?*{,/**} wklx,
-  deny /sys/devices/virtual?*{,/**} wklx,
-  deny /sys/devices?*{,/**} wklx,
-  deny /sys/f[^s]*{,/**} wklx,
-  deny /sys/fs/[^c]*{,/**} wklx,
-  deny /sys/fs/c[^g]*{,/**} wklx,
-  deny /sys/fs/cg[^r]*{,/**} wklx,
-  deny /sys/fs/cgr[^o]*{,/**} wklx,
-  deny /sys/fs/cgro[^u]*{,/**} wklx,
-  deny /sys/fs/cgrou[^p]*{,/**} wklx,
-  deny /sys/fs/cgroup?*{,/**} wklx,
-  deny /sys/fs?*{,/**} wklx,
-`
-
-const profileNesting = `
-  pivot_root,
-
-  # Allow sending signals and tracing children namespaces
-  ptrace,
-  signal,
-
-  # Prevent access to hidden proc/sys mounts
-  deny /dev/.lxc/proc/** rw,
-  deny /dev/.lxc/sys/** rw,
-
-  # Allow mounting proc and sysfs in the container
-  mount fstype=proc -> /usr/lib/*/lxc/**,
-  mount fstype=sysfs -> /usr/lib/*/lxc/**,
-
-  # Allow nested LXD
-  mount none -> /var/lib/lxd/shmounts/,
-  mount /var/lib/lxd/shmounts/ -> /var/lib/lxd/shmounts/,
-  mount options=bind /var/lib/lxd/shmounts/** -> /var/lib/lxd/**,
-
-  # FIXME: There doesn't seem to be a way to ask for:
-  # mount options=(ro,nosuid,nodev,noexec,remount,bind),
-  # as we always get mount to $cdir/proc/sys with those flags denied
-  # So allow all mounts until that is straightened out:
-  mount,
-`
-
-const profileUnprivileged = `
-  pivot_root,
-
-  # Allow modifying mount propagation
-  mount options=(rw,slave) -> **,
-  mount options=(rw,rslave) -> **,
-  mount options=(rw,shared) -> **,
-  mount options=(rw,rshared) -> **,
-  mount options=(rw,private) -> **,
-  mount options=(rw,rprivate) -> **,
-  mount options=(rw,unbindable) -> **,
-  mount options=(rw,runbindable) -> **,
-
-  # Allow all bind-mounts
-  mount options=(rw,bind) / -> /**,
-  mount options=(rw,bind) /** -> /**,
-  mount options=(rw,rbind) / -> /**,
-  mount options=(rw,rbind) /** -> /**,
-
-  # Allow common combinations of bind/remount
-  # NOTE: AppArmor bug effectively turns those into wildcards mount allow
-  mount options=(ro,remount,bind),
-  mount options=(ro,remount,bind,nodev),
-  mount options=(ro,remount,bind,nodev,nosuid),
-  mount options=(ro,remount,bind,noexec),
-  mount options=(ro,remount,bind,noexec,nodev),
-  mount options=(ro,remount,bind,nosuid),
-  mount options=(ro,remount,bind,nosuid,nodev),
-  mount options=(ro,remount,bind,nosuid,noexec),
-  mount options=(ro,remount,bind,nosuid,noexec,nodev),
-  mount options=(ro,remount,bind,nosuid,noexec,strictatime),
-
-  # Allow remounting things read-only
-  mount options=(ro,remount) /,
-  mount options=(ro,remount) /**,
-`
-
 type instance interface {
 	Project() string
 	Name() string
@@ -569,91 +70,32 @@ func profileShort(c instance) string {
 // getProfileContent generates the apparmor profile template from the given container.
 // This includes the stock lxc includes as well as stuff from raw.apparmor.
 func getAAProfileContent(state *state.State, c instance) string {
-	profile := strings.TrimLeft(profileBase, "\n")
-
-	// Apply new features
-	if aaParserSupports("unix") {
-		profile += `
-  ### Feature: unix
-  # Allow receive via unix sockets from anywhere
-  unix (receive),
-
-  # Allow all unix in the container
-  unix peer=(label=@{profile_name}),
-`
-	}
-
-	// Apply cgns bits
-	if shared.PathExists("/proc/self/ns/cgroup") {
-		profile += "\n  ### Feature: cgroup namespace\n"
-		profile += "  mount fstype=cgroup -> /sys/fs/cgroup/**,\n"
-		profile += "  mount fstype=cgroup2 -> /sys/fs/cgroup/**,\n"
-	}
-
-	if state.OS.AppArmorStacking && !state.OS.AppArmorStacked {
-		profile += "\n  ### Feature: apparmor stacking\n"
-		profile += `  ### Configuration: apparmor profile loading (in namespace)
-  deny /sys/k[^e]*{,/**} wklx,
-  deny /sys/ke[^r]*{,/**} wklx,
-  deny /sys/ker[^n]*{,/**} wklx,
-  deny /sys/kern[^e]*{,/**} wklx,
-  deny /sys/kerne[^l]*{,/**} wklx,
-  deny /sys/kernel/[^s]*{,/**} wklx,
-  deny /sys/kernel/s[^e]*{,/**} wklx,
-  deny /sys/kernel/se[^c]*{,/**} wklx,
-  deny /sys/kernel/sec[^u]*{,/**} wklx,
-  deny /sys/kernel/secu[^r]*{,/**} wklx,
-  deny /sys/kernel/secur[^i]*{,/**} wklx,
-  deny /sys/kernel/securi[^t]*{,/**} wklx,
-  deny /sys/kernel/securit[^y]*{,/**} wklx,
-  deny /sys/kernel/security/[^a]*{,/**} wklx,
-  deny /sys/kernel/security/a[^p]*{,/**} wklx,
-  deny /sys/kernel/security/ap[^p]*{,/**} wklx,
-  deny /sys/kernel/security/app[^a]*{,/**} wklx,
-  deny /sys/kernel/security/appa[^r]*{,/**} wklx,
-  deny /sys/kernel/security/appar[^m]*{,/**} wklx,
-  deny /sys/kernel/security/apparm[^o]*{,/**} wklx,
-  deny /sys/kernel/security/apparmo[^r]*{,/**} wklx,
-  deny /sys/kernel/security/apparmor?*{,/**} wklx,
-  deny /sys/kernel/security?*{,/**} wklx,
-  deny /sys/kernel?*{,/**} wklx,
-`
-		profile += fmt.Sprintf("  change_profile -> \":%s:*\",\n", Namespace(c))
-		profile += fmt.Sprintf("  change_profile -> \":%s://*\",\n", Namespace(c))
-	} else {
-		profile += "\n  ### Feature: apparmor stacking (not present)\n"
-		profile += "  deny /sys/k*{,/**} wklx,\n"
-	}
-
-	if c.IsNesting() {
-		// Apply nesting bits
-		profile += "\n  ### Configuration: nesting\n"
-		profile += strings.TrimLeft(profileNesting, "\n")
-		if !state.OS.AppArmorStacking || state.OS.AppArmorStacked {
-			profile += fmt.Sprintf("  change_profile -> \"%s\",\n", ProfileFull(c))
-		}
-	}
-
-	if !c.IsPrivileged() || state.OS.RunningInUserNS {
-		// Apply unprivileged bits
-		profile += "\n  ### Configuration: unprivileged containers\n"
-		profile += strings.TrimLeft(profileUnprivileged, "\n")
-	}
-
-	// Append raw.apparmor
+	// Prepare raw.apparmor.
+	rawContent := ""
 	rawApparmor, ok := c.ExpandedConfig()["raw.apparmor"]
 	if ok {
-		profile += "\n  ### Configuration: raw.apparmor\n"
 		for _, line := range strings.Split(strings.Trim(rawApparmor, "\n"), "\n") {
-			profile += fmt.Sprintf("  %s\n", line)
+			rawContent += fmt.Sprintf("  %s\n", line)
 		}
 	}
 
-	return fmt.Sprintf(`#include <tunables/global>
-profile "%s" flags=(attach_disconnected,mediate_deleted) {
-%s
-}
-`, ProfileFull(c), strings.Trim(profile, "\n"))
+	// Render the profile.
+	var sb *strings.Builder = &strings.Builder{}
+	err := containerProfile.Execute(sb, map[string]interface{}{
+		"feature_unix":     aaParserSupports("unix"),
+		"feature_cgns":     shared.PathExists("/proc/self/ns/cgroup"),
+		"feature_stacking": state.OS.AppArmorStacking && !state.OS.AppArmorStacked,
+		"namespace":        Namespace(c),
+		"nesting":          c.IsNesting(),
+		"name":             ProfileFull(c),
+		"unprivileged":     !c.IsPrivileged() || state.OS.RunningInUserNS,
+		"raw":              rawContent,
+	})
+	if err != nil {
+		return ""
+	}
+
+	return sb.String()
 }
 
 func runApparmor(state *state.State, command string, c instance) error {
diff --git a/lxd/apparmor/container.go b/lxd/apparmor/container.go
new file mode 100644
index 0000000000..02a08da532
--- /dev/null
+++ b/lxd/apparmor/container.go
@@ -0,0 +1,573 @@
+package apparmor
+
+import (
+	"text/template"
+)
+
+var containerProfile = template.Must(template.New("containerProfile").Parse(`#include <tunables/global>
+profile "{{ .name }}" flags=(attach_disconnected,mediate_deleted) {
+  ### Base profile
+  capability,
+  dbus,
+  file,
+  network,
+  umount,
+
+  # Hide common denials
+  deny mount options=(ro, remount) -> /,
+  deny mount options=(ro, remount, silent) -> /,
+
+  # Allow normal signal handling
+  signal (receive),
+  signal peer=@{profile_name},
+
+  # Allow normal process handling
+  ptrace (readby),
+  ptrace (tracedby),
+  ptrace peer=@{profile_name},
+
+  # Handle binfmt
+  mount fstype=binfmt_misc -> /proc/sys/fs/binfmt_misc/,
+  deny /proc/sys/fs/binfmt_misc/{,**} rwklx,
+
+  # Handle cgroupfs
+  mount options=(ro, nosuid, nodev, noexec, remount, strictatime) -> /sys/fs/cgroup/,
+
+  # Handle configfs
+  mount fstype=configfs -> /sys/kernel/config/,
+  deny /sys/kernel/config/{,**} rwklx,
+
+  # Handle debugfs
+  mount fstype=debugfs -> /sys/kernel/debug/,
+  deny /sys/kernel/debug/{,**} rwklx,
+
+  # Handle efivarfs
+  mount fstype=efivarfs -> /sys/firmware/efi/efivars/,
+  deny /sys/firmware/efi/efivars/{,**} rwklx,
+
+  # Handle tracefs
+  mount fstype=tracefs -> /sys/kernel/tracing/,
+  deny /sys/kernel/tracing/{,**} rwklx,
+
+  # Handle fuse
+  mount fstype=fuse,
+  mount fstype=fuse.*,
+  mount fstype=fusectl -> /sys/fs/fuse/connections/,
+
+  # Handle hugetlbfs
+  mount fstype=hugetlbfs,
+
+  # Handle mqueue
+  mount fstype=mqueue,
+
+  # Handle proc
+  mount fstype=proc -> /proc/,
+  deny /proc/bus/** wklx,
+  deny /proc/kcore rwklx,
+  deny /proc/sysrq-trigger rwklx,
+  deny /proc/acpi/** rwklx,
+  deny /proc/sys/fs/** wklx,
+
+  # Handle securityfs (access handled separately)
+  mount fstype=securityfs -> /sys/kernel/security/,
+
+  # Handle sysfs (access handled below)
+  mount fstype=sysfs -> /sys/,
+  mount options=(rw, nosuid, nodev, noexec, remount) -> /sys/,
+
+  # Handle tmpfs
+  mount fstype=tmpfs,
+
+  # Allow limited modification of mount propagation
+  mount options=(rw,slave) -> /,
+  mount options=(rw,rslave) -> /,
+  mount options=(rw,shared) -> /,
+  mount options=(rw,rshared) -> /,
+  mount options=(rw,private) -> /,
+  mount options=(rw,rprivate) -> /,
+  mount options=(rw,unbindable) -> /,
+  mount options=(rw,runbindable) -> /,
+
+  # Allow various ro-bind-*re*-mounts
+  mount options=(ro,remount,bind) /[^spd]*{,/**},
+  mount options=(ro,remount,bind) /d[^e]*{,/**},
+  mount options=(ro,remount,bind) /de[^v]*{,/**},
+  mount options=(ro,remount,bind) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind) /dev?*{,/**},
+  mount options=(ro,remount,bind) /p[^r]*{,/**},
+  mount options=(ro,remount,bind) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind) /proc?*{,/**},
+  mount options=(ro,remount,bind) /s[^y]*{,/**},
+  mount options=(ro,remount,bind) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,nodev) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,nodev) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,nodev) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,nodev) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,nodev) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,nodev) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,nodev) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,nodev) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,nodev) /dev?*{,/**},
+  mount options=(ro,remount,bind,nodev) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,nodev) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,nodev) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,nodev) /proc?*{,/**},
+  mount options=(ro,remount,bind,nodev) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,nodev) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,nodev) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,nodev,nosuid) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /dev?*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /proc?*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,nodev,nosuid) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,noexec) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,noexec) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,noexec) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,noexec) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,noexec) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,noexec) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,noexec) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,noexec) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,noexec) /dev?*{,/**},
+  mount options=(ro,remount,bind,noexec) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,noexec) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,noexec) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,noexec) /proc?*{,/**},
+  mount options=(ro,remount,bind,noexec) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,noexec) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,noexec) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,noexec,nodev) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /dev?*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /proc?*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,noexec,nodev) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,noatime) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,noatime) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,noatime) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,noatime) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,noatime) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,noatime) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,noatime) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,noatime) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,noatime) /dev?*{,/**},
+  mount options=(ro,remount,bind,noatime) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,noatime) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,noatime) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,noatime) /proc?*{,/**},
+  mount options=(ro,remount,bind,noatime) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,noatime) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,noatime) /sys?*{,/**},
+
+  mount options=(ro,remount,noatime,bind) /[^spd]*{,/**},
+  mount options=(ro,remount,noatime,bind) /d[^e]*{,/**},
+  mount options=(ro,remount,noatime,bind) /de[^v]*{,/**},
+  mount options=(ro,remount,noatime,bind) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,noatime,bind) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,noatime,bind) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,noatime,bind) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,noatime,bind) /dev/[^.]*{,/**},
+  mount options=(ro,remount,noatime,bind) /dev?*{,/**},
+  mount options=(ro,remount,noatime,bind) /p[^r]*{,/**},
+  mount options=(ro,remount,noatime,bind) /pr[^o]*{,/**},
+  mount options=(ro,remount,noatime,bind) /pro[^c]*{,/**},
+  mount options=(ro,remount,noatime,bind) /proc?*{,/**},
+  mount options=(ro,remount,noatime,bind) /s[^y]*{,/**},
+  mount options=(ro,remount,noatime,bind) /sy[^s]*{,/**},
+  mount options=(ro,remount,noatime,bind) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,nosuid) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,nosuid) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /dev?*{,/**},
+  mount options=(ro,remount,bind,nosuid) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /proc?*{,/**},
+  mount options=(ro,remount,bind,nosuid) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,nosuid) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,nosuid,nodev) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /dev?*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /proc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,nosuid,nodev) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,nosuid,noexec) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /dev?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /proc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /dev?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /proc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,nodev) /sys?*{,/**},
+
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /[^spd]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /d[^e]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /de[^v]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /dev?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /p[^r]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /proc?*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /s[^y]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime) /sys?*{,/**},
+
+  # Allow bind-mounts of anything except /proc, /sys and /dev/.lxc
+  mount options=(rw,bind) /[^spd]*{,/**},
+  mount options=(rw,bind) /d[^e]*{,/**},
+  mount options=(rw,bind) /de[^v]*{,/**},
+  mount options=(rw,bind) /dev/.[^l]*{,/**},
+  mount options=(rw,bind) /dev/.l[^x]*{,/**},
+  mount options=(rw,bind) /dev/.lx[^c]*{,/**},
+  mount options=(rw,bind) /dev/.lxc?*{,/**},
+  mount options=(rw,bind) /dev/[^.]*{,/**},
+  mount options=(rw,bind) /dev?*{,/**},
+  mount options=(rw,bind) /p[^r]*{,/**},
+  mount options=(rw,bind) /pr[^o]*{,/**},
+  mount options=(rw,bind) /pro[^c]*{,/**},
+  mount options=(rw,bind) /proc?*{,/**},
+  mount options=(rw,bind) /s[^y]*{,/**},
+  mount options=(rw,bind) /sy[^s]*{,/**},
+  mount options=(rw,bind) /sys?*{,/**},
+
+  # Allow rbind-mounts of anything except /, /dev, /proc and /sys
+  mount options=(rw,rbind) /[^spd]*{,/**},
+  mount options=(rw,rbind) /d[^e]*{,/**},
+  mount options=(rw,rbind) /de[^v]*{,/**},
+  mount options=(rw,rbind) /dev?*{,/**},
+  mount options=(rw,rbind) /p[^r]*{,/**},
+  mount options=(rw,rbind) /pr[^o]*{,/**},
+  mount options=(rw,rbind) /pro[^c]*{,/**},
+  mount options=(rw,rbind) /proc?*{,/**},
+  mount options=(rw,rbind) /s[^y]*{,/**},
+  mount options=(rw,rbind) /sy[^s]*{,/**},
+  mount options=(rw,rbind) /sys?*{,/**},
+
+  # Allow read-only bind-mounts of anything except /proc, /sys and /dev/.lxc
+  mount options=(ro,remount,bind) /[^spd]*{,/**},
+  mount options=(ro,remount,bind) /d[^e]*{,/**},
+  mount options=(ro,remount,bind) /de[^v]*{,/**},
+  mount options=(ro,remount,bind) /dev/.[^l]*{,/**},
+  mount options=(ro,remount,bind) /dev/.l[^x]*{,/**},
+  mount options=(ro,remount,bind) /dev/.lx[^c]*{,/**},
+  mount options=(ro,remount,bind) /dev/.lxc?*{,/**},
+  mount options=(ro,remount,bind) /dev/[^.]*{,/**},
+  mount options=(ro,remount,bind) /dev?*{,/**},
+  mount options=(ro,remount,bind) /p[^r]*{,/**},
+  mount options=(ro,remount,bind) /pr[^o]*{,/**},
+  mount options=(ro,remount,bind) /pro[^c]*{,/**},
+  mount options=(ro,remount,bind) /proc?*{,/**},
+  mount options=(ro,remount,bind) /s[^y]*{,/**},
+  mount options=(ro,remount,bind) /sy[^s]*{,/**},
+  mount options=(ro,remount,bind) /sys?*{,/**},
+
+  # Allow moving mounts except for /proc, /sys and /dev/.lxc
+  mount options=(rw,move) /[^spd]*{,/**},
+  mount options=(rw,move) /d[^e]*{,/**},
+  mount options=(rw,move) /de[^v]*{,/**},
+  mount options=(rw,move) /dev/.[^l]*{,/**},
+  mount options=(rw,move) /dev/.l[^x]*{,/**},
+  mount options=(rw,move) /dev/.lx[^c]*{,/**},
+  mount options=(rw,move) /dev/.lxc?*{,/**},
+  mount options=(rw,move) /dev/[^.]*{,/**},
+  mount options=(rw,move) /dev?*{,/**},
+  mount options=(rw,move) /p[^r]*{,/**},
+  mount options=(rw,move) /pr[^o]*{,/**},
+  mount options=(rw,move) /pro[^c]*{,/**},
+  mount options=(rw,move) /proc?*{,/**},
+  mount options=(rw,move) /s[^y]*{,/**},
+  mount options=(rw,move) /sy[^s]*{,/**},
+  mount options=(rw,move) /sys?*{,/**},
+
+  # Block dangerous paths under /proc/sys
+  deny /proc/sys/[^kn]*{,/**} wklx,
+  deny /proc/sys/k[^e]*{,/**} wklx,
+  deny /proc/sys/ke[^r]*{,/**} wklx,
+  deny /proc/sys/ker[^n]*{,/**} wklx,
+  deny /proc/sys/kern[^e]*{,/**} wklx,
+  deny /proc/sys/kerne[^l]*{,/**} wklx,
+  deny /proc/sys/kernel/[^smhd]*{,/**} wklx,
+  deny /proc/sys/kernel/d[^o]*{,/**} wklx,
+  deny /proc/sys/kernel/do[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/dom[^a]*{,/**} wklx,
+  deny /proc/sys/kernel/doma[^i]*{,/**} wklx,
+  deny /proc/sys/kernel/domai[^n]*{,/**} wklx,
+  deny /proc/sys/kernel/domain[^n]*{,/**} wklx,
+  deny /proc/sys/kernel/domainn[^a]*{,/**} wklx,
+  deny /proc/sys/kernel/domainna[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/domainnam[^e]*{,/**} wklx,
+  deny /proc/sys/kernel/domainname?*{,/**} wklx,
+  deny /proc/sys/kernel/h[^o]*{,/**} wklx,
+  deny /proc/sys/kernel/ho[^s]*{,/**} wklx,
+  deny /proc/sys/kernel/hos[^t]*{,/**} wklx,
+  deny /proc/sys/kernel/host[^n]*{,/**} wklx,
+  deny /proc/sys/kernel/hostn[^a]*{,/**} wklx,
+  deny /proc/sys/kernel/hostna[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/hostnam[^e]*{,/**} wklx,
+  deny /proc/sys/kernel/hostname?*{,/**} wklx,
+  deny /proc/sys/kernel/m[^s]*{,/**} wklx,
+  deny /proc/sys/kernel/ms[^g]*{,/**} wklx,
+  deny /proc/sys/kernel/msg*/** wklx,
+  deny /proc/sys/kernel/s[^he]*{,/**} wklx,
+  deny /proc/sys/kernel/se[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/sem*/** wklx,
+  deny /proc/sys/kernel/sh[^m]*{,/**} wklx,
+  deny /proc/sys/kernel/shm*/** wklx,
+  deny /proc/sys/kernel?*{,/**} wklx,
+  deny /proc/sys/n[^e]*{,/**} wklx,
+  deny /proc/sys/ne[^t]*{,/**} wklx,
+  deny /proc/sys/net?*{,/**} wklx,
+
+  # Block dangerous paths under /sys
+  deny /sys/[^fdck]*{,/**} wklx,
+  deny /sys/c[^l]*{,/**} wklx,
+  deny /sys/cl[^a]*{,/**} wklx,
+  deny /sys/cla[^s]*{,/**} wklx,
+  deny /sys/clas[^s]*{,/**} wklx,
+  deny /sys/class/[^n]*{,/**} wklx,
+  deny /sys/class/n[^e]*{,/**} wklx,
+  deny /sys/class/ne[^t]*{,/**} wklx,
+  deny /sys/class/net?*{,/**} wklx,
+  deny /sys/class?*{,/**} wklx,
+  deny /sys/d[^e]*{,/**} wklx,
+  deny /sys/de[^v]*{,/**} wklx,
+  deny /sys/dev[^i]*{,/**} wklx,
+  deny /sys/devi[^c]*{,/**} wklx,
+  deny /sys/devic[^e]*{,/**} wklx,
+  deny /sys/device[^s]*{,/**} wklx,
+  deny /sys/devices/[^v]*{,/**} wklx,
+  deny /sys/devices/v[^i]*{,/**} wklx,
+  deny /sys/devices/vi[^r]*{,/**} wklx,
+  deny /sys/devices/vir[^t]*{,/**} wklx,
+  deny /sys/devices/virt[^u]*{,/**} wklx,
+  deny /sys/devices/virtu[^a]*{,/**} wklx,
+  deny /sys/devices/virtua[^l]*{,/**} wklx,
+  deny /sys/devices/virtual/[^n]*{,/**} wklx,
+  deny /sys/devices/virtual/n[^e]*{,/**} wklx,
+  deny /sys/devices/virtual/ne[^t]*{,/**} wklx,
+  deny /sys/devices/virtual/net?*{,/**} wklx,
+  deny /sys/devices/virtual?*{,/**} wklx,
+  deny /sys/devices?*{,/**} wklx,
+  deny /sys/f[^s]*{,/**} wklx,
+  deny /sys/fs/[^c]*{,/**} wklx,
+  deny /sys/fs/c[^g]*{,/**} wklx,
+  deny /sys/fs/cg[^r]*{,/**} wklx,
+  deny /sys/fs/cgr[^o]*{,/**} wklx,
+  deny /sys/fs/cgro[^u]*{,/**} wklx,
+  deny /sys/fs/cgrou[^p]*{,/**} wklx,
+  deny /sys/fs/cgroup?*{,/**} wklx,
+  deny /sys/fs?*{,/**} wklx,
+
+{{- if .feature_unix }}
+
+  ### Feature: unix
+  # Allow receive via unix sockets from anywhere
+  unix (receive),
+
+  # Allow all unix in the container
+  unix peer=(label=@{profile_name}),
+{{- end }}
+
+{{- if .feature_cgns }}
+
+  ### Feature: cgroup namespace
+  mount fstype=cgroup -> /sys/fs/cgroup/**,
+  mount fstype=cgroup2 -> /sys/fs/cgroup/**,
+{{- end }}
+
+{{- if .feature_stacking }}
+
+  ### Feature: apparmor stacking
+  deny /sys/k[^e]*{,/**} wklx,
+  deny /sys/ke[^r]*{,/**} wklx,
+  deny /sys/ker[^n]*{,/**} wklx,
+  deny /sys/kern[^e]*{,/**} wklx,
+  deny /sys/kerne[^l]*{,/**} wklx,
+  deny /sys/kernel/[^s]*{,/**} wklx,
+  deny /sys/kernel/s[^e]*{,/**} wklx,
+  deny /sys/kernel/se[^c]*{,/**} wklx,
+  deny /sys/kernel/sec[^u]*{,/**} wklx,
+  deny /sys/kernel/secu[^r]*{,/**} wklx,
+  deny /sys/kernel/secur[^i]*{,/**} wklx,
+  deny /sys/kernel/securi[^t]*{,/**} wklx,
+  deny /sys/kernel/securit[^y]*{,/**} wklx,
+  deny /sys/kernel/security/[^a]*{,/**} wklx,
+  deny /sys/kernel/security/a[^p]*{,/**} wklx,
+  deny /sys/kernel/security/ap[^p]*{,/**} wklx,
+  deny /sys/kernel/security/app[^a]*{,/**} wklx,
+  deny /sys/kernel/security/appa[^r]*{,/**} wklx,
+  deny /sys/kernel/security/appar[^m]*{,/**} wklx,
+  deny /sys/kernel/security/apparm[^o]*{,/**} wklx,
+  deny /sys/kernel/security/apparmo[^r]*{,/**} wklx,
+  deny /sys/kernel/security/apparmor?*{,/**} wklx,
+  deny /sys/kernel/security?*{,/**} wklx,
+  deny /sys/kernel?*{,/**} wklx,
+
+  change_profile -> ":{{ .namespace }}:*",
+  change_profile -> ":{{ .namespace }}://*",
+{{- else }}
+
+  ### Feature: apparmor stacking (not present)
+  deny /sys/k*{,/**} wklx,
+{{- end }}
+
+{{- if .nesting }}
+
+  ### Configuration: nesting
+  pivot_root,
+
+  # Allow sending signals and tracing children namespaces
+  ptrace,
+  signal,
+
+  # Prevent access to hidden proc/sys mounts
+  deny /dev/.lxc/proc/** rw,
+  deny /dev/.lxc/sys/** rw,
+
+  # Allow mounting proc and sysfs in the container
+  mount fstype=proc -> /usr/lib/*/lxc/**,
+  mount fstype=sysfs -> /usr/lib/*/lxc/**,
+
+  # Allow nested LXD
+  mount none -> /var/lib/lxd/shmounts/,
+  mount /var/lib/lxd/shmounts/ -> /var/lib/lxd/shmounts/,
+  mount options=bind /var/lib/lxd/shmounts/** -> /var/lib/lxd/**,
+
+  # FIXME: There doesn't seem to be a way to ask for:
+  # mount options=(ro,nosuid,nodev,noexec,remount,bind),
+  # as we always get mount to $cdir/proc/sys with those flags denied
+  # So allow all mounts until that is straightened out:
+  mount,
+
+{{- if not .feature_stacking }}
+  change_profile -> "{{ .name }}",
+{{- end }}
+{{- end }}
+
+{{- if .unprivileged }}
+
+  ### Configuration: unprivileged containers
+  pivot_root,
+
+  # Allow modifying mount propagation
+  mount options=(rw,slave) -> **,
+  mount options=(rw,rslave) -> **,
+  mount options=(rw,shared) -> **,
+  mount options=(rw,rshared) -> **,
+  mount options=(rw,private) -> **,
+  mount options=(rw,rprivate) -> **,
+  mount options=(rw,unbindable) -> **,
+  mount options=(rw,runbindable) -> **,
+
+  # Allow all bind-mounts
+  mount options=(rw,bind) / -> /**,
+  mount options=(rw,bind) /** -> /**,
+  mount options=(rw,rbind) / -> /**,
+  mount options=(rw,rbind) /** -> /**,
+
+  # Allow common combinations of bind/remount
+  # NOTE: AppArmor bug effectively turns those into wildcards mount allow
+  mount options=(ro,remount,bind),
+  mount options=(ro,remount,bind,nodev),
+  mount options=(ro,remount,bind,nodev,nosuid),
+  mount options=(ro,remount,bind,noexec),
+  mount options=(ro,remount,bind,noexec,nodev),
+  mount options=(ro,remount,bind,nosuid),
+  mount options=(ro,remount,bind,nosuid,nodev),
+  mount options=(ro,remount,bind,nosuid,noexec),
+  mount options=(ro,remount,bind,nosuid,noexec,nodev),
+  mount options=(ro,remount,bind,nosuid,noexec,strictatime),
+
+  # Allow remounting things read-only
+  mount options=(ro,remount) /,
+  mount options=(ro,remount) /**,
+{{- end }}
+
+{{- if .raw }}
+
+  ### Configuration: raw.apparmor
+{{ .raw }}
+{{- end }}
+}
+`))

From 277b334a62623a783ce0bad81c02f9f2c9a57efc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 15 Jul 2020 17:35:13 -0400
Subject: [PATCH 2/2] lxd/apparmor: Use proper version parsing

---
 lxd/apparmor/apparmor.go | 77 ++++++++++++++++++++++------------------
 1 file changed, 43 insertions(+), 34 deletions(-)

diff --git a/lxd/apparmor/apparmor.go b/lxd/apparmor/apparmor.go
index d49ab15851..7598ba1211 100644
--- a/lxd/apparmor/apparmor.go
+++ b/lxd/apparmor/apparmor.go
@@ -13,6 +13,7 @@ import (
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/logger"
+	"github.com/lxc/lxd/shared/version"
 
 	log "github.com/lxc/lxd/shared/log15"
 )
@@ -67,9 +68,9 @@ func profileShort(c instance) string {
 	return fmt.Sprintf("lxd-%s", name)
 }
 
-// getProfileContent generates the apparmor profile template from the given container.
+// profileContent generates the apparmor profile template from the given container.
 // This includes the stock lxc includes as well as stuff from raw.apparmor.
-func getAAProfileContent(state *state.State, c instance) string {
+func profileContent(state *state.State, c instance) (string, error) {
 	// Prepare raw.apparmor.
 	rawContent := ""
 	rawApparmor, ok := c.ExpandedConfig()["raw.apparmor"]
@@ -82,7 +83,7 @@ func getAAProfileContent(state *state.State, c instance) string {
 	// Render the profile.
 	var sb *strings.Builder = &strings.Builder{}
 	err := containerProfile.Execute(sb, map[string]interface{}{
-		"feature_unix":     aaParserSupports("unix"),
+		"feature_unix":     parserSupports("unix"),
 		"feature_cgns":     shared.PathExists("/proc/self/ns/cgroup"),
 		"feature_stacking": state.OS.AppArmorStacking && !state.OS.AppArmorStacked,
 		"namespace":        Namespace(c),
@@ -92,10 +93,10 @@ func getAAProfileContent(state *state.State, c instance) string {
 		"raw":              rawContent,
 	})
 	if err != nil {
-		return ""
+		return "", err
 	}
 
-	return sb.String()
+	return sb.String(), nil
 }
 
 func runApparmor(state *state.State, command string, c instance) error {
@@ -120,18 +121,26 @@ func runApparmor(state *state.State, command string, c instance) error {
 func getCacheDir() string {
 	basePath := path.Join(aaPath, "cache")
 
-	major, minor, _, err := getAAParserVersion()
+	ver, err := getVersion()
 	if err != nil {
+		logger.Errorf("Unable to get AppArmor version: %v", err)
 		return basePath
 	}
 
-	// multiple policy cache directories were only added in v2.13
-	if major < 2 || (major == 2 && minor < 13) {
+	// Multiple policy cache directories were only added in v2.13.
+	minVer, err := version.NewDottedVersion("2.13")
+	if err != nil {
+		logger.Errorf("Unable to parse AppArmor version 2.13: %v", err)
+		return basePath
+	}
+
+	if ver.Compare(minVer) < 0 {
 		return basePath
 	}
 
 	output, err := shared.RunCommand("apparmor_parser", "-L", basePath, "--print-cache-dir")
 	if err != nil {
+		logger.Errorf("Unable to get AppArmor cache directory: %v", err)
 		return basePath
 	}
 
@@ -157,7 +166,8 @@ func LoadProfile(state *state.State, c instance) error {
 		return nil
 	}
 
-	if err := mkApparmorNamespace(state, c, Namespace(c)); err != nil {
+	err := mkApparmorNamespace(state, c, Namespace(c))
+	if err != nil {
 		return err
 	}
 
@@ -178,18 +188,24 @@ func LoadProfile(state *state.State, c instance) error {
 		return err
 	}
 
-	updated := getAAProfileContent(state, c)
+	updated, err := profileContent(state, c)
+	if err != nil {
+		return err
+	}
 
 	if string(content) != string(updated) {
-		if err := os.MkdirAll(path.Join(aaPath, "cache"), 0700); err != nil {
+		err = os.MkdirAll(path.Join(aaPath, "cache"), 0700)
+		if err != nil {
 			return err
 		}
 
-		if err := os.MkdirAll(path.Join(aaPath, "profiles"), 0700); err != nil {
+		err = os.MkdirAll(path.Join(aaPath, "profiles"), 0700)
+		if err != nil {
 			return err
 		}
 
-		if err := ioutil.WriteFile(profile, []byte(updated), 0600); err != nil {
+		err = ioutil.WriteFile(profile, []byte(updated), 0600)
+		if err != nil {
 			return err
 		}
 	}
@@ -236,39 +252,32 @@ func DeleteProfile(state *state.State, c instance) {
 	os.Remove(path.Join(aaPath, "profiles", profileShort(c)))
 }
 
-func aaParserSupports(feature string) bool {
-	major, minor, micro, err := getAAParserVersion()
+func parserSupports(feature string) bool {
+	ver, err := getVersion()
 	if err != nil {
+		logger.Errorf("Unable to get AppArmor version: %v", err)
 		return false
 	}
 
-	switch feature {
-	case "unix":
-		if major < 2 {
+	if feature == "unix" {
+		minVer, err := version.NewDottedVersion("2.10.95")
+		if err != nil {
+			logger.Errorf("Unable to parse AppArmor version 2.10.95: %v", err)
 			return false
 		}
 
-		if major == 2 && minor < 10 {
-			return false
-		}
-
-		if major == 2 && minor == 10 && micro < 95 {
-			return false
-		}
+		return ver.Compare(minVer) >= 0
 	}
 
-	return true
+	return false
 }
 
-func getAAParserVersion() (major int, minor int, micro int, err error) {
-	var out string
-
-	out, err = shared.RunCommand("apparmor_parser", "--version")
+func getVersion() (*version.DottedVersion, error) {
+	out, err := shared.RunCommand("apparmor_parser", "--version")
 	if err != nil {
-		return
+		return nil, err
 	}
 
-	_, err = fmt.Sscanf(strings.Split(out, "\n")[0], "AppArmor parser version %d.%d.%d", &major, &minor, &micro)
-
-	return
+	fields := strings.Fields(strings.Split(out, "\n")[0])
+	return version.NewDottedVersion(fields[len(fields)-1])
 }


More information about the lxc-devel mailing list