]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
seccomp: SECCOMP_RET_USER_NOTIF support
authorChristian Brauner <christian.brauner@ubuntu.com>
Sun, 21 Apr 2019 19:03:51 +0000 (21:03 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Thu, 25 Apr 2019 19:35:28 +0000 (21:35 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
13 files changed:
configure.ac
src/lxc/af_unix.c
src/lxc/attach.c
src/lxc/commands.c
src/lxc/commands.h
src/lxc/conf.c
src/lxc/conf.h
src/lxc/lxccontainer.c
src/lxc/lxccontainer.h
src/lxc/lxcseccomp.h
src/lxc/macro.h
src/lxc/seccomp.c
src/lxc/start.c

index a123602508935101697012f240a1b47fe6d799e7..8d6774f236cf72c3845e104c93d157b78fa564ee 100644 (file)
@@ -363,6 +363,7 @@ AM_COND_IF([ENABLE_CAP],
 OLD_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS $SECCOMP_CFLAGS"
 AC_CHECK_TYPES([scmp_filter_ctx], [], [], [[#include <seccomp.h>]])
+AC_CHECK_DECLS([seccomp_notif_get_fd], [], [], [[#include <seccomp.h>]])
 AC_CHECK_DECLS([seccomp_syscall_resolve_name_arch], [], [], [[#include <seccomp.h>]])
 CFLAGS="$OLD_CFLAGS"
 
index 3b00d64fb531c616e084bbc41fdb79a67d77cb56..06700fac1ead675980f66c19facd61e8930d1fcc 100644 (file)
@@ -201,7 +201,8 @@ int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
        struct iovec iov;
        struct cmsghdr *cmsg = NULL;
        char buf[1] = {0};
-       size_t cmsgbufsize = CMSG_SPACE(num_recvfds * sizeof(int));
+       size_t cmsgbufsize = CMSG_SPACE(sizeof(struct ucred)) +
+                            CMSG_SPACE(num_recvfds * sizeof(int));
 
        memset(&msg, 0, sizeof(msg));
        memset(&iov, 0, sizeof(iov));
@@ -224,12 +225,20 @@ int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
        if (ret <= 0)
                goto out;
 
-       cmsg = CMSG_FIRSTHDR(&msg);
-
-       memset(recvfds, -1, num_recvfds * sizeof(int));
-       if (cmsg && cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
-           cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
-               memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
+       /*
+        * If SO_PASSCRED is set we will always get a ucred message.
+        */
+       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+               if (cmsg->cmsg_type != SCM_RIGHTS)
+                       continue;
+
+               memset(recvfds, -1, num_recvfds * sizeof(int));
+               if (cmsg &&
+                   cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
+                   cmsg->cmsg_level == SOL_SOCKET)
+                       memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
+               break;
+       }
 
 out:
        return ret;
index f2a1339d3f61c0469cf2c061c49f2515e388cba3..ac0450187bfe71d9382381a244b0891628813647 100644 (file)
@@ -853,11 +853,26 @@ 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) {
-               ret = lxc_seccomp_load(init_ctx->container->lxc_conf);
+               struct lxc_conf *conf = init_ctx->container->lxc_conf;
+
+               ret = lxc_seccomp_load(conf);
                if (ret < 0)
                        goto on_error;
 
                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
        }
 
        close(payload->ipc_socket);
@@ -1311,6 +1326,25 @@ 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;
+
+                       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
+
                /* We're done, the child process should now execute whatever it
                 * is that the user requested. The parent can now track it with
                 * waitpid() or similar.
index ad2c578e14944dcd85d7825911c7ce7e53dbadbf..e429904652307827ea3c2717438b67d46ae79c43 100644 (file)
@@ -47,6 +47,7 @@
 #include "log.h"
 #include "lxc.h"
 #include "lxclock.h"
+#include "lxcseccomp.h"
 #include "mainloop.h"
 #include "memory_utils.h"
 #include "monitor.h"
@@ -97,6 +98,7 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
                [LXC_CMD_ADD_STATE_CLIENT]    = "add_state_client",
                [LXC_CMD_CONSOLE_LOG]         = "console_log",
                [LXC_CMD_SERVE_STATE_CLIENTS] = "serve_state_clients",
+               [LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER] = "seccomp_notify_add_listener",
        };
 
        if (cmd >= LXC_CMD_MAX)
@@ -244,14 +246,21 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
        if (ret < 0 || (size_t)ret != sizeof(cmd->req))
                return -1;
 
-       if (cmd->req.datalen <= 0)
-               return move_fd(client_fd);
+       if (cmd->req.cmd == LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER) {
+               int notify_fd = PTR_TO_INT(cmd->req.data);
+               ret = lxc_abstract_unix_send_fds(client_fd, &notify_fd, 1, NULL, 0);
+               if (ret <= 0)
+                       return -1;
+       } else {
+               if (cmd->req.datalen <= 0)
+                       return move_fd(client_fd);
 
-       errno = EMSGSIZE;
-       ret = lxc_send_nointr(client_fd, (void *)cmd->req.data,
-                             cmd->req.datalen, MSG_NOSIGNAL);
-       if (ret < 0 || ret != (ssize_t)cmd->req.datalen)
-               return -1;
+               errno = EMSGSIZE;
+               ret = lxc_send_nointr(client_fd, (void *)cmd->req.data,
+                                     cmd->req.datalen, MSG_NOSIGNAL);
+               if (ret < 0 || ret != (ssize_t)cmd->req.datalen)
+                       return -1;
+       }
 
        return move_fd(client_fd);
 }
@@ -373,7 +382,8 @@ pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath)
 }
 
 static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req,
-                                        struct lxc_handler *handler)
+                                        struct lxc_handler *handler,
+                                        struct lxc_epoll_descr *descr)
 {
        intmax_t pid = handler->pid;
 
@@ -407,7 +417,8 @@ int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath)
 }
 
 static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
-                                           struct lxc_handler *handler)
+                                           struct lxc_handler *handler,
+                                           struct lxc_epoll_descr *descr)
 {
        struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->ns_clone_flags) };
 
@@ -457,7 +468,8 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
 }
 
 static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
-                                      struct lxc_handler *handler)
+                                      struct lxc_handler *handler,
+                                      struct lxc_epoll_descr *descr)
 {
        const char *path;
        struct lxc_cmd_rsp rsp;
@@ -509,7 +521,8 @@ char *lxc_cmd_get_config_item(const char *name, const char *item,
 }
 
 static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req,
-                                           struct lxc_handler *handler)
+                                           struct lxc_handler *handler,
+                                           struct lxc_epoll_descr *descr)
 {
        __do_free char *cidata = NULL;
        int cilen;
@@ -575,7 +588,8 @@ int lxc_cmd_get_state(const char *name, const char *lxcpath)
 }
 
 static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req,
-                                     struct lxc_handler *handler)
+                                     struct lxc_handler *handler,
+                                     struct lxc_epoll_descr *descr)
 {
        struct lxc_cmd_rsp rsp = { .data = INT_TO_PTR(handler->state) };
 
@@ -622,7 +636,8 @@ int lxc_cmd_stop(const char *name, const char *lxcpath)
 }
 
 static int lxc_cmd_stop_callback(int fd, struct lxc_cmd_req *req,
-                                struct lxc_handler *handler)
+                                struct lxc_handler *handler,
+                                struct lxc_epoll_descr *descr)
 {
        struct lxc_cmd_rsp rsp;
        int stopsignal = SIGKILL;
@@ -665,7 +680,8 @@ int lxc_cmd_terminal_winch(const char *name, const char *lxcpath)
 }
 
 static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req,
-                                          struct lxc_handler *handler)
+                                          struct lxc_handler *handler,
+                                          struct lxc_epoll_descr *descr)
 {
        /* should never be called */
        return -1;
@@ -720,7 +736,8 @@ int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
 }
 
 static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
-                                   struct lxc_handler *handler)
+                                   struct lxc_handler *handler,
+                                   struct lxc_epoll_descr *descr)
 {
        int masterfd, ret;
        struct lxc_cmd_rsp rsp;
@@ -773,7 +790,8 @@ char *lxc_cmd_get_name(const char *hashed_sock_name)
 }
 
 static int lxc_cmd_get_name_callback(int fd, struct lxc_cmd_req *req,
-                                    struct lxc_handler *handler)
+                                    struct lxc_handler *handler,
+                                    struct lxc_epoll_descr *descr)
 {
        struct lxc_cmd_rsp rsp;
 
@@ -811,7 +829,8 @@ char *lxc_cmd_get_lxcpath(const char *hashed_sock_name)
 }
 
 static int lxc_cmd_get_lxcpath_callback(int fd, struct lxc_cmd_req *req,
-                                       struct lxc_handler *handler)
+                                       struct lxc_handler *handler,
+                                       struct lxc_epoll_descr *descr)
 {
        struct lxc_cmd_rsp rsp;
 
@@ -872,7 +891,8 @@ int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
 }
 
 static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
-                                            struct lxc_handler *handler)
+                                            struct lxc_handler *handler,
+                                            struct lxc_epoll_descr *descr)
 {
        int ret;
        struct lxc_cmd_rsp rsp = {0};
@@ -943,7 +963,8 @@ int lxc_cmd_console_log(const char *name, const char *lxcpath,
 }
 
 static int lxc_cmd_console_log_callback(int fd, struct lxc_cmd_req *req,
-                                       struct lxc_handler *handler)
+                                       struct lxc_handler *handler,
+                                       struct lxc_epoll_descr *descr)
 {
        struct lxc_cmd_rsp rsp;
        uint64_t buffer_size = handler->conf->console.buffer_size;
@@ -1002,7 +1023,8 @@ int lxc_cmd_serve_state_clients(const char *name, const char *lxcpath,
 }
 
 static int lxc_cmd_serve_state_clients_callback(int fd, struct lxc_cmd_req *req,
-                                               struct lxc_handler *handler)
+                                               struct lxc_handler *handler,
+                                               struct lxc_epoll_descr *descr)
 {
        int ret;
        lxc_state_t state = PTR_TO_INT(req->data);
@@ -1025,62 +1047,138 @@ reap_client_fd:
        return 1;
 }
 
+int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath,
+                                       int fd,
+                                       /* unused */ unsigned int command,
+                                       /* unused */ unsigned int flags)
+{
+
+#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+       int ret, stopped;
+       struct lxc_cmd_rr cmd = {
+               .req = {
+                       .cmd = LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER,
+                       .data = INT_TO_PTR(fd),
+               },
+       };
+
+       ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
+       if (ret < 0) {
+               SYSERROR("Failed to execute command");
+               return -1;
+       }
+
+       return cmd.rsp.ret;
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
+
+static int lxc_cmd_seccomp_notify_add_listener_callback(int fd,
+                                                       struct lxc_cmd_req *req,
+                                                       struct lxc_handler *handler,
+                                                       struct lxc_epoll_descr *descr)
+{
+       struct lxc_cmd_rsp rsp = {0};
+       int ret;
+
+#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+       __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)
+               goto reap_client_fd;
+
+       ret = lxc_mainloop_add_handler(descr, notify_fd, seccomp_notify_handler,
+                                      handler);
+       notify_fd = move_fd(recv_fd);
+       if (ret < 0)
+               goto reap_client_fd;
+
+send_error:
+#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;
+}
+
 static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
-                          struct lxc_handler *handler)
+                          struct lxc_handler *handler,
+                          struct lxc_epoll_descr *descr)
 {
-       typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *);
+       typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *,
+                               struct lxc_epoll_descr *);
 
        callback cb[LXC_CMD_MAX] = {
-               [LXC_CMD_CONSOLE]             = lxc_cmd_console_callback,
-               [LXC_CMD_TERMINAL_WINCH]      = lxc_cmd_terminal_winch_callback,
-               [LXC_CMD_STOP]                = lxc_cmd_stop_callback,
-               [LXC_CMD_GET_STATE]           = lxc_cmd_get_state_callback,
-               [LXC_CMD_GET_INIT_PID]        = lxc_cmd_get_init_pid_callback,
-               [LXC_CMD_GET_CLONE_FLAGS]     = lxc_cmd_get_clone_flags_callback,
-               [LXC_CMD_GET_CGROUP]          = lxc_cmd_get_cgroup_callback,
-               [LXC_CMD_GET_CONFIG_ITEM]     = lxc_cmd_get_config_item_callback,
-               [LXC_CMD_GET_NAME]            = lxc_cmd_get_name_callback,
-               [LXC_CMD_GET_LXCPATH]         = lxc_cmd_get_lxcpath_callback,
-               [LXC_CMD_ADD_STATE_CLIENT]    = lxc_cmd_add_state_client_callback,
-               [LXC_CMD_CONSOLE_LOG]         = lxc_cmd_console_log_callback,
-               [LXC_CMD_SERVE_STATE_CLIENTS] = lxc_cmd_serve_state_clients_callback,
+               [LXC_CMD_CONSOLE]                     = lxc_cmd_console_callback,
+               [LXC_CMD_TERMINAL_WINCH]              = lxc_cmd_terminal_winch_callback,
+               [LXC_CMD_STOP]                        = lxc_cmd_stop_callback,
+               [LXC_CMD_GET_STATE]                   = lxc_cmd_get_state_callback,
+               [LXC_CMD_GET_INIT_PID]                = lxc_cmd_get_init_pid_callback,
+               [LXC_CMD_GET_CLONE_FLAGS]             = lxc_cmd_get_clone_flags_callback,
+               [LXC_CMD_GET_CGROUP]                  = lxc_cmd_get_cgroup_callback,
+               [LXC_CMD_GET_CONFIG_ITEM]             = lxc_cmd_get_config_item_callback,
+               [LXC_CMD_GET_NAME]                    = lxc_cmd_get_name_callback,
+               [LXC_CMD_GET_LXCPATH]                 = lxc_cmd_get_lxcpath_callback,
+               [LXC_CMD_ADD_STATE_CLIENT]            = lxc_cmd_add_state_client_callback,
+               [LXC_CMD_CONSOLE_LOG]                 = lxc_cmd_console_log_callback,
+               [LXC_CMD_SERVE_STATE_CLIENTS]         = lxc_cmd_serve_state_clients_callback,
+               [LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER] = lxc_cmd_seccomp_notify_add_listener_callback,
        };
 
        if (req->cmd >= LXC_CMD_MAX) {
                ERROR("Undefined command id %d", req->cmd);
                return -1;
        }
-       return cb[req->cmd](fd, req, handler);
+       return cb[req->cmd](fd, req, handler, descr);
 }
 
 static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
-                              struct lxc_epoll_descr *descr,
-                              const lxc_cmd_t cmd)
+                              struct lxc_epoll_descr *descr, const lxc_cmd_t cmd)
 {
        struct lxc_list *cur, *next;
 
        lxc_terminal_free(handler->conf, fd);
        lxc_mainloop_del_handler(descr, fd);
-       if (cmd != LXC_CMD_ADD_STATE_CLIENT) {
-               close(fd);
-               return;
-       }
-
-       lxc_list_for_each_safe(cur, &handler->conf->state_clients, next) {
-               struct lxc_state_client *client = cur->elem;
-
-               if (client->clientfd != fd)
-                       continue;
 
-               /* kick client from list */
-               lxc_list_del(cur);
-               close(client->clientfd);
-               free(cur->elem);
-               free(cur);
-               /* No need to walk the whole list. If we found the state client
-                * fd there can't be a second one.
-                */
+       switch (cmd) {
+       case LXC_CMD_ADD_STATE_CLIENT:
+               lxc_list_for_each_safe(cur, &handler->conf->state_clients, next) {
+                       struct lxc_state_client *client = cur->elem;
+
+                       if (client->clientfd != fd)
+                               continue;
+
+                       /* kick client from list */
+                       lxc_list_del(cur);
+                       close(client->clientfd);
+                       free(cur->elem);
+                       free(cur);
+                       /* No need to walk the whole list. If we found the state
+                        * client fd there can't be a second one.
+                        */
+                       break;
+               }
                break;
+       default:
+               close(fd);
        }
 }
 
@@ -1139,7 +1237,7 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
                req.data = reqdata;
        }
 
-       ret = lxc_cmd_process(fd, &req, handler);
+       ret = lxc_cmd_process(fd, &req, handler, descr);
        if (ret) {
                /* This is not an error, but only a request to close fd. */
                ret = LXC_MAINLOOP_CONTINUE;
index 2c024b65d124d4e70966512de71f6b4c09b94100..d7d0c6096aa2d77f24490a69f5ef13f96428dc51 100644 (file)
@@ -46,6 +46,7 @@ typedef enum {
        LXC_CMD_ADD_STATE_CLIENT,
        LXC_CMD_CONSOLE_LOG,
        LXC_CMD_SERVE_STATE_CLIENTS,
+       LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER,
        LXC_CMD_MAX,
 } lxc_cmd_t;
 
@@ -124,5 +125,10 @@ extern int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
 extern int lxc_try_cmd(const char *name, const char *lxcpath);
 extern int lxc_cmd_console_log(const char *name, const char *lxcpath,
                               struct lxc_console_log *log);
+extern int lxc_cmd_seccomp_notify_add_listener(const char *name,
+                                              const char *lxcpath,
+                                              int fd,
+                                              /* unused */ unsigned int command,
+                                              /* unused */ unsigned int flags);
 
 #endif /* __commands_h */
index 986cb89b024bf6bbeedc84a75a36460eda497e98..453763243a42347d738afe2c2e762aa5d87b9557 100644 (file)
@@ -2752,6 +2752,13 @@ 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;
+       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;
index 85daf1b6a514d189df90990c70a17ee3ec601593..f00f477c36cd5ba30880879d63ae1fe4ab2213c9 100644 (file)
@@ -299,6 +299,13 @@ struct lxc_conf {
        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 seccomp_notif *seccomp_notify_req;
+       struct seccomp_notif_resp *seccomp_notify_resp;
 #endif
        int maincmd_fd;
        unsigned int autodev;  /* if 1, mount and fill a /dev at start */
index 72d87410f85c0ce95044ef61dfec3a16c880314b..e16639d4855328fd353a9817ae688798576a098a 100644 (file)
@@ -5227,6 +5227,28 @@ out:
        return ret;
 }
 
+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);
+
+       switch (cmd) {
+       case LXC_SECCOMP_NOTIFY_GET_FD:
+               if (fd)
+                       return minus_one_set_errno(EINVAL);
+
+               return c->lxc_conf->seccomp_notify_fd;
+       }
+
+       return minus_one_set_errno(EINVAL);
+#else
+       return minus_one_set_errno(ENOSYS);
+#endif
+}
+
+WRAP_API_2(int, lxcapi_seccomp_notify, unsigned int, int)
+
 struct lxc_container *lxc_container_new(const char *name, const char *configpath)
 {
        struct lxc_container *c;
@@ -5351,6 +5373,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
        c->console_log = lxcapi_console_log;
        c->mount = lxcapi_mount;
        c->umount = lxcapi_umount;
+       c->seccomp_notify = lxcapi_seccomp_notify;
 
        return c;
 
index c46be521eab71d5147d8c0696b13cf23f1481911..2bd3271149e201e3f5a2792e8b9cb9d51ca5377b 100644 (file)
 
 #include <lxc/attach_options.h>
 
+#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+#include <seccomp.h>
+#endif
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -60,6 +64,21 @@ struct lxc_mount {
        int version;
 };
 
+enum {
+       LXC_SECCOMP_NOTIFY_GET_FD = 0,
+       LXC_SECCOMP_NOTIFY_MAX,
+};
+
+#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+struct seccomp_notify_proxy_msg {
+       uint32_t version;
+       struct seccomp_notif req;
+       struct seccomp_notif_resp resp;
+       pid_t monitor_pid;
+       pid_t init_pid;
+};
+#endif
+
 /*!
  * An LXC container.
  *
@@ -867,6 +886,8 @@ struct lxc_container {
         */
        int (*umount)(struct lxc_container *c, const char *target,
                      unsigned long mountflags, struct lxc_mount *mnt);
+
+       int (*seccomp_notify)(struct lxc_container *c, unsigned int cmd, int fd);
 };
 
 /*!
index 93d57bbdcd31cae8453effebc197b2933ace9c4c..530fffd80a1c416d09deca360e20195a4033b87b 100644 (file)
 #ifndef __LXC_LXCSECCOMP_H
 #define __LXC_LXCSECCOMP_H
 
+#include <errno.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+#endif
+
 #include "conf.h"
 
 #ifdef HAVE_SECCOMP
 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 int seccomp_notify_handler(int fd, uint32_t events, void *data,
+                                 struct lxc_epoll_descr *descr);
+
 #else
 static inline int lxc_seccomp_load(struct lxc_conf *conf)
 {
@@ -46,6 +54,11 @@ static inline void lxc_seccomp_free(struct lxc_conf *conf)
        free(conf->seccomp);
        conf->seccomp = NULL;
 }
+static inline int seccomp_notify_handler(int fd, uint32_t events, void *data,
+                                 struct lxc_epoll_descr *descr)
+{
+       return -ENOSYS;
+}
 #endif
 
 #endif
index b83e4391159332d19d810bd6c697976700f88251..7df3b56f0300b84321a8264f49d9a52d475b90d3 100644 (file)
@@ -407,4 +407,10 @@ enum {
                __internal_fd__;            \
        })
 
+#define minus_one_set_errno(__errno__) \
+       ({                             \
+               errno = __errno__;     \
+               -1;                    \
+       })
+
 #endif /* __LXC_MACRO_H */
index f90602e1f9a32154b19b3d2ebb5d0aae25ae30d7..10b634f2b3a6c083778538765663a4f40a6de289 100644 (file)
@@ -33,7 +33,9 @@
 
 #include "config.h"
 #include "log.h"
+#include "lxccontainer.h"
 #include "lxcseccomp.h"
+#include "memory_utils.h"
 #include "utils.h"
 
 #ifdef __MIPSEL__
@@ -87,6 +89,10 @@ static const char *get_action_name(uint32_t action)
                return "trap";
        case SCMP_ACT_ERRNO(0):
                return "errno";
+#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+       case SCMP_ACT_USER_NOTIF:
+               return "notify";
+#endif
        }
 
        return "invalid action";
@@ -116,6 +122,10 @@ static uint32_t get_v2_default_action(char *line)
                ret_action = SCMP_ACT_ALLOW;
        } else if (strncmp(line, "trap", 4) == 0) {
                ret_action = SCMP_ACT_TRAP;
+#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+       } else if (strncmp(line, "notify", 6) == 0) {
+               ret_action = SCMP_ACT_USER_NOTIF;
+#endif
        } else if (line[0]) {
                ERROR("Unrecognized seccomp action \"%s\"", line);
                return -2;
@@ -928,6 +938,19 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
                        goto bad_rule;
                }
 
+#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,
+                                              SCMP_FLTATR_NEW_LISTENER, 1);
+                       if (ret)
+                               goto bad_rule;
+
+                       conf->has_seccomp_notify = true;
+                       TRACE("Set SCMP_FLTATR_NEW_LISTENER attribute");
+               }
+#endif
+
                if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
                                         conf->seccomp_ctx, &rule))
                        goto bad_rule;
@@ -1230,6 +1253,19 @@ 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 (ret < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+
+               conf->seccomp_notify_fd = ret;
+               TRACE("Retrieved new seccomp listener fd %d", ret);
+       }
+#endif
+
        return 0;
 }
 
@@ -1244,4 +1280,56 @@ void lxc_seccomp_free(struct lxc_conf *conf)
                conf->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;
+#endif
+}
+
+int seccomp_notify_handler(int fd, uint32_t events, void *data,
+                          struct lxc_epoll_descr *descr)
+{
+
+#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+       int ret;
+       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_notify_proxy_msg msg;
+
+       if (listener_proxy_fd < 0)
+               return minus_one_set_errno(EINVAL);
+
+       ret = seccomp_notif_receive(fd, req);
+       if (ret)
+               return minus_one_set_errno(-ret);
+
+       memcpy(&msg.req, req, sizeof(msg.req));
+       msg.monitor_pid = hdlr->monitor_pid;
+       msg.init_pid = hdlr->pid;
+
+       ret = lxc_send_nointr(listener_proxy_fd, &msg, sizeof(msg), MSG_NOSIGNAL);
+       if (ret < 0 || ret != (ssize_t)sizeof(msg))
+               return -1;
+
+       ret = lxc_recv_nointr(listener_proxy_fd, &msg, sizeof(msg), 0);
+       if (ret != (ssize_t)sizeof(msg))
+               return -1;
+
+       memcpy(resp, &msg.resp, sizeof(*resp));
+
+       ret = seccomp_notif_send_resp(fd, resp);
+       if (ret)
+               return minus_one_set_errno(-ret);
+
+       return 0;
+#else
+       return -ENOSYS;
+#endif
 }
index 46a92d3d4695c9bfca2247f1c8646c0783c4d989..b1b4a3af780e81d1614d4803a332e278560d3b4b 100644 (file)
@@ -591,6 +591,20 @@ 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_fd >= 0) {
+               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;
+               }
+       }
+#endif
+
        if (has_console) {
                struct lxc_terminal *console = &handler->conf->console;
 
@@ -1094,6 +1108,9 @@ void lxc_abort(const char *name, struct lxc_handler *handler)
 
 static int do_start(void *data)
 {
+       struct lxc_handler *handler = data;
+       __do_close_prot_errno int data_sock0 = handler->data_sock[0],
+                                 data_sock1 = handler->data_sock[1];
        int ret;
        char path[PATH_MAX];
        uid_t new_uid;
@@ -1102,7 +1119,6 @@ static int do_start(void *data)
        uid_t nsuid = 0;
        gid_t nsgid = 0;
        int devnull_fd = -1;
-       struct lxc_handler *handler = data;
 
        lxc_sync_fini_parent(handler);
 
@@ -1278,8 +1294,6 @@ static int do_start(void *data)
 
        /* Setup the container, ip, names, utsname, ... */
        ret = lxc_setup(handler);
-       close(handler->data_sock[1]);
-       close(handler->data_sock[0]);
        if (ret < 0) {
                ERROR("Failed to setup container \"%s\"", handler->name);
                goto out_warn_father;
@@ -1330,6 +1344,20 @@ 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;
+       }
+#endif
+
        ret = run_lxc_hooks(handler->name, "start", handler->conf, NULL);
        if (ret < 0) {
                ERROR("Failed to run lxc.hook.start for container \"%s\"",
@@ -1592,6 +1620,7 @@ static inline int do_share_ns(void *arg)
  */
 static int lxc_spawn(struct lxc_handler *handler)
 {
+       __do_close_prot_errno int data_sock0 = -EBADF, data_sock1 = -EBADF;
        int i, ret;
        char pidstr[20];
        bool wants_to_map_ids;
@@ -1624,6 +1653,8 @@ static int lxc_spawn(struct lxc_handler *handler)
                         handler->data_sock);
        if (ret < 0)
                goto out_sync_fini;
+       data_sock0 = handler->data_sock[0];
+       data_sock1 = handler->data_sock[1];
 
        ret = resolve_clone_flags(handler);
        if (ret < 0)
@@ -1888,6 +1919,26 @@ 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;
+               }
+       }
+#endif
+
        ret = handler->ops->post_start(handler, handler->data);
        if (ret < 0)
                goto out_abort;
@@ -1980,11 +2031,6 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
                ERROR("Failed to spawn container \"%s\"", name);
                goto out_detach_blockdev;
        }
-       /* close parent side of data socket */
-       close(handler->data_sock[0]);
-       handler->data_sock[0] = -1;
-       close(handler->data_sock[1]);
-       handler->data_sock[1] = -1;
 
        handler->conf->reboot = REBOOT_NONE;