[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