diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c index 328f891f0..275430a52 100644 --- a/src/lxc/af_unix.c +++ b/src/lxc/af_unix.c @@ -156,7 +156,8 @@ int lxc_abstract_unix_connect(const char *path) int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds, void *data, size_t size) { - __do_free char *cmsgbuf; + __do_free char *cmsgbuf = NULL; + int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsg = NULL; @@ -189,13 +190,19 @@ int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds, msg.msg_iov = &iov; msg.msg_iovlen = 1; - return sendmsg(fd, &msg, MSG_NOSIGNAL); +again: + ret = sendmsg(fd, &msg, MSG_NOSIGNAL); + if (ret < 0) + if (errno == EINTR) + goto again; + + return ret; } int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds, void *data, size_t size) { - __do_free char *cmsgbuf; + __do_free char *cmsgbuf = NULL; int ret; struct msghdr msg; struct iovec iov; @@ -221,8 +228,15 @@ int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds, msg.msg_iov = &iov; msg.msg_iovlen = 1; +again: ret = recvmsg(fd, &msg, 0); - if (ret <= 0) + if (ret < 0) { + if (errno == EINTR) + goto again; + + goto out; + } + if (ret == 0) goto out; /* diff --git a/src/lxc/attach.c b/src/lxc/attach.c index ac0450187..331434b26 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -608,8 +608,8 @@ static bool fetch_seccomp(struct lxc_container *c, lxc_attach_options_t *options if (!(options->namespaces & CLONE_NEWNS) || !(options->attach_flags & LXC_ATTACH_LSM)) { - free(c->lxc_conf->seccomp); - c->lxc_conf->seccomp = NULL; + free(c->lxc_conf->seccomp.seccomp); + c->lxc_conf->seccomp.seccomp = NULL; return true; } @@ -852,7 +852,7 @@ static int attach_child_main(struct attach_clone_payload *payload) } if (init_ctx->container && init_ctx->container->lxc_conf && - init_ctx->container->lxc_conf->seccomp) { + init_ctx->container->lxc_conf->seccomp.seccomp) { struct lxc_conf *conf = init_ctx->container->lxc_conf; ret = lxc_seccomp_load(conf); @@ -861,18 +861,9 @@ static int attach_child_main(struct attach_clone_payload *payload) TRACE("Loaded seccomp profile"); -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - if (conf->has_seccomp_notify) { - ret = lxc_abstract_unix_send_fds(payload->ipc_socket, - &conf->seccomp_notify_fd, - 1, NULL, 0); - close_prot_errno_disarm(conf->seccomp_notify_fd); - if (ret < 0) - goto on_error; - - TRACE("Sent seccomp listener fd to parent"); - } -#endif + ret = lxc_seccomp_send_notifier_fd(&conf->seccomp, payload->ipc_socket); + if (ret < 0) + goto on_error; } close(payload->ipc_socket); @@ -1326,24 +1317,13 @@ int lxc_attach(const char *name, const char *lxcpath, TRACE("Sent LSM label file descriptor %d to child", labelfd); } -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - if (conf->seccomp && conf->has_seccomp_notify) { - ret = lxc_abstract_unix_recv_fds(ipc_sockets[0], - &conf->seccomp_notify_fd, - 1, NULL, 0); - if (ret < 0) - goto close_mainloop; + ret = lxc_seccomp_recv_notifier_fd(&conf->seccomp, ipc_sockets[0]); + if (ret < 0) + goto close_mainloop; - TRACE("Retrieved seccomp listener fd %d from child", - conf->seccomp_notify_fd); - ret = lxc_cmd_seccomp_notify_add_listener(name, lxcpath, - conf->seccomp_notify_fd, - -1, 0); - close_prot_errno_disarm(conf->seccomp_notify_fd); - if (ret < 0) - goto close_mainloop; - } -#endif + ret = lxc_seccomp_add_notifier(name, lxcpath, &conf->seccomp); + if (ret < 0) + goto close_mainloop; /* We're done, the child process should now execute whatever it * is that the user requested. The parent can now track it with diff --git a/src/lxc/commands.c b/src/lxc/commands.c index e42990465..90e3c5863 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -1053,7 +1053,7 @@ int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath, /* unused */ unsigned int flags) { -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +#ifdef HAVE_SECCOMP_NOTIFY int ret, stopped; struct lxc_cmd_rr cmd = { .req = { @@ -1080,43 +1080,39 @@ static int lxc_cmd_seccomp_notify_add_listener_callback(int fd, struct lxc_epoll_descr *descr) { struct lxc_cmd_rsp rsp = {0}; - int ret; -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +#ifdef HAVE_SECCOMP_NOTIFY + int ret; __do_close_prot_errno int recv_fd = -EBADF; int notify_fd = -EBADF; - if (!handler->conf->has_seccomp_notify || - handler->conf->seccomp_notify_proxy_fd < 0) { - rsp.ret = -EINVAL; - goto send_error; + ret = lxc_abstract_unix_recv_fds(fd, &recv_fd, 1, NULL, 0); + if (ret <= 0) { + rsp.ret = -errno; + goto out; } - ret = lxc_abstract_unix_recv_fds(fd, &recv_fd, 1, NULL, 0); - if (ret <= 0) - goto reap_client_fd; + if (!handler->conf->seccomp.notifier.wants_supervision || + handler->conf->seccomp.notifier.proxy_fd < 0) { + SYSERROR("No seccomp proxy fd specified"); + rsp.ret = -EINVAL; + goto out; + } - ret = lxc_mainloop_add_handler(descr, notify_fd, seccomp_notify_handler, + ret = lxc_mainloop_add_handler(descr, recv_fd, seccomp_notify_handler, handler); + if (ret < 0) { + rsp.ret = -errno; + goto out; + } notify_fd = move_fd(recv_fd); - if (ret < 0) - goto reap_client_fd; -send_error: +out: #else rsp.ret = -ENOSYS; + #endif - ret = lxc_cmd_rsp_send(fd, &rsp); - if (ret < 0) - goto reap_client_fd; - - return 0; - -reap_client_fd: - /* Special indicator to lxc_cmd_handler() to close the fd and do - * related cleanup. - */ - return 1; + return lxc_cmd_rsp_send(fd, &rsp); } static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, diff --git a/src/lxc/conf.c b/src/lxc/conf.c index db00c70e9..ec9543f74 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2752,14 +2752,6 @@ struct lxc_conf *lxc_conf_init(void) new->lsm_aa_profile = NULL; lxc_list_init(&new->lsm_aa_raw); new->lsm_se_context = NULL; -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - new->has_seccomp_notify = false; - new->seccomp_notify_fd = -EBADF; - new->seccomp_notify_proxy_fd = -EBADF; - memset(&new->seccomp_notify_proxy_addr, 0, sizeof(new->seccomp_notify_proxy_addr)); - new->seccomp_notify_req = NULL; - new->seccomp_notify_resp = NULL; -#endif new->tmp_umount_proc = false; new->tmp_umount_proc = 0; new->shmount.path_host = NULL; @@ -2771,6 +2763,7 @@ struct lxc_conf *lxc_conf_init(void) new->init_gid = 0; memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup)); memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX); + seccomp_conf_init(new); return new; } @@ -4074,7 +4067,7 @@ void lxc_conf_free(struct lxc_conf *conf) free(conf->lsm_aa_profile); free(conf->lsm_aa_profile_computed); free(conf->lsm_se_context); - lxc_seccomp_free(conf); + lxc_seccomp_free(&conf->seccomp); lxc_clear_config_caps(conf); lxc_clear_config_keepcaps(conf); lxc_clear_cgroups(conf, "lxc.cgroup", CGROUP_SUPER_MAGIC); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index f7b8e9724..2664a1527 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -38,6 +38,7 @@ #include "compiler.h" #include "config.h" #include "list.h" +#include "lxcseccomp.h" #include "ringbuf.h" #include "start.h" #include "terminal.h" @@ -295,19 +296,7 @@ struct lxc_conf { struct lxc_list lsm_aa_raw; char *lsm_se_context; bool tmp_umount_proc; - char *seccomp; /* filename with the seccomp rules */ - unsigned int seccomp_allow_nesting; -#if HAVE_SCMP_FILTER_CTX - scmp_filter_ctx seccomp_ctx; -#endif -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - bool has_seccomp_notify; - int seccomp_notify_fd; - int seccomp_notify_proxy_fd; - struct sockaddr_un seccomp_notify_proxy_addr; - struct seccomp_notif *seccomp_notify_req; - struct seccomp_notif_resp *seccomp_notify_resp; -#endif + struct lxc_seccomp seccomp; int maincmd_fd; unsigned int autodev; /* if 1, mount and fill a /dev at start */ int haltsignal; /* signal used to halt container */ diff --git a/src/lxc/confile.c b/src/lxc/confile.c index da5e45ce3..efbac0c3d 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -780,22 +780,27 @@ static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook) static int set_config_seccomp_allow_nesting(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { +#ifdef HAVE_SECCOMP if (lxc_config_value_empty(value)) return clr_config_seccomp_allow_nesting(key, lxc_conf, NULL); - if (lxc_safe_uint(value, &lxc_conf->seccomp_allow_nesting) < 0) + if (lxc_safe_uint(value, &lxc_conf->seccomp.allow_nesting) < 0) return -1; - if (lxc_conf->seccomp_allow_nesting > 1) + if (lxc_conf->seccomp.allow_nesting > 1) return minus_one_set_errno(EINVAL); return 0; +#else + errno = ENOSYS; + return -1; +#endif } static int set_config_seccomp_notify_proxy(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +#ifdef HAVE_SECCOMP_NOTIFY const char *offset; if (lxc_config_value_empty(value)) @@ -805,7 +810,7 @@ static int set_config_seccomp_notify_proxy(const char *key, const char *value, return minus_one_set_errno(EINVAL); offset = value + 5; - if (lxc_unix_sockaddr(&lxc_conf->seccomp_notify_proxy_addr, offset) < 0) + if (lxc_unix_sockaddr(&lxc_conf->seccomp.notifier.proxy_addr, offset) < 0) return -1; return 0; @@ -817,7 +822,7 @@ static int set_config_seccomp_notify_proxy(const char *key, const char *value, static int set_config_seccomp_profile(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - return set_config_path_item(&lxc_conf->seccomp, value); + return set_config_path_item(&lxc_conf->seccomp.seccomp, value); } static int set_config_execute_cmd(const char *key, const char *value, @@ -3726,17 +3731,22 @@ static int get_config_seccomp_allow_nesting(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - return lxc_get_conf_int(c, retv, inlen, c->seccomp_allow_nesting); +#ifdef HAVE_SECCOMP + return lxc_get_conf_int(c, retv, inlen, c->seccomp.allow_nesting); +#else + errno = ENOSYS; + return -1; +#endif } static int get_config_seccomp_notify_proxy(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +#ifdef HAVE_SECCOMP_NOTIFY return lxc_get_conf_str(retv, inlen, - (c->seccomp_notify_proxy_addr.sun_path[0]) == '/' - ? &c->seccomp_notify_proxy_addr.sun_path[0] - : &c->seccomp_notify_proxy_addr.sun_path[1]); + (c->seccomp.notifier.proxy_addr.sun_path[0]) == '/' + ? &c->seccomp.notifier.proxy_addr.sun_path[0] + : &c->seccomp.notifier.proxy_addr.sun_path[1]); #else return minus_one_set_errno(ENOSYS); #endif @@ -3745,7 +3755,7 @@ static int get_config_seccomp_notify_proxy(const char *key, char *retv, int inle static int get_config_seccomp_profile(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - return lxc_get_conf_str(retv, inlen, c->seccomp); + return lxc_get_conf_str(retv, inlen, c->seccomp.seccomp); } static int get_config_autodev(const char *key, char *retv, int inlen, @@ -4328,16 +4338,21 @@ static inline int clr_config_console_size(const char *key, struct lxc_conf *c, static inline int clr_config_seccomp_allow_nesting(const char *key, struct lxc_conf *c, void *data) { - c->seccomp_allow_nesting = 0; +#ifdef HAVE_SECCOMP + c->seccomp.allow_nesting = 0; return 0; +#else + errno = ENOSYS; + return -1; +#endif } static inline int clr_config_seccomp_notify_proxy(const char *key, struct lxc_conf *c, void *data) { -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - memset(&c->seccomp_notify_proxy_addr, 0, - sizeof(c->seccomp_notify_proxy_addr)); +#ifdef HAVE_SECCOMP_NOTIFY + memset(&c->seccomp.notifier.proxy_addr, 0, + sizeof(c->seccomp.notifier.proxy_addr)); return 0; #else return minus_one_set_errno(ENOSYS); @@ -4347,8 +4362,8 @@ static inline int clr_config_seccomp_notify_proxy(const char *key, static inline int clr_config_seccomp_profile(const char *key, struct lxc_conf *c, void *data) { - free(c->seccomp); - c->seccomp = NULL; + free(c->seccomp.seccomp); + c->seccomp.seccomp = NULL; return 0; } diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index e16639d48..98f86a24e 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -5229,7 +5229,6 @@ out: static int do_lxcapi_seccomp_notify(struct lxc_container *c, unsigned int cmd, int fd) { -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD if (!c || !c->lxc_conf) return minus_one_set_errno(-EINVAL); @@ -5238,13 +5237,10 @@ static int do_lxcapi_seccomp_notify(struct lxc_container *c, unsigned int cmd, i if (fd) return minus_one_set_errno(EINVAL); - return c->lxc_conf->seccomp_notify_fd; + return lxc_seccomp_get_notify_fd(&c->lxc_conf->seccomp); } return minus_one_set_errno(EINVAL); -#else - return minus_one_set_errno(ENOSYS); -#endif } WRAP_API_2(int, lxcapi_seccomp_notify, unsigned int, int) diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 2bd327114..e2e788993 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -31,7 +31,8 @@ #include -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +#ifdef SCMP_ACT_USER_NOTIF +#include #include #endif @@ -69,7 +70,7 @@ enum { LXC_SECCOMP_NOTIFY_MAX, }; -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +#ifdef SCMP_ACT_USER_NOTIF struct seccomp_notify_proxy_msg { uint32_t version; struct seccomp_notif req; diff --git a/src/lxc/lxcseccomp.h b/src/lxc/lxcseccomp.h index 530fffd80..aafe09f12 100644 --- a/src/lxc/lxcseccomp.h +++ b/src/lxc/lxcseccomp.h @@ -24,21 +24,86 @@ #ifndef __LXC_LXCSECCOMP_H #define __LXC_LXCSECCOMP_H +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif #include #ifdef HAVE_SECCOMP +#include #include #endif +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +#include +#include +#endif #include "conf.h" +#include "config.h" +#include "memory_utils.h" + +struct lxc_conf; +struct lxc_epoll_descr; +struct lxc_handler; #ifdef HAVE_SECCOMP + +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD +struct seccomp_notify { + bool wants_supervision; + int notify_fd; + int proxy_fd; + struct sockaddr_un proxy_addr; + struct seccomp_notif *req_buf; + struct seccomp_notif_resp *rsp_buf; +}; + +#define HAVE_SECCOMP_NOTIFY 1 + +#endif /* HAVE_DECL_SECCOMP_NOTIF_GET_FD */ + +struct lxc_seccomp { + char *seccomp; +#if HAVE_SCMP_FILTER_CTX + unsigned int allow_nesting; + scmp_filter_ctx seccomp_ctx; +#endif /* HAVE_SCMP_FILTER_CTX */ + +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD + struct seccomp_notify notifier; +#endif /* HAVE_DECL_SECCOMP_NOTIF_GET_FD */ +}; + extern int lxc_seccomp_load(struct lxc_conf *conf); extern int lxc_read_seccomp_config(struct lxc_conf *conf); -extern void lxc_seccomp_free(struct lxc_conf *conf); +extern void lxc_seccomp_free(struct lxc_seccomp *seccomp); extern int seccomp_notify_handler(int fd, uint32_t events, void *data, struct lxc_epoll_descr *descr); - +extern void seccomp_conf_init(struct lxc_conf *conf); +extern int lxc_seccomp_setup_notifier(struct lxc_seccomp *seccomp, + struct lxc_epoll_descr *descr, + struct lxc_handler *handler); +extern int lxc_seccomp_send_notifier_fd(struct lxc_seccomp *seccomp, + int socket_fd); +extern int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, + int socket_fd); +extern int lxc_seccomp_add_notifier(const char *name, const char *lxcpath, + struct lxc_seccomp *seccomp); +static inline int lxc_seccomp_get_notify_fd(struct lxc_seccomp *seccomp) +{ +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD + return seccomp->notifier.notify_fd; #else + errno = ENOSYS; + return -EBADF; +#endif +} + +#else /* HAVE_SECCOMP */ + +struct lxc_seccomp { + char *seccomp; +}; + static inline int lxc_seccomp_load(struct lxc_conf *conf) { return 0; @@ -49,16 +114,50 @@ static inline int lxc_read_seccomp_config(struct lxc_conf *conf) return 0; } -static inline void lxc_seccomp_free(struct lxc_conf *conf) +static inline void lxc_seccomp_free(struct lxc_seccomp *seccomp) { - free(conf->seccomp); - conf->seccomp = NULL; + free_disarm(seccomp->seccomp); } + static inline int seccomp_notify_handler(int fd, uint32_t events, void *data, struct lxc_epoll_descr *descr) { return -ENOSYS; } -#endif -#endif +static inline void seccomp_conf_init(struct lxc_conf *conf) +{ +} + +static inline int lxc_seccomp_setup_notifier(struct lxc_seccomp *seccomp, + struct lxc_epoll_descr *descr, + struct lxc_handler *handler) +{ + return 0; +} + +static inline int lxc_seccomp_send_notifier_fd(struct lxc_seccomp *seccomp, + int socket_fd) +{ + return 0; +} + +static inline int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, + int socket_fd) +{ + return 0; +} + +static inline int lxc_seccomp_add_notifier(const char *name, const char *lxcpath, + struct lxc_seccomp *seccomp) +{ + return 0; +} + +static inline int lxc_seccomp_get_notify_fd(struct lxc_seccomp *seccomp) +{ + return -EBADF; +} + +#endif /* HAVE_SECCOMP */ +#endif /* __LXC_LXCSECCOMP_H */ diff --git a/src/lxc/memory_utils.h b/src/lxc/memory_utils.h index c1dafb441..b5220c189 100644 --- a/src/lxc/memory_utils.h +++ b/src/lxc/memory_utils.h @@ -55,6 +55,12 @@ static inline void __auto_closedir__(DIR **d) fd = -EBADF; \ } +#define free_disarm(ptr) \ + ({ \ + free(ptr); \ + move_ptr(ptr); \ + }) + static inline void __auto_close__(int *fd) { close_prot_errno_disarm(*fd); diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c index 287da564d..a63b6d69f 100644 --- a/src/lxc/seccomp.c +++ b/src/lxc/seccomp.c @@ -32,10 +32,12 @@ #include #include "af_unix.h" +#include "commands.h" #include "config.h" #include "log.h" #include "lxccontainer.h" #include "lxcseccomp.h" +#include "mainloop.h" #include "memory_utils.h" #include "utils.h" @@ -63,7 +65,7 @@ static int parse_config_v1(FILE *f, char *line, size_t *line_bufsz, struct lxc_c } #if HAVE_SCMP_FILTER_CTX - ret = seccomp_rule_add(conf->seccomp_ctx, SCMP_ACT_ALLOW, nr, 0); + ret = seccomp_rule_add(conf->seccomp.seccomp_ctx, SCMP_ACT_ALLOW, nr, 0); #else ret = seccomp_rule_add(SCMP_ACT_ALLOW, nr, 0); #endif @@ -736,13 +738,13 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c } if (default_policy_action != SCMP_ACT_KILL) { - ret = seccomp_reset(conf->seccomp_ctx, default_policy_action); + ret = seccomp_reset(conf->seccomp.seccomp_ctx, default_policy_action); if (ret != 0) { ERROR("Error re-initializing Seccomp"); return -1; } - ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0); + ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0); if (ret < 0) { errno = -ret; SYSERROR("Failed to turn off no-new-privs"); @@ -750,7 +752,7 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c } #ifdef SCMP_FLTATR_ATL_TSKIP - ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1); + ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1); if (ret < 0) { errno = -ret; SYSWARN("Failed to turn on seccomp nop-skip, continuing"); @@ -941,19 +943,19 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c #if HAVE_DECL_SECCOMP_NOTIF_GET_FD if ((rule.action == SCMP_ACT_USER_NOTIF) && - !conf->has_seccomp_notify) { - ret = seccomp_attr_set(conf->seccomp_ctx, + !conf->seccomp.notifier.wants_supervision) { + ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_NEW_LISTENER, 1); if (ret) goto bad_rule; - conf->has_seccomp_notify = true; + conf->seccomp.notifier.wants_supervision = true; TRACE("Set SCMP_FLTATR_NEW_LISTENER attribute"); } #endif if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, - conf->seccomp_ctx, &rule)) + conf->seccomp.seccomp_ctx, &rule)) goto bad_rule; INFO("Added native rule for arch %d for %s action %d(%s)", @@ -994,7 +996,7 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c INFO("Merging compat seccomp contexts into main context"); if (ctx.contexts[0]) { if (ctx.needs_merge[0]) { - ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[0]); + ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[0]); if (ret < 0) { ERROR("Failed to merge first compat seccomp " "context into main context"); @@ -1010,7 +1012,7 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c if (ctx.contexts[1]) { if (ctx.needs_merge[1]) { - ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[1]); + ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[1]); if (ret < 0) { ERROR("Failed to merge first compat seccomp " "context into main context"); @@ -1026,7 +1028,7 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c if (ctx.contexts[2]) { if (ctx.needs_merge[2]) { - ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[2]); + ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[2]); if (ret < 0) { ERROR("Failed to merge third compat seccomp " "context into main context"); @@ -1128,7 +1130,7 @@ static bool use_seccomp(const struct lxc_conf *conf) char *line = NULL; bool already_enabled = false, found = false; - if (conf->seccomp_allow_nesting > 0) + if (conf->seccomp.allow_nesting > 0) return true; f = fopen("/proc/self/status", "r"); @@ -1167,7 +1169,7 @@ int lxc_read_seccomp_config(struct lxc_conf *conf) int ret; FILE *f; - if (!conf->seccomp) + if (!conf->seccomp.seccomp) return 0; if (!use_seccomp(conf)) @@ -1175,8 +1177,8 @@ int lxc_read_seccomp_config(struct lxc_conf *conf) #if HAVE_SCMP_FILTER_CTX /* XXX for debug, pass in SCMP_ACT_TRAP */ - conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL); - ret = !conf->seccomp_ctx; + conf->seccomp.seccomp_ctx = seccomp_init(SCMP_ACT_KILL); + ret = !conf->seccomp.seccomp_ctx; #else ret = seccomp_init(SCMP_ACT_KILL) < 0; #endif @@ -1188,7 +1190,7 @@ int lxc_read_seccomp_config(struct lxc_conf *conf) /* turn off no-new-privs. We don't want it in lxc, and it breaks * with apparmor */ #if HAVE_SCMP_FILTER_CTX - ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0); + ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0); #else ret = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0); #endif @@ -1199,16 +1201,16 @@ int lxc_read_seccomp_config(struct lxc_conf *conf) } #ifdef SCMP_FLTATR_ATL_TSKIP - ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1); + ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1); if (ret < 0) { errno = -ret; SYSWARN("Failed to turn on seccomp nop-skip, continuing"); } #endif - f = fopen(conf->seccomp, "r"); + f = fopen(conf->seccomp.seccomp, "r"); if (!f) { - SYSERROR("Failed to open seccomp policy file %s", conf->seccomp); + SYSERROR("Failed to open seccomp policy file %s", conf->seccomp.seccomp); return -1; } @@ -1222,14 +1224,14 @@ int lxc_seccomp_load(struct lxc_conf *conf) { int ret; - if (!conf->seccomp) + if (!conf->seccomp.seccomp) return 0; if (!use_seccomp(conf)) return 0; #if HAVE_SCMP_FILTER_CTX - ret = seccomp_load(conf->seccomp_ctx); + ret = seccomp_load(conf->seccomp.seccomp_ctx); #else ret = seccomp_load(); #endif @@ -1245,7 +1247,7 @@ int lxc_seccomp_load(struct lxc_conf *conf) if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) && lxc_log_fd >= 0) { - ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd); + ret = seccomp_export_pfc(conf->seccomp.seccomp_ctx, lxc_log_fd); /* Just give an warning when export error */ if (ret < 0) { errno = -ret; @@ -1255,14 +1257,14 @@ int lxc_seccomp_load(struct lxc_conf *conf) #endif #if HAVE_DECL_SECCOMP_NOTIF_GET_FD - if (conf->has_seccomp_notify) { - ret = seccomp_notif_get_fd(conf->seccomp_ctx); + if (conf->seccomp.notifier.wants_supervision) { + ret = seccomp_notif_get_fd(conf->seccomp.seccomp_ctx); if (ret < 0) { errno = -ret; return -1; } - conf->seccomp_notify_fd = ret; + conf->seccomp.notifier.notify_fd = ret; TRACE("Retrieved new seccomp listener fd %d", ret); } #endif @@ -1270,24 +1272,23 @@ int lxc_seccomp_load(struct lxc_conf *conf) return 0; } -void lxc_seccomp_free(struct lxc_conf *conf) +void lxc_seccomp_free(struct lxc_seccomp *seccomp) { - free(conf->seccomp); - conf->seccomp = NULL; + free_disarm(seccomp->seccomp); #if HAVE_SCMP_FILTER_CTX - if (conf->seccomp_ctx) { - seccomp_release(conf->seccomp_ctx); - conf->seccomp_ctx = NULL; + if (seccomp->seccomp_ctx) { + seccomp_release(seccomp->seccomp_ctx); + seccomp->seccomp_ctx = NULL; } #endif #if HAVE_DECL_SECCOMP_NOTIF_GET_FD - close_prot_errno_disarm(conf->seccomp_notify_fd); - close_prot_errno_disarm(conf->seccomp_notify_proxy_fd); - seccomp_notif_free(conf->seccomp_notify_req, conf->seccomp_notify_resp); - conf->seccomp_notify_req = NULL; - conf->seccomp_notify_resp = NULL; + close_prot_errno_disarm(seccomp->notifier.notify_fd); + close_prot_errno_disarm(seccomp->notifier.proxy_fd); + seccomp_notif_free(seccomp->notifier.req_buf, seccomp->notifier.rsp_buf); + seccomp->notifier.req_buf = NULL; + seccomp->notifier.rsp_buf = NULL; #endif } @@ -1296,9 +1297,9 @@ static int seccomp_notify_reconnect(struct lxc_handler *handler) { __do_close_prot_errno int notify_fd = -EBADF; - close_prot_errno_disarm(handler->conf->seccomp_notify_proxy_fd); + close_prot_errno_disarm(handler->conf->seccomp.notifier.proxy_fd); - notify_fd = lxc_unix_connect(&handler->conf->seccomp_notify_proxy_addr); + notify_fd = lxc_unix_connect(&handler->conf->seccomp.notifier.proxy_addr); if (notify_fd < 0) { SYSERROR("Failed to reconnect to seccomp proxy"); return -1; @@ -1309,7 +1310,7 @@ static int seccomp_notify_reconnect(struct lxc_handler *handler) SYSERROR("Failed to set socket timeout"); return -1; } - handler->conf->seccomp_notify_proxy_fd = move_fd(notify_fd); + handler->conf->seccomp.notifier.proxy_fd = move_fd(notify_fd); return 0; } #endif @@ -1338,9 +1339,9 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data, ssize_t bytes; struct lxc_handler *hdlr = data; struct lxc_conf *conf = hdlr->conf; - struct seccomp_notif *req = conf->seccomp_notify_req; - struct seccomp_notif_resp *resp = conf->seccomp_notify_resp; - int listener_proxy_fd = conf->seccomp_notify_proxy_fd; + struct seccomp_notif *req = conf->seccomp.notifier.req_buf; + 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; if (listener_proxy_fd < 0) { @@ -1390,3 +1391,113 @@ out: return -ENOSYS; #endif } + +void seccomp_conf_init(struct lxc_conf *conf) +{ + conf->seccomp.seccomp = NULL; +#if HAVE_SCMP_FILTER_CTX + conf->seccomp.allow_nesting = 0; + memset(&conf->seccomp.seccomp_ctx, 0, sizeof(conf->seccomp.seccomp_ctx)); +#endif /* HAVE_SCMP_FILTER_CTX */ +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD + conf->seccomp.notifier.wants_supervision = false; + conf->seccomp.notifier.notify_fd = -EBADF; + conf->seccomp.notifier.proxy_fd = -EBADF; + memset(&conf->seccomp.notifier.proxy_addr, 0, + sizeof(conf->seccomp.notifier.proxy_addr)); + conf->seccomp.notifier.req_buf = NULL; + conf->seccomp.notifier.rsp_buf = NULL; +#endif +} + +int lxc_seccomp_setup_notifier(struct lxc_seccomp *seccomp, + struct lxc_epoll_descr *descr, + struct lxc_handler *handler) +{ +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD + if (seccomp->notifier.wants_supervision && + seccomp->notifier.proxy_addr.sun_path[1] != '\0') { + __do_close_prot_errno int notify_fd = -EBADF; + int ret; + + notify_fd = lxc_unix_connect(&seccomp->notifier.proxy_addr); + if (notify_fd < 0) + return -1; + + /* 30 second timeout */ + ret = lxc_socket_set_timeout(notify_fd, 30, 30); + if (ret) + return -1; + + ret = lxc_mainloop_add_handler(descr, + seccomp->notifier.notify_fd, + seccomp_notify_handler, handler); + if (ret < 0) { + ERROR("Failed to add seccomp notify handler for %d to mainloop", + seccomp->notifier.notify_fd); + return -1; + } + + seccomp->notifier.proxy_fd = move_fd(notify_fd); + } +#endif + return 0; +} + +int lxc_seccomp_send_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd) +{ +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD + if (seccomp->notifier.wants_supervision) { + if (lxc_abstract_unix_send_fds(socket_fd, + &seccomp->notifier.notify_fd, 1, + NULL, 0) < 0) + return -1; + close_prot_errno_disarm(seccomp->notifier.notify_fd); + } +#endif + return 0; +} + +int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd) +{ +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD + if (seccomp->notifier.wants_supervision) { + int ret; + + ret = lxc_abstract_unix_recv_fds(socket_fd, + &seccomp->notifier.notify_fd, + 1, NULL, 0); + if (ret < 0) + return -1; + + if (seccomp->notifier.proxy_fd >= 0) { + ret = seccomp_notif_alloc(&seccomp->notifier.req_buf, + &seccomp->notifier.rsp_buf); + if (ret) { + errno = ret; + return -1; + } + } + } +#endif + return 0; +} + +int lxc_seccomp_add_notifier(const char *name, const char *lxcpath, + struct lxc_seccomp *seccomp) +{ + +#if HAVE_DECL_SECCOMP_NOTIF_GET_FD + if (seccomp->notifier.proxy_fd >= 0) { + int ret; + + ret = lxc_cmd_seccomp_notify_add_listener(name, lxcpath, + seccomp->notifier.notify_fd, + -1, 0); + close_prot_errno_disarm(seccomp->notifier.notify_fd); + if (ret < 0) + return -1; + } +#endif + return 0; +} diff --git a/src/lxc/start.c b/src/lxc/start.c index b26d0ce7a..a72970fdf 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -591,32 +591,9 @@ int lxc_poll(const char *name, struct lxc_handler *handler) goto out_mainloop_console; } -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - if (handler->conf->has_seccomp_notify && - handler->conf->seccomp_notify_proxy_addr.sun_path[1] != '\0') { - __do_close_prot_errno int notify_fd = -EBADF; - - notify_fd = lxc_unix_connect(&handler->conf->seccomp_notify_proxy_addr); - if (notify_fd < 0) - goto out_mainloop_console; - - /* 30 second timeout */ - ret = lxc_socket_set_timeout(notify_fd, 30, 30); - if (ret) - goto out_mainloop_console; - - ret = lxc_mainloop_add_handler(&descr, - handler->conf->seccomp_notify_fd, - seccomp_notify_handler, handler); - if (ret < 0) { - ERROR("Failed to add seccomp notify handler for %d to mainloop", - handler->conf->seccomp_notify_fd); - goto out_mainloop_console; - } - - handler->conf->seccomp_notify_proxy_fd = move_fd(notify_fd); - } -#endif + ret = lxc_seccomp_setup_notifier(&handler->conf->seccomp, &descr, handler); + if (ret < 0) + goto out_mainloop_console; if (has_console) { struct lxc_terminal *console = &handler->conf->console; @@ -1357,19 +1334,11 @@ static int do_start(void *data) if (ret < 0) goto out_warn_father; -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - if (handler->conf->has_seccomp_notify) { - ret = lxc_abstract_unix_send_fds(data_sock0, - &handler->conf->seccomp_notify_fd, - 1, NULL, 0); - if (ret < 0) { - SYSERROR("Failed to send seccomp notify fd to parent"); - goto out_warn_father; - } - close(handler->conf->seccomp_notify_fd); - handler->conf->seccomp_notify_fd = -EBADF; + ret = lxc_seccomp_send_notifier_fd(&handler->conf->seccomp, data_sock0); + if (ret < 0) { + SYSERROR("Failed to send seccomp notify fd to parent"); + goto out_warn_father; } -#endif ret = run_lxc_hooks(handler->name, "start", handler->conf, NULL); if (ret < 0) { @@ -1932,25 +1901,11 @@ static int lxc_spawn(struct lxc_handler *handler) goto out_delete_net; } -#if HAVE_DECL_SECCOMP_NOTIF_GET_FD - if (handler->conf->has_seccomp_notify) { - ret = lxc_abstract_unix_recv_fds(handler->data_sock[1], - &handler->conf->seccomp_notify_fd, - 1, NULL, 0); - if (ret < 0) { - SYSERROR("Failed to receive seccomp notify fd from child"); - goto out_delete_net; - } - - ret = seccomp_notif_alloc(&handler->conf->seccomp_notify_req, - &handler->conf->seccomp_notify_resp); - if (ret) { - errno = ret; - ret = -1; - goto out_delete_net; - } + ret = lxc_seccomp_recv_notifier_fd(&handler->conf->seccomp, data_sock1); + if (ret < 0) { + SYSERROR("Failed to receive seccomp notify fd from child"); + goto out_delete_net; } -#endif ret = handler->ops->post_start(handler, handler->data); if (ret < 0) diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index f7e9dc829..309212e9c 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -25,7 +25,8 @@ lxc_test_locktests_SOURCES = locktests.c lxc_test_lxcpath_SOURCES = lxcpath.c lxc_test_may_control_SOURCES = may_control.c lxc_test_mount_injection_SOURCES = mount_injection.c lxctest.h -lxc_test_parse_config_file_SOURCES = parse_config_file.c lxctest.h +lxc_test_parse_config_file_SOURCES = parse_config_file.c \ + lxctest.h lxc_test_raw_clone_SOURCES = lxc_raw_clone.c \ lxctest.h \ ../lxc/namespace.c ../lxc/namespace.h \ @@ -57,6 +58,11 @@ if ENABLE_APPARMOR AM_CFLAGS += -DHAVE_APPARMOR endif +if ENABLE_SECCOMP +AM_CFLAGS += -DHAVE_SECCOMP \ + $(SECCOMP_CFLAGS) +endif + if ENABLE_SELINUX AM_CFLAGS += -DHAVE_SELINUX endif diff --git a/src/tests/parse_config_file.c b/src/tests/parse_config_file.c index b8b71c8e1..c265cd1d9 100644 --- a/src/tests/parse_config_file.c +++ b/src/tests/parse_config_file.c @@ -28,6 +28,7 @@ #include #include +#include "conf.h" #include "confile_utils.h" #include "lxc/state.h" #include "lxctest.h"