[lxc-devel] [lxd/master] Moves seccomp to separate package

tomponline on Github lxc-bot at linuxcontainers.org
Thu Sep 26 16:49:13 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 354 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190926/80265f70/attachment.bin>
-------------- next part --------------
From 2cae61a4b7740004663ec3b9045699b85986a201 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/6] 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 +++++++++++++++++++++--------------
 1 file changed, 158 insertions(+), 98 deletions(-)
 rename lxd/{ => seccomp}/seccomp.go (78%)

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..aea64d36fa 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 recieves 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
+}

From 762451d536e436bbe7b7238125cf1ac37b51a9ea 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/6] 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 2d2d433ee5..9203e8c0fd 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -36,6 +36,7 @@ import (
 	"github.com/lxc/lxd/lxd/maas"
 	"github.com/lxc/lxd/lxd/node"
 	"github.com/lxc/lxd/lxd/rbac"
+	"github.com/lxc/lxd/lxd/seccomp"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/lxd/sys"
 	"github.com/lxc/lxd/lxd/task"
@@ -72,7 +73,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)
 
@@ -876,7 +877,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
 			}
@@ -1090,6 +1093,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 dd7a4f4c18de76e21776432b9e3e394e6bc10d95 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/6] 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 90c29b01d1db4afc23d2d2c5a47ed66080266852 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/6] 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 5f9af0685303c2729f36d07c24cf4d30ea415d4c 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/6] 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 835634c79a..4533126afc 100644
--- a/test/suites/static_analysis.sh
+++ b/test/suites/static_analysis.sh
@@ -93,6 +93,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 a42b6203fe39ac1784e46e453318ae56e214447b 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/6] 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 4533126afc..d335b7e67b 100644
--- a/test/suites/static_analysis.sh
+++ b/test/suites/static_analysis.sh
@@ -92,7 +92,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/


More information about the lxc-devel mailing list