[lxc-devel] [lxd/master] Moves apparmor into own package

tomponline on Github lxc-bot at linuxcontainers.org
Fri Sep 27 09:28:24 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 346 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190927/e1c3ea53/attachment-0001.bin>
-------------- next part --------------
From bdb28a2ce35cb9e45b7ce2a920b8011bf593a5b9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 26 Sep 2019 17:42:12 +0100
Subject: [PATCH 1/8] lxd/seccomp: Adds seccomp package

- Cleans up existing seccomp code to pass go lint

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/{ => seccomp}/seccomp.go | 256 +++++++++++++++++++++--------------
 lxd/seccomp/seccomp_empty.go |   3 +
 2 files changed, 161 insertions(+), 98 deletions(-)
 rename lxd/{ => seccomp}/seccomp.go (78%)
 create mode 100644 lxd/seccomp/seccomp_empty.go

diff --git a/lxd/seccomp.go b/lxd/seccomp/seccomp.go
similarity index 78%
rename from lxd/seccomp.go
rename to lxd/seccomp/seccomp.go
index a314e52cfc..182da123a9 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp/seccomp.go
@@ -1,7 +1,7 @@
 // +build linux
 // +build cgo
 
-package main
+package seccomp
 
 import (
 	"fmt"
@@ -17,11 +17,14 @@ import (
 	"unsafe"
 
 	"golang.org/x/sys/unix"
+	lxc "gopkg.in/lxc/go-lxc.v2"
 
 	"github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/ucred"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
+	"github.com/lxc/lxd/shared/idmap"
 	log "github.com/lxc/lxd/shared/log15"
 	"github.com/lxc/lxd/shared/logger"
 	"github.com/lxc/lxd/shared/netutils"
@@ -273,14 +276,14 @@ static void prepare_seccomp_iovec(struct iovec *iov,
 // #cgo CFLAGS: -std=gnu11 -Wvla
 import "C"
 
-const LxdSeccompNotifyMknod = C.LXD_SECCOMP_NOTIFY_MKNOD
-const LxdSeccompNotifyMknodat = C.LXD_SECCOMP_NOTIFY_MKNODAT
-const LxdSeccompNotifySetxattr = C.LXD_SECCOMP_NOTIFY_SETXATTR
+const lxdSeccompNotifyMknod = C.LXD_SECCOMP_NOTIFY_MKNOD
+const lxdSeccompNotifyMknodat = C.LXD_SECCOMP_NOTIFY_MKNODAT
+const lxdSeccompNotifySetxattr = C.LXD_SECCOMP_NOTIFY_SETXATTR
 
-const SECCOMP_HEADER = `2
+const seccompHeader = `2
 `
 
-const DEFAULT_SECCOMP_POLICY = `reject_force_umount  # comment this to allow umount -f;  not recommended
+const defaultSeccompPolicy = `reject_force_umount  # comment this to allow umount -f;  not recommended
 [all]
 kexec_load errno 38
 open_by_handle_at errno 38
@@ -289,15 +292,15 @@ finit_module errno 38
 delete_module errno 38
 `
 
-const SECCOMP_NOTIFY_MKNOD = `mknod notify [1,8192,SCMP_CMP_MASKED_EQ,61440]
+const seccompNotifyMknod = `mknod notify [1,8192,SCMP_CMP_MASKED_EQ,61440]
 mknod notify [1,24576,SCMP_CMP_MASKED_EQ,61440]
 mknodat notify [2,8192,SCMP_CMP_MASKED_EQ,61440]
 mknodat notify [2,24576,SCMP_CMP_MASKED_EQ,61440]
 `
-const SECCOMP_NOTIFY_SETXATTR = `setxattr notify [3,1,SCMP_CMP_EQ]
+const seccompNotifySetxattr = `setxattr notify [3,1,SCMP_CMP_EQ]
 `
 
-const COMPAT_BLOCKING_POLICY = `[%s]
+const compatBlockingPolicy = `[%s]
 compat_sys_rt_sigaction errno 38
 stub_x32_rt_sigreturn errno 38
 compat_sys_ioctl errno 38
@@ -334,13 +337,28 @@ compat_sys_io_submit errno 38
 stub_x32_execveat errno 38
 `
 
+// Instance is a seccomp specific instance interface.
+type Instance interface {
+	Name() string
+	Project() string
+	ExpandedConfig() map[string]string
+	IsPrivileged() bool
+	DaemonState() *state.State
+	Architecture() int
+	RootfsPath() string
+	CurrentIdmap() (*idmap.IdmapSet, error)
+	InsertSeccompUnixDevice(prefix string, m config.Device, pid int) error
+}
+
 var seccompPath = shared.VarPath("security", "seccomp")
 
-func SeccompProfilePath(c container) string {
+// ProfilePath returns the seccomp path for the instance.
+func ProfilePath(c Instance) string {
 	return path.Join(seccompPath, c.Name())
 }
 
-func seccompContainerNeedsPolicy(c container) bool {
+// InstanceNeedsPolicy returns whether the instance needs a policy or not.
+func InstanceNeedsPolicy(c Instance) bool {
 	config := c.ExpandedConfig()
 
 	// Check for text keys
@@ -385,7 +403,8 @@ func seccompContainerNeedsPolicy(c container) bool {
 	return false
 }
 
-func seccompContainerNeedsIntercept(c container) (bool, error) {
+// InstanceNeedsIntercept returns whether instance needs intercept.
+func InstanceNeedsIntercept(c Instance) (bool, error) {
 	// No need if privileged
 	if c.IsPrivileged() {
 		return false, nil
@@ -420,7 +439,7 @@ func seccompContainerNeedsIntercept(c container) (bool, error) {
 	return needed, nil
 }
 
-func seccompGetPolicyContent(c container) (string, error) {
+func seccompGetPolicyContent(c Instance) (string, error) {
 	config := c.ExpandedConfig()
 
 	// Full policy override
@@ -430,7 +449,7 @@ func seccompGetPolicyContent(c container) (string, error) {
 	}
 
 	// Policy header
-	policy := SECCOMP_HEADER
+	policy := seccompHeader
 	whitelist := config["security.syscalls.whitelist"]
 	if whitelist != "" {
 		policy += "whitelist\n[all]\n"
@@ -438,25 +457,25 @@ func seccompGetPolicyContent(c container) (string, error) {
 	} else {
 		policy += "blacklist\n"
 
-		default_, ok := config["security.syscalls.blacklist_default"]
-		if !ok || shared.IsTrue(default_) {
-			policy += DEFAULT_SECCOMP_POLICY
+		defaultFlag, ok := config["security.syscalls.blacklist_default"]
+		if !ok || shared.IsTrue(defaultFlag) {
+			policy += defaultSeccompPolicy
 		}
 	}
 
 	// Syscall interception
-	ok, err := seccompContainerNeedsIntercept(c)
+	ok, err := InstanceNeedsIntercept(c)
 	if err != nil {
 		return "", err
 	}
 
 	if ok {
 		if shared.IsTrue(config["security.syscalls.intercept.mknod"]) {
-			policy += SECCOMP_NOTIFY_MKNOD
+			policy += seccompNotifyMknod
 		}
 
 		if shared.IsTrue(config["security.syscalls.intercept.setxattr"]) {
-			policy += SECCOMP_NOTIFY_SETXATTR
+			policy += seccompNotifySetxattr
 		}
 	}
 
@@ -471,7 +490,7 @@ func seccompGetPolicyContent(c container) (string, error) {
 		if err != nil {
 			return "", err
 		}
-		policy += fmt.Sprintf(COMPAT_BLOCKING_POLICY, arch)
+		policy += fmt.Sprintf(compatBlockingPolicy, arch)
 	}
 
 	blacklist := config["security.syscalls.blacklist"]
@@ -482,14 +501,15 @@ func seccompGetPolicyContent(c container) (string, error) {
 	return policy, nil
 }
 
-func SeccompCreateProfile(c container) error {
+// CreateProfile creates a seccomp profile.
+func CreateProfile(c Instance) error {
 	/* Unlike apparmor, there is no way to "cache" profiles, and profiles
 	 * are automatically unloaded when a task dies. Thus, we don't need to
 	 * unload them when a container stops, and we don't have to worry about
 	 * the mtime on the file for any compiler purpose, so let's just write
 	 * out the profile.
 	 */
-	if !seccompContainerNeedsPolicy(c) {
+	if !InstanceNeedsPolicy(c) {
 		return nil
 	}
 
@@ -502,23 +522,26 @@ func SeccompCreateProfile(c container) error {
 		return err
 	}
 
-	return ioutil.WriteFile(SeccompProfilePath(c), []byte(profile), 0600)
+	return ioutil.WriteFile(ProfilePath(c), []byte(profile), 0600)
 }
 
-func SeccompDeleteProfile(c container) {
+// DeleteProfile removes a seccomp profile.
+func DeleteProfile(c Instance) {
 	/* similar to AppArmor, if we've never started this container, the
 	 * delete can fail and that's ok.
 	 */
-	os.Remove(SeccompProfilePath(c))
+	os.Remove(ProfilePath(c))
 }
 
-type SeccompServer struct {
-	d    *Daemon
+// Server defines a seccomp server.
+type Server struct {
+	s    *state.State
 	path string
 	l    net.Listener
 }
 
-type SeccompIovec struct {
+// Iovec defines an iovec to move data between kernel and userspace.
+type Iovec struct {
 	ucred  *ucred.UCred
 	memFd  int
 	procFd int
@@ -529,30 +552,31 @@ type SeccompIovec struct {
 	iov    *C.struct_iovec
 }
 
-func NewSeccompIovec(ucred *ucred.UCred) *SeccompIovec {
-	msg_ptr := C.malloc(C.sizeof_struct_seccomp_notify_proxy_msg)
-	msg := (*C.struct_seccomp_notify_proxy_msg)(msg_ptr)
-	C.memset(msg_ptr, 0, C.sizeof_struct_seccomp_notify_proxy_msg)
+// NewSeccompIovec creates a new seccomp iovec.
+func NewSeccompIovec(ucred *ucred.UCred) *Iovec {
+	msgPtr := C.malloc(C.sizeof_struct_seccomp_notify_proxy_msg)
+	msg := (*C.struct_seccomp_notify_proxy_msg)(msgPtr)
+	C.memset(msgPtr, 0, C.sizeof_struct_seccomp_notify_proxy_msg)
 
-	req_ptr := C.malloc(C.sizeof_struct_seccomp_notif)
-	req := (*C.struct_seccomp_notif)(req_ptr)
-	C.memset(req_ptr, 0, C.sizeof_struct_seccomp_notif)
+	regPtr := C.malloc(C.sizeof_struct_seccomp_notif)
+	req := (*C.struct_seccomp_notif)(regPtr)
+	C.memset(regPtr, 0, C.sizeof_struct_seccomp_notif)
 
-	resp_ptr := C.malloc(C.sizeof_struct_seccomp_notif_resp)
-	resp := (*C.struct_seccomp_notif_resp)(resp_ptr)
-	C.memset(resp_ptr, 0, C.sizeof_struct_seccomp_notif_resp)
+	respPtr := C.malloc(C.sizeof_struct_seccomp_notif_resp)
+	resp := (*C.struct_seccomp_notif_resp)(respPtr)
+	C.memset(respPtr, 0, C.sizeof_struct_seccomp_notif_resp)
 
-	cookie_ptr := C.malloc(64 * C.sizeof_char)
-	cookie := (*C.char)(cookie_ptr)
-	C.memset(cookie_ptr, 0, 64*C.sizeof_char)
+	cookiePtr := C.malloc(64 * C.sizeof_char)
+	cookie := (*C.char)(cookiePtr)
+	C.memset(cookiePtr, 0, 64*C.sizeof_char)
 
-	iov_unsafe_ptr := C.malloc(4 * C.sizeof_struct_iovec)
-	iov := (*C.struct_iovec)(iov_unsafe_ptr)
-	C.memset(iov_unsafe_ptr, 0, 4*C.sizeof_struct_iovec)
+	iovUnsafePtr := C.malloc(4 * C.sizeof_struct_iovec)
+	iov := (*C.struct_iovec)(iovUnsafePtr)
+	C.memset(iovUnsafePtr, 0, 4*C.sizeof_struct_iovec)
 
 	C.prepare_seccomp_iovec(iov, msg, req, resp, cookie)
 
-	return &SeccompIovec{
+	return &Iovec{
 		memFd:  -1,
 		procFd: -1,
 		msg:    msg,
@@ -564,7 +588,8 @@ func NewSeccompIovec(ucred *ucred.UCred) *SeccompIovec {
 	}
 }
 
-func (siov *SeccompIovec) PutSeccompIovec() {
+// PutSeccompIovec puts a seccomp iovec.
+func (siov *Iovec) PutSeccompIovec() {
 	if siov.memFd >= 0 {
 		unix.Close(siov.memFd)
 	}
@@ -578,7 +603,8 @@ func (siov *SeccompIovec) PutSeccompIovec() {
 	C.free(unsafe.Pointer(siov.iov))
 }
 
-func (siov *SeccompIovec) ReceiveSeccompIovec(fd int) (uint64, error) {
+// ReceiveSeccompIovec receives a seccomp iovec.
+func (siov *Iovec) ReceiveSeccompIovec(fd int) (uint64, error) {
 	bytes, fds, err := netutils.AbstractUnixReceiveFdData(fd, 2, unsafe.Pointer(siov.iov), 4)
 	if err != nil || err == io.EOF {
 		return 0, err
@@ -594,7 +620,8 @@ func (siov *SeccompIovec) ReceiveSeccompIovec(fd int) (uint64, error) {
 	return bytes, nil
 }
 
-func (siov *SeccompIovec) IsValidSeccompIovec(size uint64) bool {
+// IsValidSeccompIovec checks whether a seccomp iovec is valid.
+func (siov *Iovec) IsValidSeccompIovec(size uint64) bool {
 	if size < uint64(C.SECCOMP_MSG_SIZE_MIN) {
 		logger.Warnf("Disconnected from seccomp socket after incomplete receive")
 		return false
@@ -626,7 +653,8 @@ func (siov *SeccompIovec) IsValidSeccompIovec(size uint64) bool {
 	return true
 }
 
-func (siov *SeccompIovec) SendSeccompIovec(fd int, errno int) error {
+// SendSeccompIovec sends seccomp iovec.
+func (siov *Iovec) SendSeccompIovec(fd int, errno int) error {
 	C.seccomp_notify_update_response(siov.resp, C.int(errno))
 
 	msghdr := C.struct_msghdr{}
@@ -651,7 +679,8 @@ retry:
 	return nil
 }
 
-func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
+// NewSeccompServer creates a new seccomp server.
+func NewSeccompServer(s *state.State, path string, findPID func(pid int32, state *state.State) (Instance, error)) (*Server, error) {
 	ret := C.seccomp_notify_get_sizes(&C.expected_sizes)
 	if ret < 0 {
 		return nil, fmt.Errorf("Failed to query kernel for seccomp notifier sizes")
@@ -678,8 +707,8 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
 	}
 
 	// Start the server
-	s := SeccompServer{
-		d:    d,
+	server := Server{
+		s:    s,
 		path: path,
 		l:    l,
 	}
@@ -715,101 +744,103 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
 					}
 
 					if siov.IsValidSeccompIovec(bytes) {
-						go s.Handler(int(unixFile.Fd()), siov)
+						go server.handler(int(unixFile.Fd()), siov, findPID)
 					} else {
-						go s.InvalidHandler(int(unixFile.Fd()), siov)
+						go server.InvalidHandler(int(unixFile.Fd()), siov)
 					}
 				}
 			}()
 		}
 	}()
 
-	return &s, nil
+	return &server, nil
 }
 
-func taskIds(pid int) (error, int64, int64, int64, int64) {
+// TaskIDs returns the task IDs for a process.
+func TaskIDs(pid int) (int64, int64, int64, int64, error) {
 	status, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
 	if err != nil {
-		return err, -1, -1, -1, -1
+		return -1, -1, -1, -1, err
 	}
 
-	reUid := regexp.MustCompile("Uid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)")
-	reGid := regexp.MustCompile("Gid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)")
-	var gid int64 = -1
-	var uid int64 = -1
-	var fsgid int64 = -1
-	var fsuid int64 = -1
-	uidFound := false
-	gidFound := false
+	reUID := regexp.MustCompile("Uid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)")
+	reGID := regexp.MustCompile("Gid:\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)\\s*([0-9]*)")
+	var UID int64 = -1
+	var GID int64 = -1
+	var fsUID int64 = -1
+	var fsGID int64 = -1
+	UIDFound := false
+	GIDFound := false
 	for _, line := range strings.Split(string(status), "\n") {
-		if uidFound && gidFound {
+		if UIDFound && GIDFound {
 			break
 		}
 
-		if !uidFound {
-			m := reUid.FindStringSubmatch(line)
+		if !UIDFound {
+			m := reUID.FindStringSubmatch(line)
 			if m != nil && len(m) > 2 {
 				// effective uid
 				result, err := strconv.ParseInt(m[2], 10, 64)
 				if err != nil {
-					return err, -1, -1, -1, -1
+					return -1, -1, -1, -1, err
 				}
 
-				uid = result
-				uidFound = true
+				UID = result
+				UIDFound = true
 			}
 
 			if m != nil && len(m) > 4 {
 				// fsuid
 				result, err := strconv.ParseInt(m[4], 10, 64)
 				if err != nil {
-					return err, -1, -1, -1, -1
+					return -1, -1, -1, -1, err
 				}
 
-				fsuid = result
+				fsUID = result
 			}
 
 			continue
 		}
 
-		if !gidFound {
-			m := reGid.FindStringSubmatch(line)
+		if !GIDFound {
+			m := reGID.FindStringSubmatch(line)
 			if m != nil && len(m) > 2 {
 				// effective gid
 				result, err := strconv.ParseInt(m[2], 10, 64)
 				if err != nil {
-					return err, -1, -1, -1, -1
+					return -1, -1, -1, -1, err
 				}
 
-				gid = result
-				gidFound = true
+				GID = result
+				GIDFound = true
 			}
 
 			if m != nil && len(m) > 4 {
 				// fsgid
 				result, err := strconv.ParseInt(m[4], 10, 64)
 				if err != nil {
-					return err, -1, -1, -1, -1
+					return -1, -1, -1, -1, err
 				}
 
-				fsgid = result
+				fsGID = result
 			}
 
 			continue
 		}
 	}
 
-	return nil, uid, gid, fsuid, fsgid
+	return UID, GID, fsUID, fsGID, nil
 }
 
-func CallForkmknod(c container, dev config.Device, requestPID int) int {
+// CallForkmknod executes fork mknod.
+func CallForkmknod(c Instance, dev config.Device, requestPID int) int {
 	rootLink := fmt.Sprintf("/proc/%d/root", requestPID)
 	rootPath, err := os.Readlink(rootLink)
 	if err != nil {
 		return int(-C.EPERM)
 	}
 
-	err, uid, gid, fsuid, fsgid := taskIds(requestPID)
+	uid, gid, fsuid, fsgid, err := TaskIDs(requestPID)
 	if err != nil {
 		return int(-C.EPERM)
 	}
@@ -846,12 +877,13 @@ func CallForkmknod(c container, dev config.Device, requestPID int) int {
 
 // InvalidHandler sends a dummy message to LXC. LXC will notice the short write
 // and send a default message to the kernel thereby avoiding a 30s hang.
-func (s *SeccompServer) InvalidHandler(fd int, siov *SeccompIovec) {
+func (s *Server) InvalidHandler(fd int, siov *Iovec) {
 	msghdr := C.struct_msghdr{}
 	C.sendmsg(C.int(fd), &msghdr, C.MSG_NOSIGNAL)
 	siov.PutSeccompIovec()
 }
 
+// MknodArgs arguments for mknod.
 type MknodArgs struct {
 	cMode C.mode_t
 	cDev  C.dev_t
@@ -859,7 +891,7 @@ type MknodArgs struct {
 	path  string
 }
 
-func (s *SeccompServer) doDeviceSyscall(c container, args *MknodArgs, siov *SeccompIovec) int {
+func (s *Server) doDeviceSyscall(c Instance, args *MknodArgs, siov *Iovec) int {
 	dev := config.Device{}
 	dev["type"] = "unix-char"
 	dev["mode"] = fmt.Sprintf("%#o", args.cMode)
@@ -883,7 +915,8 @@ func (s *SeccompServer) doDeviceSyscall(c container, args *MknodArgs, siov *Secc
 	return 0
 }
 
-func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int {
+// HandleMknodSyscall handles a mknod syscall.
+func (s *Server) HandleMknodSyscall(c Instance, siov *Iovec) int {
 	logger.Debug("Handling mknod syscall",
 		log.Ctx{"container": c.Name(),
 			"project":              c.Project(),
@@ -916,7 +949,8 @@ func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int
 	return s.doDeviceSyscall(c, &args, siov)
 }
 
-func (s *SeccompServer) HandleMknodatSyscall(c container, siov *SeccompIovec) int {
+// HandleMknodatSyscall handles a mknodat syscall.
+func (s *Server) HandleMknodatSyscall(c Instance, siov *Iovec) int {
 	logger.Debug("Handling mknodat syscall",
 		log.Ctx{"container": c.Name(),
 			"project":              c.Project(),
@@ -956,6 +990,7 @@ func (s *SeccompServer) HandleMknodatSyscall(c container, siov *SeccompIovec) in
 	return s.doDeviceSyscall(c, &args, siov)
 }
 
+// SetxattrArgs arguments for setxattr.
 type SetxattrArgs struct {
 	nsuid   int64
 	nsgid   int64
@@ -969,7 +1004,8 @@ type SetxattrArgs struct {
 	flags   C.int
 }
 
-func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) int {
+// HandleSetxattrSyscall handles setxattr syscalls.
+func (s *Server) HandleSetxattrSyscall(c Instance, siov *Iovec) int {
 	logger.Debug("Handling setxattr syscall",
 		log.Ctx{"container": c.Name(),
 			"project":              c.Project(),
@@ -982,7 +1018,7 @@ func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) i
 	args := SetxattrArgs{}
 
 	args.pid = int(siov.req.pid)
-	err, uid, gid, fsuid, fsgid := taskIds(args.pid)
+	uid, gid, fsuid, fsgid, err := TaskIDs(args.pid)
 	if err != nil {
 		return int(-C.EPERM)
 	}
@@ -1057,30 +1093,30 @@ func (s *SeccompServer) HandleSetxattrSyscall(c container, siov *SeccompIovec) i
 	return 0
 }
 
-func (s *SeccompServer) HandleSyscall(c container, siov *SeccompIovec) int {
+func (s *Server) handleSyscall(c Instance, siov *Iovec) int {
 	switch int(C.seccomp_notify_get_syscall(siov.req, siov.resp)) {
-	case LxdSeccompNotifyMknod:
+	case lxdSeccompNotifyMknod:
 		return s.HandleMknodSyscall(c, siov)
-	case LxdSeccompNotifyMknodat:
+	case lxdSeccompNotifyMknodat:
 		return s.HandleMknodatSyscall(c, siov)
-	case LxdSeccompNotifySetxattr:
+	case lxdSeccompNotifySetxattr:
 		return s.HandleSetxattrSyscall(c, siov)
 	}
 
 	return int(-C.EINVAL)
 }
 
-func (s *SeccompServer) Handler(fd int, siov *SeccompIovec) error {
+func (s *Server) handler(fd int, siov *Iovec, findPID func(pid int32, state *state.State) (Instance, error)) error {
 	defer siov.PutSeccompIovec()
 
-	c, err := findContainerForPid(int32(siov.msg.monitor_pid), s.d)
+	c, err := findPID(int32(siov.msg.monitor_pid), s.s)
 	if err != nil {
 		siov.SendSeccompIovec(fd, int(-C.EPERM))
 		logger.Errorf("Failed to find container for monitor %d", siov.msg.monitor_pid)
 		return err
 	}
 
-	errno := s.HandleSyscall(c, siov)
+	errno := s.handleSyscall(c, siov)
 
 	err = siov.SendSeccompIovec(fd, errno)
 	if err != nil {
@@ -1090,7 +1126,31 @@ func (s *SeccompServer) Handler(fd int, siov *SeccompIovec) error {
 	return nil
 }
 
-func (s *SeccompServer) Stop() error {
+// Stop stops a seccomp server.
+func (s *Server) Stop() error {
 	os.Remove(s.path)
 	return s.l.Close()
 }
+
+func lxcSupportSeccompNotify(state *state.State) bool {
+	if !state.OS.SeccompListener {
+		return false
+	}
+
+	if !state.OS.LXCFeatures["seccomp_notify"] {
+		return false
+	}
+
+	c, err := lxc.NewContainer("test-seccomp", state.OS.LxcPath)
+	if err != nil {
+		return false
+	}
+
+	err = c.SetConfigItem("lxc.seccomp.notify.proxy", fmt.Sprintf("unix:%s", shared.VarPath("seccomp.socket")))
+	if err != nil {
+		return false
+	}
+
+	c.Release()
+	return true
+}
diff --git a/lxd/seccomp/seccomp_empty.go b/lxd/seccomp/seccomp_empty.go
new file mode 100644
index 0000000000..13b55d66db
--- /dev/null
+++ b/lxd/seccomp/seccomp_empty.go
@@ -0,0 +1,3 @@
+package seccomp
+
+// Placeholder for non-linux systems.

From 4bb9d795b037651abc93b3c14848c5252e494425 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 26 Sep 2019 17:43:32 +0100
Subject: [PATCH 2/8] lxd/daemon: Updates to use seccomp package

- Updates to use seccomp package.
- Uses workaround to expose findContainerForPid to seccomp package.
- Adds call to seccomp server Stop() on LXD shutdown.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/daemon.go | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/lxd/daemon.go b/lxd/daemon.go
index b483125ae8..dc50d1adaf 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -37,6 +37,7 @@ import (
 	"github.com/lxc/lxd/lxd/node"
 	"github.com/lxc/lxd/lxd/rbac"
 	"github.com/lxc/lxd/lxd/response"
+	"github.com/lxc/lxd/lxd/seccomp"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/sys"
 	"github.com/lxc/lxd/lxd/task"
@@ -73,7 +74,7 @@ type Daemon struct {
 	config    *DaemonConfig
 	endpoints *endpoints.Endpoints
 	gateway   *cluster.Gateway
-	seccomp   *SeccompServer
+	seccomp   *seccomp.Server
 
 	proxy func(req *http.Request) (*url.URL, error)
 
@@ -877,7 +878,9 @@ func (d *Daemon) init() error {
 
 		// Setup seccomp handler
 		if d.os.SeccompListener {
-			seccompServer, err := NewSeccompServer(d, shared.VarPath("seccomp.socket"))
+			seccompServer, err := seccomp.NewSeccompServer(d.State(), shared.VarPath("seccomp.socket"), func(pid int32, state *state.State) (seccomp.Instance, error) {
+				return findContainerForPid(pid, state)
+			})
 			if err != nil {
 				return err
 			}
@@ -1091,6 +1094,10 @@ func (d *Daemon) Stop() error {
 			"Not unmounting temporary filesystems (containers are still running)")
 	}
 
+	if d.seccomp != nil {
+		trackError(d.seccomp.Stop())
+	}
+
 	var err error
 	if n := len(errs); n > 0 {
 		format := "%v"

From 9ff4fa52e407d761fedb02b1ae99b36ba35c3917 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 26 Sep 2019 17:44:52 +0100
Subject: [PATCH 3/8] lxd/container/lxc: Removes lxcSupportSeccompNotify

- This has moved to seccomp package.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/container_lxc.go | 23 -----------------------
 1 file changed, 23 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 0f8fb885a3..a82fafd239 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -206,29 +206,6 @@ func lxcParseRawLXC(line string) (string, string, error) {
 	return key, val, nil
 }
 
-func lxcSupportSeccompNotify(state *state.State) bool {
-	if !state.OS.SeccompListener {
-		return false
-	}
-
-	if !state.OS.LXCFeatures["seccomp_notify"] {
-		return false
-	}
-
-	c, err := lxc.NewContainer("test-seccomp", state.OS.LxcPath)
-	if err != nil {
-		return false
-	}
-
-	err = c.SetConfigItem("lxc.seccomp.notify.proxy", fmt.Sprintf("unix:%s", shared.VarPath("seccomp.socket")))
-	if err != nil {
-		return false
-	}
-
-	c.Release()
-	return true
-}
-
 func lxcValidConfig(rawLxc string) error {
 	for _, line := range strings.Split(rawLxc, "\n") {
 		key, _, err := lxcParseRawLXC(line)

From 86fc392c3097c8f4d4904534a4d0f711e7aa4553 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 26 Sep 2019 17:45:20 +0100
Subject: [PATCH 4/8] lxd: Updates to use seccomp package

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/container_lxc.go | 13 +++++++------
 lxd/devlxd.go        |  9 +++++----
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index a82fafd239..cc83a3a7cb 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -34,6 +34,7 @@ import (
 	"github.com/lxc/lxd/lxd/instance/instancetype"
 	"github.com/lxc/lxd/lxd/maas"
 	"github.com/lxc/lxd/lxd/project"
+	"github.com/lxc/lxd/lxd/seccomp"
 	"github.com/lxc/lxd/lxd/state"
 	driver "github.com/lxc/lxd/lxd/storage"
 	"github.com/lxc/lxd/lxd/template"
@@ -1257,15 +1258,15 @@ func (c *containerLXC) initLXC(config bool) error {
 	}
 
 	// Setup Seccomp if necessary
-	if seccompContainerNeedsPolicy(c) {
-		err = lxcSetConfigItem(cc, "lxc.seccomp.profile", SeccompProfilePath(c))
+	if seccomp.InstanceNeedsPolicy(c) {
+		err = lxcSetConfigItem(cc, "lxc.seccomp.profile", seccomp.ProfilePath(c))
 		if err != nil {
 			return err
 		}
 
 		// Setup notification socket
 		// System requirement errors are handled during policy generation instead of here
-		ok, err := seccompContainerNeedsIntercept(c)
+		ok, err := seccomp.InstanceNeedsIntercept(c)
 		if err == nil && ok {
 			err = lxcSetConfigItem(cc, "lxc.seccomp.notify.proxy", fmt.Sprintf("unix:%s", shared.VarPath("seccomp.socket")))
 			if err != nil {
@@ -2260,7 +2261,7 @@ func (c *containerLXC) startCommon() (string, []func() error, error) {
 	}
 
 	// Generate the Seccomp profile
-	if err := SeccompCreateProfile(c); err != nil {
+	if err := seccomp.CreateProfile(c); err != nil {
 		return "", postStartHooks, err
 	}
 
@@ -3606,7 +3607,7 @@ func (c *containerLXC) cleanup() {
 
 	// Remove the security profiles
 	AADeleteProfile(c)
-	SeccompDeleteProfile(c)
+	seccomp.DeleteProfile(c)
 
 	// Remove the devices path
 	os.Remove(c.DevicesPath())
@@ -6360,7 +6361,7 @@ func (c *containerLXC) InsertSeccompUnixDevice(prefix string, m config.Device, p
 		return err
 	}
 
-	err, uid, gid, _, _ := taskIds(pid)
+	uid, gid, _, _, err := seccomp.TaskIDs(pid)
 	if err != nil {
 		return err
 	}
diff --git a/lxd/devlxd.go b/lxd/devlxd.go
index 060eafef4e..f5f2baab2d 100644
--- a/lxd/devlxd.go
+++ b/lxd/devlxd.go
@@ -20,6 +20,7 @@ import (
 
 	"github.com/lxc/lxd/lxd/events"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
+	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/ucred"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
@@ -217,7 +218,7 @@ func hoistReq(f func(*Daemon, container, http.ResponseWriter, *http.Request) *de
 			return
 		}
 
-		c, err := findContainerForPid(cred.PID, d)
+		c, err := findContainerForPid(cred.PID, d.State())
 		if err != nil {
 			http.Error(w, err.Error(), 500)
 			return
@@ -352,7 +353,7 @@ func extractUnderlyingConn(w http.ResponseWriter) *net.UnixConn {
 
 var pidNotInContainerErr = fmt.Errorf("pid not in container?")
 
-func findContainerForPid(pid int32, d *Daemon) (container, error) {
+func findContainerForPid(pid int32, s *state.State) (container, error) {
 	/*
 	 * Try and figure out which container a pid is in. There is probably a
 	 * better way to do this. Based on rharper's initial performance
@@ -390,7 +391,7 @@ func findContainerForPid(pid int32, d *Daemon) (container, error) {
 				name = fields[1]
 			}
 
-			inst, err := instanceLoadByProjectAndName(d.State(), project, name)
+			inst, err := instanceLoadByProjectAndName(s, project, name)
 			if err != nil {
 				return nil, err
 			}
@@ -428,7 +429,7 @@ func findContainerForPid(pid int32, d *Daemon) (container, error) {
 		return nil, err
 	}
 
-	instances, err := instanceLoadNodeAll(d.State())
+	instances, err := instanceLoadNodeAll(s)
 	if err != nil {
 		return nil, err
 	}

From 96f27feabbba9320c76279d7a2d56c3082b6060e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 26 Sep 2019 17:46:24 +0100
Subject: [PATCH 5/8] test: Adds seccomp package to static analysis

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 test/suites/static_analysis.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh
index e7ec6f686e..db632955b6 100644
--- a/test/suites/static_analysis.sh
+++ b/test/suites/static_analysis.sh
@@ -94,6 +94,7 @@ test_static_analysis() {
       golint -set_exit_status lxd/iptables/...
       golint -set_exit_status lxd/instance/...
       golint -set_exit_status lxd/unixcred/...
+      golint -set_exit_status lxd/seccomp/...
 
       golint -set_exit_status shared/api/
       golint -set_exit_status shared/cancel/

From be95d6f9b6dad1ad7f54bbfad28d16e976aed607 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 26 Sep 2019 17:47:51 +0100
Subject: [PATCH 6/8] test: Fixes static analysis for ucred package

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 test/suites/static_analysis.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh
index db632955b6..29333c2220 100644
--- a/test/suites/static_analysis.sh
+++ b/test/suites/static_analysis.sh
@@ -93,7 +93,7 @@ test_static_analysis() {
       golint -set_exit_status lxd/dnsmasq/...
       golint -set_exit_status lxd/iptables/...
       golint -set_exit_status lxd/instance/...
-      golint -set_exit_status lxd/unixcred/...
+      golint -set_exit_status lxd/ucred/...
       golint -set_exit_status lxd/seccomp/...
 
       golint -set_exit_status shared/api/

From fbfdc5253ca74ddf2c79557445e0f4defef6dab0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 27 Sep 2019 10:26:40 +0100
Subject: [PATCH 7/8] lxd/apparmor: Moves apparmor into its own package

- Unexports functions and variables where possible.
- Makes go-lint happy.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/{ => apparmor}/apparmor.go | 96 +++++++++++++++++++---------------
 1 file changed, 53 insertions(+), 43 deletions(-)
 rename lxd/{ => apparmor}/apparmor.go (92%)

diff --git a/lxd/apparmor.go b/lxd/apparmor/apparmor.go
similarity index 92%
rename from lxd/apparmor.go
rename to lxd/apparmor/apparmor.go
index 46037ff32f..91e413dcf0 100644
--- a/lxd/apparmor.go
+++ b/lxd/apparmor/apparmor.go
@@ -1,4 +1,4 @@
-package main
+package apparmor
 
 import (
 	"crypto/sha256"
@@ -10,6 +10,7 @@ import (
 	"strings"
 
 	"github.com/lxc/lxd/lxd/project"
+	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/logger"
 
@@ -17,14 +18,14 @@ import (
 )
 
 const (
-	APPARMOR_CMD_LOAD   = "r"
-	APPARMOR_CMD_UNLOAD = "R"
-	APPARMOR_CMD_PARSE  = "Q"
+	cmdLoad   = "r"
+	cmdUnload = "R"
+	cmdParse  = "Q"
 )
 
 var aaPath = shared.VarPath("security", "apparmor")
 
-const AA_PROFILE_BASE = `
+const profileBase = `
   ### Base profile
   capability,
   dbus,
@@ -417,7 +418,7 @@ const AA_PROFILE_BASE = `
   deny /sys/fs?*{,/**} wklx,
 `
 
-const AA_PROFILE_NESTING = `
+const profileNesting = `
   pivot_root,
 
   # Allow sending signals and tracing children namespaces
@@ -444,7 +445,7 @@ const AA_PROFILE_NESTING = `
   mount,
 `
 
-const AA_PROFILE_UNPRIVILEGED = `
+const profileUnprivileged = `
   pivot_root,
 
   # Allow modifying mount propagation
@@ -481,6 +482,15 @@ const AA_PROFILE_UNPRIVILEGED = `
   mount options=(ro,remount) /**,
 `
 
+type instance interface {
+	Project() string
+	Name() string
+	IsNesting() bool
+	DaemonState() *state.State
+	IsPrivileged() bool
+	ExpandedConfig() map[string]string
+}
+
 func mkApparmorName(name string) string {
 	if len(name)+7 >= 253 {
 		hash := sha256.New()
@@ -491,7 +501,8 @@ func mkApparmorName(name string) string {
 	return name
 }
 
-func AANamespace(c container) string {
+// Namespace returns the instance's apparmor namespace.
+func Namespace(c instance) string {
 	/* / is not allowed in apparmor namespace names; let's also trim the
 	 * leading / so it doesn't look like "-var-lib-lxd"
 	 */
@@ -501,23 +512,23 @@ func AANamespace(c container) string {
 	return fmt.Sprintf("lxd-%s_<%s>", name, lxddir)
 }
 
-func AAProfileFull(c container) string {
+// ProfileFull returns the instance's apparmor profile.
+func ProfileFull(c instance) string {
 	lxddir := shared.VarPath("")
 	lxddir = mkApparmorName(lxddir)
 	name := project.Prefix(c.Project(), c.Name())
 	return fmt.Sprintf("lxd-%s_<%s>", name, lxddir)
 }
 
-func AAProfileShort(c container) string {
+func profileShort(c instance) string {
 	name := project.Prefix(c.Project(), c.Name())
 	return fmt.Sprintf("lxd-%s", name)
 }
 
-// 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(c container) string {
-	profile := strings.TrimLeft(AA_PROFILE_BASE, "\n")
+// 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(c instance) string {
+	profile := strings.TrimLeft(profileBase, "\n")
 
 	// Apply new features
 	if aaParserSupports("unix") {
@@ -567,8 +578,8 @@ func getAAProfileContent(c container) string {
   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))
+		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"
@@ -577,16 +588,16 @@ func getAAProfileContent(c container) string {
 	if c.IsNesting() {
 		// Apply nesting bits
 		profile += "\n  ### Configuration: nesting\n"
-		profile += strings.TrimLeft(AA_PROFILE_NESTING, "\n")
+		profile += strings.TrimLeft(profileNesting, "\n")
 		if !state.OS.AppArmorStacking || state.OS.AppArmorStacked {
-			profile += fmt.Sprintf("  change_profile -> \"%s\",\n", AAProfileFull(c))
+			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(AA_PROFILE_UNPRIVILEGED, "\n")
+		profile += strings.TrimLeft(profileUnprivileged, "\n")
 	}
 
 	// Append raw.apparmor
@@ -602,10 +613,10 @@ func getAAProfileContent(c container) string {
 profile "%s" flags=(attach_disconnected,mediate_deleted) {
 %s
 }
-`, AAProfileFull(c), strings.Trim(profile, "\n"))
+`, ProfileFull(c), strings.Trim(profile, "\n"))
 }
 
-func runApparmor(command string, c container) error {
+func runApparmor(command string, c instance) error {
 	state := c.DaemonState()
 	if !state.OS.AppArmorAvailable {
 		return nil
@@ -614,7 +625,7 @@ func runApparmor(command string, c container) error {
 	output, err := shared.RunCommand("apparmor_parser", []string{
 		fmt.Sprintf("-%sWL", command),
 		path.Join(aaPath, "cache"),
-		path.Join(aaPath, "profiles", AAProfileShort(c)),
+		path.Join(aaPath, "profiles", profileShort(c)),
 	}...)
 
 	if err != nil {
@@ -625,7 +636,7 @@ func runApparmor(command string, c container) error {
 	return err
 }
 
-func getAACacheDir() string {
+func getCacheDir() string {
 	basePath := path.Join(aaPath, "cache")
 
 	major, minor, _, err := getAAParserVersion()
@@ -646,7 +657,7 @@ func getAACacheDir() string {
 	return strings.TrimSpace(output)
 }
 
-func mkApparmorNamespace(c container, namespace string) error {
+func mkApparmorNamespace(c instance, namespace string) error {
 	state := c.DaemonState()
 	if !state.OS.AppArmorStacking || state.OS.AppArmorStacked {
 		return nil
@@ -660,15 +671,14 @@ func mkApparmorNamespace(c container, namespace string) error {
 	return nil
 }
 
-// Ensure that the container's policy is loaded into the kernel so the
-// container can boot.
-func AALoadProfile(c container) error {
+// LoadProfile ensures that the instances's policy is loaded into the kernel so the it can boot.
+func LoadProfile(c instance) error {
 	state := c.DaemonState()
 	if !state.OS.AppArmorAdmin {
 		return nil
 	}
 
-	if err := mkApparmorNamespace(c, AANamespace(c)); err != nil {
+	if err := mkApparmorNamespace(c, Namespace(c)); err != nil {
 		return err
 	}
 
@@ -683,7 +693,7 @@ func AALoadProfile(c container) error {
 	 * version out so that the new changes are reflected and we definitely
 	 * force a recompile.
 	 */
-	profile := path.Join(aaPath, "profiles", AAProfileShort(c))
+	profile := path.Join(aaPath, "profiles", profileShort(c))
 	content, err := ioutil.ReadFile(profile)
 	if err != nil && !os.IsNotExist(err) {
 		return err
@@ -705,39 +715,39 @@ func AALoadProfile(c container) error {
 		}
 	}
 
-	return runApparmor(APPARMOR_CMD_LOAD, c)
+	return runApparmor(cmdLoad, c)
 }
 
-// Ensure that the container's policy namespace is unloaded to free kernel
-// memory. This does not delete the policy from disk or cache.
-func AADestroy(c container) error {
+// Destroy ensures that the instances's policy namespace is unloaded to free kernel memory.
+// This does not delete the policy from disk or cache.
+func Destroy(c instance) error {
 	state := c.DaemonState()
 	if !state.OS.AppArmorAdmin {
 		return nil
 	}
 
 	if state.OS.AppArmorStacking && !state.OS.AppArmorStacked {
-		p := path.Join("/sys/kernel/security/apparmor/policy/namespaces", AANamespace(c))
+		p := path.Join("/sys/kernel/security/apparmor/policy/namespaces", Namespace(c))
 		if err := os.Remove(p); err != nil {
 			logger.Error("Error removing apparmor namespace", log.Ctx{"err": err, "ns": p})
 		}
 	}
 
-	return runApparmor(APPARMOR_CMD_UNLOAD, c)
+	return runApparmor(cmdUnload, c)
 }
 
-// Parse the profile without loading it into the kernel.
-func AAParseProfile(c container) error {
+// ParseProfile parses the profile without loading it into the kernel.
+func ParseProfile(c instance) error {
 	state := c.DaemonState()
 	if !state.OS.AppArmorAvailable {
 		return nil
 	}
 
-	return runApparmor(APPARMOR_CMD_PARSE, c)
+	return runApparmor(cmdParse, c)
 }
 
-// Delete the policy from cache/disk.
-func AADeleteProfile(c container) {
+// DeleteProfile removes the policy from cache/disk.
+func DeleteProfile(c instance) {
 	state := c.DaemonState()
 	if !state.OS.AppArmorAdmin {
 		return
@@ -746,8 +756,8 @@ func AADeleteProfile(c container) {
 	/* It's ok if these deletes fail: if the container was never started,
 	 * we'll have never written a profile or cached it.
 	 */
-	os.Remove(path.Join(getAACacheDir(), AAProfileShort(c)))
-	os.Remove(path.Join(aaPath, "profiles", AAProfileShort(c)))
+	os.Remove(path.Join(getCacheDir(), profileShort(c)))
+	os.Remove(path.Join(aaPath, "profiles", profileShort(c)))
 }
 
 func aaParserSupports(feature string) bool {

From 21efa047a29e86ff4edc9e7ee52d248202ded9af Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Fri, 27 Sep 2019 10:27:18 +0100
Subject: [PATCH 8/8] lxd/container/lxc: Updates use of apparmor package

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/container_lxc.go | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index cc83a3a7cb..5e5cbb84fc 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -25,6 +25,7 @@ import (
 	lxc "gopkg.in/lxc/go-lxc.v2"
 	yaml "gopkg.in/yaml.v2"
 
+	"github.com/lxc/lxd/lxd/apparmor"
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/db/query"
@@ -1237,7 +1238,7 @@ func (c *containerLXC) initLXC(config bool) error {
 			}
 		} else {
 			// If not currently confined, use the container's profile
-			profile := AAProfileFull(c)
+			profile := apparmor.ProfileFull(c)
 
 			/* In the nesting case, we want to enable the inside
 			 * LXD to load its profile. Unprivileged containers can
@@ -1247,7 +1248,7 @@ func (c *containerLXC) initLXC(config bool) error {
 			 * profile.
 			 */
 			if c.state.OS.AppArmorStacking && !c.state.OS.AppArmorStacked {
-				profile = fmt.Sprintf("%s//&:%s:", profile, AANamespace(c))
+				profile = fmt.Sprintf("%s//&:%s:", profile, apparmor.Namespace(c))
 			}
 
 			err := lxcSetConfigItem(cc, "lxc.apparmor.profile", profile)
@@ -2684,7 +2685,7 @@ func (c *containerLXC) OnStart() error {
 	}
 
 	// Load the container AppArmor profile
-	err = AALoadProfile(c)
+	err = apparmor.LoadProfile(c)
 	if err != nil {
 		if ourStart {
 			c.StorageStop()
@@ -2698,7 +2699,7 @@ func (c *containerLXC) OnStart() error {
 		// Run any template that needs running
 		err = c.templateApplyNow(c.localConfig[key])
 		if err != nil {
-			AADestroy(c)
+			apparmor.Destroy(c)
 			if ourStart {
 				c.StorageStop()
 			}
@@ -2708,7 +2709,7 @@ func (c *containerLXC) OnStart() error {
 		// Remove the volatile key from the DB
 		err := c.state.Cluster.ContainerConfigRemove(c.id, key)
 		if err != nil {
-			AADestroy(c)
+			apparmor.Destroy(c)
 			if ourStart {
 				c.StorageStop()
 			}
@@ -2718,7 +2719,7 @@ func (c *containerLXC) OnStart() error {
 
 	err = c.templateApplyNow("start")
 	if err != nil {
-		AADestroy(c)
+		apparmor.Destroy(c)
 		if ourStart {
 			c.StorageStop()
 		}
@@ -3053,7 +3054,7 @@ func (c *containerLXC) OnStop(target string) error {
 		c.IsRunning()
 
 		// Unload the apparmor profile
-		err = AADestroy(c)
+		err = apparmor.Destroy(c)
 		if err != nil {
 			logger.Error("Failed to destroy apparmor namespace", log.Ctx{"container": c.Name(), "err": err})
 		}
@@ -3606,7 +3607,7 @@ func (c *containerLXC) cleanup() {
 	c.removeDiskDevices()
 
 	// Remove the security profiles
-	AADeleteProfile(c)
+	apparmor.DeleteProfile(c)
 	seccomp.DeleteProfile(c)
 
 	// Remove the devices path
@@ -4332,7 +4333,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 
 	// If apparmor changed, re-validate the apparmor profile
 	if shared.StringInSlice("raw.apparmor", changedConfig) || shared.StringInSlice("security.nesting", changedConfig) {
-		err = AAParseProfile(c)
+		err = apparmor.ParseProfile(c)
 		if err != nil {
 			return errors.Wrap(err, "Parse AppArmor profile")
 		}
@@ -4404,7 +4405,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 
 			if key == "raw.apparmor" || key == "security.nesting" {
 				// Update the AppArmor profile
-				err = AALoadProfile(c)
+				err = apparmor.LoadProfile(c)
 				if err != nil {
 					return err
 				}


More information about the lxc-devel mailing list