diff --git a/configure.ac b/configure.ac index a041f2fdb..8de7204da 100644 --- a/configure.ac +++ b/configure.ac @@ -367,6 +367,7 @@ OLD_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $SECCOMP_CFLAGS" AC_CHECK_TYPES([scmp_filter_ctx], [], [], [[#include ]]) AC_CHECK_DECLS([seccomp_notify_fd], [], [], [[#include ]]) +AC_CHECK_TYPES([struct seccomp_notif_sizes], [], [], [[#include ]]) AC_CHECK_DECLS([seccomp_syscall_resolve_name_arch], [], [], [[#include ]]) CFLAGS="$OLD_CFLAGS" diff --git a/src/lxc/lxcseccomp.h b/src/lxc/lxcseccomp.h index f81943672..3502d19e9 100644 --- a/src/lxc/lxcseccomp.h +++ b/src/lxc/lxcseccomp.h @@ -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; diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c index 1e688a451..48c4e26f0 100644 --- a/src/lxc/seccomp.c +++ b/src/lxc/seccomp.c @@ -49,8 +49,25 @@ #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) {