lxd/apparmor.go
func getAAProfileContent(c container) string {
	profile := strings.TrimLeft(AA_PROFILE_BASE, "\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"
	}

	state := c.DaemonState()
	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", AANamespace(c))
		profile += fmt.Sprintf("  change_profile -> \":%s://*\",\n", AANamespace(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(AA_PROFILE_NESTING, "\n")
		if !state.OS.AppArmorStacking || state.OS.AppArmorStacked {
			profile += fmt.Sprintf("  change_profile -> \"%s\",\n", AAProfileFull(c))
		}
	}

	if !c.IsPrivileged() || state.OS.RunningInUserNS {
		// Apply unprivileged bits
		profile += "\n  ### Configuration: unprivileged containers\n"
		profile += strings.TrimLeft(AA_PROFILE_UNPRIVILEGED, "\n")
	}

	// Append raw.apparmor
	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)
		}
	}

	return fmt.Sprintf(`#include <tunables/global>
profile "%s" flags=(attach_disconnected,mediate_deleted) {
%s
}
`, AAProfileFull(c), strings.Trim(profile, "\n"))
}
func getAAProfileContent(c container) string {
	profile := strings.TrimLeft(AA_PROFILE_BASE, "\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"
	}

	state := c.DaemonState()
	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", AANamespace(c))
		profile += fmt.Sprintf("  change_profile -> \":%s://*\",\n", AANamespace(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(AA_PROFILE_NESTING, "\n")
		if !state.OS.AppArmorStacking || state.OS.AppArmorStacked {
			profile += fmt.Sprintf("  change_profile -> \"%s\",\n", AAProfileFull(c))
		}
	}

	if !c.IsPrivileged() || state.OS.RunningInUserNS {
		// Apply unprivileged bits
		profile += "\n  ### Configuration: unprivileged containers\n"
		profile += strings.TrimLeft(AA_PROFILE_UNPRIVILEGED, "\n")
	}

	// Append raw.apparmor
	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)
		}
	}

	return fmt.Sprintf(`#include <tunables/global>
profile "%s" flags=(attach_disconnected,mediate_deleted) {
%s
}
`, AAProfileFull(c), strings.Trim(profile, "\n"))
}
// getProfileContent generates the apparmor profile template from the given
// container. This includes the stock lxc includes as well as stuff from
// raw.apparmor.