]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
seccomp: update notify api
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 5 Jul 2019 07:22:11 +0000 (09:22 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Tue, 9 Jul 2019 10:25:10 +0000 (12:25 +0200)
The previous API doesn't reflect the fact that
`seccomp_notif` and `seccomp_notif_resp` are allocatd
dynamically with sizes figured out at runtime.

We now query the sizes via the seccomp(2) syscall and change
`struct seccomp_notify_proxy_msg` to contain the sizes
instead of the data, with the data following afterwards.

Additionally it did not provide a convenient way to identify
the container the message originated from, for which we now
include a cookie configured via `lxc.seccomp.notify.cookie`.

Since we currently always send exactly one request and await
the response immediately, verify the `id` in the client's
response.

Finally, the proxy message's "version" field is removed, and
we reserve 64 bits in its place.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
configure.ac
src/lxc/lxcseccomp.h
src/lxc/seccomp.c

index a041f2fdb0521c4721b0d5eb7bda15246e627094..8de7204da4a8849c8bd751640089f4eb5bc8dd24 100644 (file)
@@ -367,6 +367,7 @@ OLD_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS $SECCOMP_CFLAGS"
 AC_CHECK_TYPES([scmp_filter_ctx], [], [], [[#include <seccomp.h>]])
 AC_CHECK_DECLS([seccomp_notify_fd], [], [], [[#include <seccomp.h>]])
+AC_CHECK_TYPES([struct seccomp_notif_sizes], [], [], [[#include <seccomp.h>]])
 AC_CHECK_DECLS([seccomp_syscall_resolve_name_arch], [], [], [[#include <seccomp.h>]])
 CFLAGS="$OLD_CFLAGS"
 
index f81943672465ead23f275c28d709631e4604ce7a..3502d19e96d88ab7f7e97b43185a8ccb5a2d45b0 100644 (file)
@@ -54,12 +54,21 @@ struct lxc_handler;
 
 #if HAVE_DECL_SECCOMP_NOTIFY_FD
 
+#if !HAVE_STRUCT_SECCOMP_NOTIF_SIZES
+struct seccomp_notif_sizes {
+       __u16 seccomp_notif;
+       __u16 seccomp_notif_resp;
+       __u16 seccomp_data;
+};
+#endif
+
 struct seccomp_notify_proxy_msg {
-       uint32_t version;
-       struct seccomp_notif req;
-       struct seccomp_notif_resp resp;
+       uint64_t __reserved;
        pid_t monitor_pid;
        pid_t init_pid;
+       struct seccomp_notif_sizes sizes;
+       uint64_t cookie_len;
+       /* followed by: seccomp_notif, seccomp_notif_resp, cookie */
 };
 
 struct seccomp_notify {
@@ -67,6 +76,7 @@ struct seccomp_notify {
        int notify_fd;
        int proxy_fd;
        struct sockaddr_un proxy_addr;
+       struct seccomp_notif_sizes sizes;
        struct seccomp_notif *req_buf;
        struct seccomp_notif_resp *rsp_buf;
        char *cookie;
index 1e688a451707a9c5228570881230dfcd23f2768b..48c4e26f0d7977a00f474d0a09cd0e488ad145bd 100644 (file)
 #define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
 #endif
 
+#ifndef SECCOMP_GET_NOTIF_SIZES
+#define SECCOMP_GET_NOTIF_SIZES 3
+#endif
+
 lxc_log_define(seccomp, lxc);
 
+#if HAVE_DECL_SECCOMP_NOTIFY_FD
+static inline int __seccomp(unsigned int operation, unsigned int flags,
+                         void *args)
+{
+#ifdef __NR_seccomp
+       return syscall(__NR_seccomp, operation, flags, args);
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+#endif
+
 static int parse_config_v1(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf)
 {
        int ret = 0;
@@ -1333,6 +1350,8 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
        __do_close_prot_errno int fd_mem = -EBADF;
        int reconnect_count, ret;
        ssize_t bytes;
+       struct iovec iov[4];
+       size_t iov_len, msg_base_size, msg_full_size;
        char mem_path[6 /* /proc/ */
                      + INTTYPE_TO_STRLEN(int64_t)
                      + 3 /* mem */
@@ -1343,6 +1362,8 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
        struct seccomp_notif_resp *resp = conf->seccomp.notifier.rsp_buf;
        int listener_proxy_fd = conf->seccomp.notifier.proxy_fd;
        struct seccomp_notify_proxy_msg msg = {0};
+       char *cookie = conf->seccomp.notifier.cookie;
+       uint64_t req_id;
 
        if (listener_proxy_fd < 0) {
                ERROR("No seccomp proxy registered");
@@ -1355,6 +1376,9 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
                goto out;
        }
 
+       /* remember the ID in case we receive garbage from the proxy */
+       resp->id = req_id = req->id;
+
        snprintf(mem_path, sizeof(mem_path), "/proc/%d/mem", req->pid);
        fd_mem = open(mem_path, O_RDONLY | O_CLOEXEC);
        if (fd_mem < 0) {
@@ -1374,15 +1398,38 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
                goto out;
        }
 
-       memcpy(&msg.req, req, sizeof(msg.req));
        msg.monitor_pid = hdlr->monitor_pid;
        msg.init_pid = hdlr->pid;
+       memcpy(&msg.sizes, &conf->seccomp.notifier.sizes, sizeof(msg.sizes));
+
+       msg_base_size = 0;
+       iov[0].iov_base = &msg;
+       msg_base_size += (iov[0].iov_len = sizeof(msg));
+       iov[1].iov_base = req;
+       msg_base_size += (iov[1].iov_len = msg.sizes.seccomp_notif);
+       iov[2].iov_base = resp;
+       msg_base_size += (iov[2].iov_len = msg.sizes.seccomp_notif_resp);
+       msg_full_size = msg_base_size;
+
+       if (cookie) {
+               size_t len = strlen(cookie);
+
+               msg.cookie_len = (uint64_t)len;
+
+               iov[3].iov_base = cookie;
+               msg_full_size += (iov[3].iov_len = len);
+
+               iov_len = 4;
+       } else {
+               iov_len = 3;
+       }
 
        reconnect_count = 0;
        do {
-               bytes = lxc_unix_send_fds(listener_proxy_fd, &fd_mem, 1, &msg,
-                                         sizeof(msg));
-               if (bytes != (ssize_t)sizeof(msg)) {
+               bytes = lxc_abstract_unix_send_fds_iov(listener_proxy_fd,
+                                                      &fd_mem, 1, iov,
+                                                      iov_len);
+               if (bytes != (ssize_t)msg_full_size) {
                        SYSERROR("Failed to forward message to seccomp proxy");
                        if (seccomp_notify_default_answer(fd, req, resp, hdlr))
                                goto out;
@@ -1391,17 +1438,24 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
 
        close_prot_errno_disarm(fd_mem);
 
+       if (resp->id != req_id) {
+               resp->id = req_id;
+               ERROR("Proxy returned response with illegal id");
+               (void)seccomp_notify_default_answer(fd, req, resp, hdlr);
+               goto out;
+       }
+
        reconnect_count = 0;
        do {
-               bytes = lxc_recv_nointr(listener_proxy_fd, &msg, sizeof(msg), 0);
-               if (bytes != (ssize_t)sizeof(msg)) {
+               bytes = lxc_recvmsg_nointr_iov(listener_proxy_fd, iov,iov_len,
+                                              0);
+               if (bytes != (ssize_t)msg_base_size) {
                        SYSERROR("Failed to receive message from seccomp proxy");
                        if (seccomp_notify_default_answer(fd, req, resp, hdlr))
                                goto out;
                }
        } while (reconnect_count++);
 
-       memcpy(resp, &msg.resp, sizeof(*resp));
        ret = seccomp_notify_respond(fd, resp);
        if (ret)
                SYSERROR("Failed to send seccomp notification");
@@ -1454,6 +1508,13 @@ int lxc_seccomp_setup_proxy(struct lxc_seccomp *seccomp,
                        return -1;
                }
 
+               ret = __seccomp(SECCOMP_GET_NOTIF_SIZES, 0,
+                               &seccomp->notifier.sizes);
+               if (ret) {
+                       SYSERROR("Failed to query seccomp notify struct sizes");
+                       return -1;
+               }
+
                ret = seccomp_notify_alloc(&seccomp->notifier.req_buf,
                                          &seccomp->notifier.rsp_buf);
                if (ret) {