seccomp: update notify api

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>
This commit is contained in:
Wolfgang Bumiller 2019-07-05 09:22:11 +02:00
parent 84cf6d259b
commit 4a094eec4a
3 changed files with 82 additions and 10 deletions

View 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"

View 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;

View File

@ -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) {