[lxc-devel] [lxd/master] seccomp: cleanup + simplify

brauner on Github lxc-bot at linuxcontainers.org
Fri Jul 12 00:33:14 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190711/02d4dc35/attachment.bin>
-------------- next part --------------
From 9bbf3b8ac1566fb9627d1928e1b306e1b479d5c6 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jul 2019 02:29:59 +0200
Subject: [PATCH] seccomp: cleanup + simplify

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/seccomp.go                   | 273 +++++++++++++++++--------------
 shared/netutils/network_linux.go |   8 +-
 2 files changed, 158 insertions(+), 123 deletions(-)

diff --git a/lxd/seccomp.go b/lxd/seccomp.go
index 40c14c847b..0d23334fae 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp.go
@@ -567,6 +567,134 @@ type SeccompServer struct {
 	l    net.Listener
 }
 
+type SeccompIovec struct {
+	ucred  *ucred
+	memFd  int
+	procFd int
+	msg    *C.struct_seccomp_notify_proxy_msg
+	req    *C.struct_seccomp_notif
+	resp   *C.struct_seccomp_notif_resp
+	cookie *C.char
+	iov    *C.struct_iovec
+}
+
+func NewSeccompIovec(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)
+
+	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)
+
+	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)
+
+	cookie_ptr := C.malloc(64 * C.sizeof_char)
+	cookie := (*C.char)(cookie_ptr)
+	C.memset(cookie_ptr, 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)
+
+	C.prepare_seccomp_iovec(iov, msg, req, resp, cookie)
+
+	return &SeccompIovec{
+		memFd:  -1,
+		procFd: -1,
+		msg:    msg,
+		req:    req,
+		resp:   resp,
+		cookie: cookie,
+		iov:    iov,
+		ucred:  ucred,
+	}
+}
+
+func (siov *SeccompIovec) PutSeccompIovec() {
+	if siov.memFd >= 0 {
+		unix.Close(siov.memFd)
+	}
+	if siov.procFd >= 0 {
+		unix.Close(siov.procFd)
+	}
+	C.free(unsafe.Pointer(siov.msg))
+	C.free(unsafe.Pointer(siov.req))
+	C.free(unsafe.Pointer(siov.resp))
+	C.free(unsafe.Pointer(siov.cookie))
+	C.free(unsafe.Pointer(siov.iov))
+}
+
+func (siov *SeccompIovec) 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
+	}
+
+	if len(fds) == 2 {
+		siov.procFd = int(fds[0])
+		siov.memFd = int(fds[1])
+	} else {
+		siov.memFd = int(fds[0])
+	}
+
+	return bytes, nil
+}
+
+func (siov *SeccompIovec) IsValidSeccompIovec(size uint64) bool {
+	if size < uint64(C.SECCOMP_MSG_SIZE_MIN) {
+		logger.Warnf("Disconnected from seccomp socket after incomplete receive")
+		return false
+	}
+	if siov.msg.__reserved != 0 {
+		logger.Warnf("Disconnected from seccomp socket after client sent non-zero reserved field: pid=%v",
+			siov.ucred.pid)
+		return false
+	}
+
+	if siov.msg.sizes.seccomp_notif != C.expected_sizes.seccomp_notif {
+		logger.Warnf("Disconnected from seccomp socket since client uses different seccomp_notif sizes: %d != %d, pid=%v",
+			siov.msg.sizes.seccomp_notif, C.expected_sizes.seccomp_notif, siov.ucred.pid)
+		return false
+	}
+
+	if siov.msg.sizes.seccomp_notif_resp != C.expected_sizes.seccomp_notif_resp {
+		logger.Warnf("Disconnected from seccomp socket since client uses different seccomp_notif_resp sizes: %d != %d, pid=%v",
+			siov.msg.sizes.seccomp_notif_resp, C.expected_sizes.seccomp_notif_resp, siov.ucred.pid)
+		return false
+	}
+
+	if siov.msg.sizes.seccomp_data != C.expected_sizes.seccomp_data {
+		logger.Warnf("Disconnected from seccomp socket since client uses different seccomp_data sizes: %d != %d, pid=%v",
+			siov.msg.sizes.seccomp_data, C.expected_sizes.seccomp_data, siov.ucred.pid)
+		return false
+	}
+
+	return true
+}
+
+func (siov *SeccompIovec) SendSeccompIovec(fd int, goErrno int) error {
+	C.seccomp_notify_mknod_update_response(siov.resp, C.int(goErrno))
+
+	msghdr := C.struct_msghdr{}
+	msghdr.msg_iov = siov.iov
+	msghdr.msg_iovlen = 4 - 1 // without cookie
+	bytes := C.sendmsg(C.int(fd), &msghdr, C.MSG_NOSIGNAL)
+	if bytes < 0 {
+		logger.Debugf("Disconnected from seccomp socket after failed write: pid=%v", siov.ucred.pid)
+		return fmt.Errorf("Failed to send response to seccomp client %v", siov.ucred.pid)
+	}
+
+	if uint64(bytes) != uint64(C.SECCOMP_MSG_SIZE_MIN) {
+		logger.Debugf("Disconnected from seccomp socket after short write: pid=%v", siov.ucred.pid)
+		return fmt.Errorf("Failed to send full response to seccomp client %v", siov.ucred.pid)
+	}
+
+	return nil
+}
+
 func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
 	ret := C.seccomp_notify_get_sizes(&C.expected_sizes)
 	if ret < 0 {
@@ -622,96 +750,25 @@ func NewSeccompServer(d *Daemon, path string) (*SeccompServer, error) {
 				}
 
 				for {
-
-					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)
-
-					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)
-
-					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)
-
-					cookie_ptr := C.malloc(64 * C.sizeof_char)
-					cookie := (*C.char)(cookie_ptr)
-					C.memset(cookie_ptr, 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)
-
-					C.prepare_seccomp_iovec(iov, msg, req, resp, cookie)
-
-					bytes, fds, err := netutils.AbstractUnixReceiveFdData(int(unixFile.Fd()), 2, iov_unsafe_ptr, 4)
-					if err != nil || err == io.EOF {
+					siov := NewSeccompIovec(ucred)
+					bytes, err := siov.ReceiveSeccompIovec(int(unixFile.Fd()))
+					if err != nil {
 						logger.Debugf("Disconnected from seccomp socket after failed receive: pid=%v, err=%s", ucred.pid, err)
 						c.Close()
 						return
 					}
 
-					fdMem := -1
-					fdProc := -1
-
-					if len(fds) == 2 {
-						fdProc = int(fds[0])
-						fdMem = int(fds[1])
-					} else {
-						fdMem = int(fds[0])
-					}
-
 					handleInvalidRequest := func() {
 						s.InvalidHandler(c, int(unixFile.Fd()))
-						if fdMem >= 0 {
-							unix.Close(fdMem)
-						}
-						if fdProc >= 0 {
-							unix.Close(fdProc)
-						}
-						C.free(unsafe.Pointer(msg))
-						C.free(unsafe.Pointer(req))
-						C.free(unsafe.Pointer(resp))
-						C.free(unsafe.Pointer(cookie))
-					}
-
-					if uint64(bytes) < uint64(C.SECCOMP_MSG_SIZE_MIN) {
-						logger.Warnf("Disconnected from seccomp socket after incomplete receive: pid=%v",
-							ucred.pid)
-						go handleInvalidRequest()
-						continue
-					}
-
-					if msg.__reserved != 0 {
-						logger.Warnf("Disconnected from seccomp socket after client sent non-zero reserved field: pid=%v",
-							ucred.pid)
-						go handleInvalidRequest()
-						continue
-					}
-
-					if msg.sizes.seccomp_notif != C.expected_sizes.seccomp_notif {
-						logger.Warnf("Disconnected from seccomp socket since client uses different seccomp_notif sizes: %d != %d, pid=%v",
-							msg.sizes.seccomp_notif, C.expected_sizes.seccomp_notif, ucred.pid)
-						go handleInvalidRequest()
-						continue
-					}
-
-					if msg.sizes.seccomp_notif_resp != C.expected_sizes.seccomp_notif_resp {
-						logger.Warnf("Disconnected from seccomp socket since client uses different seccomp_notif_resp sizes: %d != %d, pid=%v",
-							msg.sizes.seccomp_notif_resp, C.expected_sizes.seccomp_notif_resp, ucred.pid)
-						go handleInvalidRequest()
-						continue
+						siov.PutSeccompIovec()
 					}
 
-					if msg.sizes.seccomp_data != C.expected_sizes.seccomp_data {
-						logger.Warnf("Disconnected from seccomp socket since client uses different seccomp_data sizes: %d != %d, pid=%v",
-							msg.sizes.seccomp_data, C.expected_sizes.seccomp_data, ucred.pid)
+					if !siov.IsValidSeccompIovec(bytes) {
 						go handleInvalidRequest()
 						continue
 					}
 
-					go s.Handler(c, int(unixFile.Fd()), ucred, fdMem, fdProc, iov, msg, req, resp, cookie)
+					go s.Handler(c, int(unixFile.Fd()), siov)
 				}
 			}()
 		}
@@ -825,24 +882,10 @@ func (s *SeccompServer) InvalidHandler(c net.Conn, clientFd int) {
 	C.sendmsg(C.int(clientFd), &msghdr, C.MSG_NOSIGNAL)
 }
 
-func (s *SeccompServer) Handler(c net.Conn, clientFd int, ucred *ucred,
-	fdMem int, fdProc int, iov *C.struct_iovec, msg *C.struct_seccomp_notify_proxy_msg,
-	req *C.struct_seccomp_notif, resp *C.struct_seccomp_notif_resp,
-	cookie *C.char) error {
-	logger.Debugf("Handling seccomp notification from: %v", ucred.pid)
+func (s *SeccompServer) Handler(c net.Conn, clientFd int, siov *SeccompIovec) error {
+	logger.Debugf("Handling seccomp notification from: %v", siov.ucred.pid)
 
-	defer func() {
-		if fdMem >= 0 {
-			unix.Close(fdMem)
-		}
-		if fdProc >= 0 {
-			unix.Close(fdProc)
-		}
-		C.free(unsafe.Pointer(msg))
-		C.free(unsafe.Pointer(req))
-		C.free(unsafe.Pointer(resp))
-		C.free(unsafe.Pointer(cookie))
-	}()
+	defer siov.PutSeccompIovec()
 
 	var cMode C.mode_t
 	var cDev C.dev_t
@@ -850,7 +893,7 @@ func (s *SeccompServer) Handler(c net.Conn, clientFd int, ucred *ucred,
 	var err error
 	goErrno := 0
 	cPathBuf := [unix.PathMax]C.char{}
-	goErrno = int(C.seccomp_notify_mknod_set_response(C.int(fdMem), req, resp,
+	goErrno = int(C.seccomp_notify_mknod_set_response(C.int(siov.memFd), siov.req, siov.resp,
 		&cPathBuf[0],
 		unix.PathMax, &cMode,
 		&cDev, &cPid))
@@ -865,30 +908,34 @@ func (s *SeccompServer) Handler(c net.Conn, clientFd int, ucred *ucred,
 		dev["mode_t"] = fmt.Sprintf("%d", cMode)
 		dev["dev_t"] = fmt.Sprintf("%d", cDev)
 
-		c, _ := findContainerForPid(int32(msg.monitor_pid), s.d)
+		c, _ := findContainerForPid(int32(siov.msg.monitor_pid), s.d)
 		if c != nil {
 			diskIdmap, err2 := c.DiskIdmap()
 			if err2 != nil {
-				goErrno = int(-C.EPERM)
-				goto send_response
+				return siov.SendSeccompIovec(clientFd, int(-C.EPERM))
 			}
 
 			if s.d.os.Shiftfs && !c.IsPrivileged() && diskIdmap == nil {
 				goErrno = s.doMknod(c, dev, int(cPid), true)
 				if goErrno == int(-C.ENOMEDIUM) {
 					err = c.InsertSeccompUnixDevice(fmt.Sprintf("forkmknod.unix.%d", int(cPid)), dev, int(cPid))
+					if err != nil {
+						goErrno = int(-C.EPERM)
+					} else {
+						goErrno = 0
+					}
 				}
 			} else {
 				goErrno = s.doMknod(c, dev, int(cPid), false)
 				if goErrno == int(-C.ENOMEDIUM) {
 					err = c.InsertSeccompUnixDevice(fmt.Sprintf("forkmknod.unix.%d", int(cPid)), dev, int(cPid))
+					if err != nil {
+						goErrno = int(-C.EPERM)
+					} else {
+						goErrno = 0
+					}
 				}
 			}
-			if err != nil {
-				goErrno = int(-C.EPERM)
-			} else {
-				goErrno = 0
-			}
 		}
 
 		if goErrno != 0 {
@@ -896,24 +943,12 @@ func (s *SeccompServer) Handler(c net.Conn, clientFd int, ucred *ucred,
 		}
 	}
 
-send_response:
-	C.seccomp_notify_mknod_update_response(resp, C.int(goErrno))
-
-	msghdr := C.struct_msghdr{}
-	msghdr.msg_iov = iov
-	msghdr.msg_iovlen = 4 - 1 // without cookie
-	bytes := C.sendmsg(C.int(clientFd), &msghdr, C.MSG_NOSIGNAL)
-	if bytes < 0 {
-		logger.Debugf("Disconnected from seccomp socket after failed write: pid=%v", ucred.pid)
-		return fmt.Errorf("Failed to send response to seccomp client %v", ucred.pid)
-	}
-
-	if uint64(bytes) != uint64(C.SECCOMP_MSG_SIZE_MIN) {
-		logger.Debugf("Disconnected from seccomp socket after short write: pid=%v", ucred.pid)
-		return fmt.Errorf("Failed to send full response to seccomp client %v", ucred.pid)
+	err = siov.SendSeccompIovec(clientFd, goErrno)
+	if err != nil {
+		return err
 	}
 
-	logger.Debugf("Handled seccomp notification from: %v", ucred.pid)
+	logger.Debugf("Handled seccomp notification from: %v", siov.ucred.pid)
 	return nil
 }
 
diff --git a/shared/netutils/network_linux.go b/shared/netutils/network_linux.go
index 5282015ed6..9d1216122f 100644
--- a/shared/netutils/network_linux.go
+++ b/shared/netutils/network_linux.go
@@ -234,17 +234,17 @@ func AbstractUnixReceiveFd(sockFD int) (*os.File, error) {
 	return file, nil
 }
 
-func AbstractUnixReceiveFdData(sockFD int, num_fds int, iov unsafe.Pointer, iovLen int32) (int64, []C.int, error) {
+func AbstractUnixReceiveFdData(sockFD int, num_fds int, iov unsafe.Pointer, iovLen int32) (uint64, []C.int, error) {
 	cfd := make([]C.int, num_fds)
 	sk_fd := C.int(sockFD)
 	ret, errno := C.lxc_abstract_unix_recv_fds_iov(sk_fd, (*C.int)(&cfd[0]), C.int(num_fds), (*C.struct_iovec)(iov), C.size_t(iovLen))
 	if ret < 0 {
-		return -1, []C.int{-C.EBADF}, fmt.Errorf("Failed to receive file descriptor via abstract unix socket: errno=%d", errno)
+		return 0, []C.int{-C.EBADF}, fmt.Errorf("Failed to receive file descriptor via abstract unix socket: errno=%d", errno)
 	}
 
 	if ret == 0 {
-		return -1, []C.int{-C.EBADF}, io.EOF
+		return 0, []C.int{-C.EBADF}, io.EOF
 	}
 
-	return int64(ret), cfd, nil
+	return uint64(ret), cfd, nil
 }


More information about the lxc-devel mailing list