[lxc-devel] [lxd/master] seccomp: abstract syscall handling

brauner on Github lxc-bot at linuxcontainers.org
Fri Jul 12 17:04:48 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/20190712/a3dde5a0/attachment.bin>
-------------- next part --------------
From 3c42afbb2394e9ea65cfa7b10ee6f8b6b5aefdce Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jul 2019 18:33:47 +0200
Subject: [PATCH] seccomp: abstract syscall handling

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/seccomp.go | 144 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 118 insertions(+), 26 deletions(-)

diff --git a/lxd/seccomp.go b/lxd/seccomp.go
index 08f5a85796..d7ff1ff330 100644
--- a/lxd/seccomp.go
+++ b/lxd/seccomp.go
@@ -146,6 +146,9 @@ struct lxd_seccomp_data_arch {
 	int nr_mknodat;
 };
 
+#define LXD_SECCOMP_NOTIFY_MKNOD    0
+#define LXD_SECCOMP_NOTIFY_MKNODAT  1
+
 // ordered by likelihood of usage...
 static const struct lxd_seccomp_data_arch seccomp_notify_syscall_table[] = {
 #ifdef AUDIT_ARCH_X86_64
@@ -267,6 +270,35 @@ static const struct lxd_seccomp_data_arch seccomp_notify_syscall_table[] = {
 #endif
 };
 
+static int seccomp_notify_get_syscall(struct seccomp_notif *req,
+				      struct seccomp_notif_resp *resp)
+{
+	resp->id = req->id;
+	resp->flags = req->flags;
+	resp->val = 0;
+	resp->error = 0;
+
+	for (size_t i = 0; i < (sizeof(seccomp_notify_syscall_table) /
+				sizeof(seccomp_notify_syscall_table[0]));
+	     i++) {
+		const struct lxd_seccomp_data_arch *entry = &seccomp_notify_syscall_table[i];
+
+		if (entry->arch != req->data.arch)
+			continue;
+
+		if (entry->nr_mknod == req->data.nr)
+			return LXD_SECCOMP_NOTIFY_MKNOD;
+
+		if (entry->nr_mknodat == req->data.nr)
+			return LXD_SECCOMP_NOTIFY_MKNODAT;
+
+		break;
+	}
+
+	errno = EINVAL;
+	return -EINVAL;
+}
+
 static int seccomp_notify_verify_syscall(int fd_mem, struct seccomp_notif *req,
 					 struct seccomp_notif_resp *resp,
 					 char *buf, size_t size, mode_t *mode,
@@ -393,6 +425,9 @@ static void seccomp_notify_mknod_update_response(struct seccomp_notify_proxy_msg
 // #cgo CFLAGS: -std=gnu11 -Wvla
 import "C"
 
+const LxdSeccompNotifyMknod = C.LXD_SECCOMP_NOTIFY_MKNOD
+const LxdSeccompNotifyMknodat = C.LXD_SECCOMP_NOTIFY_MKNODAT
+
 const SECCOMP_HEADER = `2
 `
 
@@ -883,21 +918,14 @@ func (s *SeccompServer) InvalidHandler(fd int, siov *SeccompIovec) {
 	siov.PutSeccompIovec()
 }
 
-func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int {
-	var cMode C.mode_t
-	var cDev C.dev_t
-	var cPid C.pid_t
-	cPathBuf := [unix.PathMax]C.char{}
-	errno := int(C.seccomp_notify_verify_syscall(C.int(siov.memFd),
-		siov.req,
-		siov.resp,
-		&cPathBuf[0],
-		unix.PathMax, &cMode,
-		&cDev, &cPid))
-	if errno != 0 {
-		return errno
-	}
+type MknodArgs struct {
+	cMode C.mode_t
+	cDev  C.dev_t
+	cPid  C.pid_t
+	path  string
+}
 
+func (s *SeccompServer) doDeviceSyscall(c container, args *MknodArgs, siov *SeccompIovec) int {
 	diskIdmap, err := c.DiskIdmap()
 	if err != nil {
 		return int(-C.EPERM)
@@ -905,21 +933,21 @@ func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int
 
 	dev := types.Device{}
 	dev["type"] = "unix-char"
-	dev["mode"] = fmt.Sprintf("%#o", cMode)
-	dev["major"] = fmt.Sprintf("%d", unix.Major(uint64(cDev)))
-	dev["minor"] = fmt.Sprintf("%d", unix.Minor(uint64(cDev)))
-	dev["pid"] = fmt.Sprintf("%d", cPid)
-	dev["path"] = C.GoString(&cPathBuf[0])
-	dev["mode_t"] = fmt.Sprintf("%d", cMode)
-	dev["dev_t"] = fmt.Sprintf("%d", cDev)
+	dev["mode"] = fmt.Sprintf("%#o", args.cMode)
+	dev["major"] = fmt.Sprintf("%d", unix.Major(uint64(args.cDev)))
+	dev["minor"] = fmt.Sprintf("%d", unix.Minor(uint64(args.cDev)))
+	dev["pid"] = fmt.Sprintf("%d", args.cPid)
+	dev["path"] = args.path
+	dev["mode_t"] = fmt.Sprintf("%d", args.cMode)
+	dev["dev_t"] = fmt.Sprintf("%d", args.cDev)
 
 	if s.d.os.Shiftfs && !c.IsPrivileged() && diskIdmap == nil {
-		errno = CallForkmknod(c, dev, int(cPid), true)
+		errno := CallForkmknod(c, dev, int(args.cPid), true)
 		if errno != int(-C.ENOMEDIUM) {
 			return errno
 		}
 
-		err = c.InsertSeccompUnixDevice(fmt.Sprintf("forkmknod.unix.%d", int(cPid)), dev, int(cPid))
+		err = c.InsertSeccompUnixDevice(fmt.Sprintf("forkmknod.unix.%d", int(args.cPid)), dev, int(args.cPid))
 		if err != nil {
 			return int(-C.EPERM)
 		}
@@ -927,12 +955,12 @@ func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int
 		return 0
 	}
 
-	errno = CallForkmknod(c, dev, int(cPid), false)
+	errno := CallForkmknod(c, dev, int(args.cPid), false)
 	if errno != int(-C.ENOMEDIUM) {
 		return errno
 	}
 
-	err = c.InsertSeccompUnixDevice(fmt.Sprintf("forkmknod.unix.%d", int(cPid)), dev, int(cPid))
+	err = c.InsertSeccompUnixDevice(fmt.Sprintf("forkmknod.unix.%d", int(args.cPid)), dev, int(args.cPid))
 	if err != nil {
 		return int(-C.EPERM)
 	}
@@ -940,6 +968,70 @@ func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int
 	return 0
 }
 
+func (s *SeccompServer) HandleMknodSyscall(c container, siov *SeccompIovec) int {
+	siov.resp.error = C.device_allowed(C.dev_t(siov.req.data.args[2]), C.mode_t(siov.req.data.args[1]))
+	if siov.resp.error != 0 {
+		logger.Errorf("Device not allowed")
+		return int(siov.resp.error)
+	}
+
+	cPathBuf := [unix.PathMax]C.char{}
+	_, err := C.pread(C.int(siov.memFd), unsafe.Pointer(&cPathBuf[0]), C.size_t(unix.PathMax), C.off_t(siov.req.data.args[0]))
+	if err != nil {
+		logger.Errorf("Failed to read memory for mknod syscall: %s", err)
+		return int(-C.EPERM)
+	}
+
+	args := MknodArgs{
+		cMode: C.mode_t(siov.req.data.args[1]),
+		cDev:  C.dev_t(siov.req.data.args[2]),
+		cPid:  C.pid_t(siov.req.pid),
+		path:  C.GoString(&cPathBuf[0]),
+	}
+
+	return s.doDeviceSyscall(c, &args, siov)
+}
+
+func (s *SeccompServer) HandleMknodatSyscall(c container, siov *SeccompIovec) int {
+	if int(siov.req.data.args[0]) != int(C.AT_FDCWD) {
+		logger.Errorf("Non AT_FDCWD mknodat calls are not allowed")
+		return int(-C.EINVAL)
+	}
+
+	siov.resp.error = C.device_allowed(C.dev_t(siov.req.data.args[3]), C.mode_t(siov.req.data.args[2]))
+	if siov.resp.error != 0 {
+		logger.Errorf("Device not allowed")
+		return int(siov.resp.error)
+	}
+
+	cPathBuf := [unix.PathMax]C.char{}
+	_, err := C.pread(C.int(siov.memFd), unsafe.Pointer(&cPathBuf[0]), C.size_t(unix.PathMax), C.off_t(siov.req.data.args[1]))
+	if err != nil {
+		logger.Errorf("Failed to read memory for mknodat syscall: %s", err)
+		return int(-C.EPERM)
+	}
+
+	args := MknodArgs{
+		cMode: C.mode_t(siov.req.data.args[2]),
+		cDev:  C.dev_t(siov.req.data.args[3]),
+		cPid:  C.pid_t(siov.req.pid),
+		path:  C.GoString(&cPathBuf[0]),
+	}
+
+	return s.doDeviceSyscall(c, &args, siov)
+}
+
+func (s *SeccompServer) HandleSyscall(c container, siov *SeccompIovec) int {
+	switch int(C.seccomp_notify_get_syscall(siov.req, siov.resp)) {
+	case LxdSeccompNotifyMknod:
+		return s.HandleMknodSyscall(c, siov)
+	case LxdSeccompNotifyMknodat:
+		return s.HandleMknodatSyscall(c, siov)
+	}
+
+	return -1
+}
+
 func (s *SeccompServer) Handler(fd int, siov *SeccompIovec) error {
 	logger.Debugf("Handling seccomp notification from: %v", siov.ucred.pid)
 
@@ -952,7 +1044,7 @@ func (s *SeccompServer) Handler(fd int, siov *SeccompIovec) error {
 		return err
 	}
 
-	errno := s.HandleMknodSyscall(c, siov)
+	errno := s.HandleSyscall(c, siov)
 
 	err = siov.SendSeccompIovec(fd, errno)
 	if err != nil {


More information about the lxc-devel mailing list