Merge pull request #2947 from brauner/2019-04-18/seccomp_trap

seccomp: SECCOMP_RET_USER_NOTIF support
This commit is contained in:
Stéphane Graber 2019-04-25 18:44:37 -04:00 committed by GitHub
commit a82463a071
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 661 additions and 71 deletions

View File

@ -363,6 +363,7 @@ AM_COND_IF([ENABLE_CAP],
OLD_CFLAGS="$CFLAGS" OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $SECCOMP_CFLAGS" CFLAGS="$CFLAGS $SECCOMP_CFLAGS"
AC_CHECK_TYPES([scmp_filter_ctx], [], [], [[#include <seccomp.h>]]) 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>]]) AC_CHECK_DECLS([seccomp_syscall_resolve_name_arch], [], [], [[#include <seccomp.h>]])
CFLAGS="$OLD_CFLAGS" CFLAGS="$OLD_CFLAGS"

View File

@ -1873,8 +1873,27 @@ dev/null proc/kcore none bind,relative 0 0
2 2
blacklist blacklist
mknod errno 0 mknod errno 0
ioctl notify
</programlisting> </programlisting>
<para>
Specifying "errno" as action will cause LXC to register a seccomp filter
that will cause a specific errno to be returned ot the caller. The errno
value can be specified after the "errno" action word.
</para>
<para>
Specifying "notify" as action will cause LXC to register a seccomp
listener and retrieve a listener file descriptor from the kernel. When a
syscall is made that is registered as "notify" the kernel will generate a
poll event and send a message over the file descriptor. The caller can
read this message, inspect the syscalls including its arguments. Based on
this information the caller is expected to send back a message informing
the kernel which action to take. Until that message is sent the kernel
will block the calling process. The format of the messages to read and
sent is documented in seccomp itself.
</para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term> <term>
@ -1900,6 +1919,20 @@ dev/null proc/kcore none bind,relative 0 0
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>lxc.seccomp.notify.proxy</option>
</term>
<listitem>
<para>
Specify a unix socket to which LXC will connect and forward
seccomp events to. The path must by in the form
unix:/path/to/socket or unix:@socket. The former specifies a
path-bound unix domain socket while the latter specifies an
abstract unix domain socket.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect2> </refsect2>

View File

@ -201,7 +201,8 @@ int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
struct iovec iov; struct iovec iov;
struct cmsghdr *cmsg = NULL; struct cmsghdr *cmsg = NULL;
char buf[1] = {0}; 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(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov)); 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) if (ret <= 0)
goto out; goto out;
cmsg = CMSG_FIRSTHDR(&msg); /*
* 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)); memset(recvfds, -1, num_recvfds * sizeof(int));
if (cmsg && cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) && if (cmsg &&
cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int)); cmsg->cmsg_level == SOL_SOCKET)
memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
break;
}
out: out:
return ret; return ret;
@ -307,3 +316,73 @@ int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size)
out: out:
return ret; return ret;
} }
int lxc_unix_sockaddr(struct sockaddr_un *ret, const char *path)
{
size_t len;
len = strlen(path);
if (len == 0)
return minus_one_set_errno(EINVAL);
if (path[0] != '/' && path[0] != '@')
return minus_one_set_errno(EINVAL);
if (path[1] == '\0')
return minus_one_set_errno(EINVAL);
if (len + 1 > sizeof(ret->sun_path))
return minus_one_set_errno(EINVAL);
*ret = (struct sockaddr_un){
.sun_family = AF_UNIX,
};
if (path[0] == '@') {
memcpy(ret->sun_path + 1, path + 1, len);
return (int)(offsetof(struct sockaddr_un, sun_path) + len);
}
memcpy(ret->sun_path, path, len + 1);
return (int)(offsetof(struct sockaddr_un, sun_path) + len + 1);
}
int lxc_unix_connect(struct sockaddr_un *addr)
{
__do_close_prot_errno int fd = -EBADF;
int ret;
ssize_t len;
fd = socket(PF_UNIX, SOCK_STREAM, SOCK_CLOEXEC);
if (fd < 0)
return -1;
if (addr->sun_path[0] == '\0')
len = strlen(&addr->sun_path[1]);
else
len = strlen(&addr->sun_path[0]);
ret = connect(fd, (struct sockaddr *)&addr,
offsetof(struct sockaddr_un, sun_path) + len + 1);
if (ret < 0)
return -1;
return move_fd(fd);
}
int lxc_socket_set_timeout(int fd, int rcv_timeout, int snd_timeout)
{
struct timeval out = {0};
int ret;
out.tv_sec = snd_timeout;
ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&out,
sizeof(out));
if (ret < 0)
return -1;
out.tv_sec = rcv_timeout;
ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&out,
sizeof(out));
if (ret < 0)
return -1;
return 0;
}

View File

@ -25,6 +25,8 @@
#define __LXC_AF_UNIX_H #define __LXC_AF_UNIX_H
#include <stdio.h> #include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
/* does not enforce \0-termination */ /* does not enforce \0-termination */
extern int lxc_abstract_unix_open(const char *path, int type, int flags); extern int lxc_abstract_unix_open(const char *path, int type, int flags);
@ -37,5 +39,8 @@ extern int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
void *data, size_t size); void *data, size_t size);
extern int lxc_abstract_unix_send_credential(int fd, void *data, size_t size); extern int lxc_abstract_unix_send_credential(int fd, void *data, size_t size);
extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size); extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size);
extern int lxc_unix_sockaddr(struct sockaddr_un *ret, const char *path);
extern int lxc_unix_connect(struct sockaddr_un *addr);
extern int lxc_socket_set_timeout(int fd, int rcv_timeout, int snd_timeout);
#endif /* __LXC_AF_UNIX_H */ #endif /* __LXC_AF_UNIX_H */

View File

@ -43,6 +43,7 @@ static char *api_extensions[] = {
"cgroup_relative", "cgroup_relative",
"mount_injection_file", "mount_injection_file",
"seccomp_allow_nesting", "seccomp_allow_nesting",
"seccomp_notify",
}; };
static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions); static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);

View File

@ -853,11 +853,26 @@ static int attach_child_main(struct attach_clone_payload *payload)
if (init_ctx->container && init_ctx->container->lxc_conf && if (init_ctx->container && init_ctx->container->lxc_conf &&
init_ctx->container->lxc_conf->seccomp) { 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) if (ret < 0)
goto on_error; goto on_error;
TRACE("Loaded seccomp profile"); 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); 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); 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 /* We're done, the child process should now execute whatever it
* is that the user requested. The parent can now track it with * is that the user requested. The parent can now track it with
* waitpid() or similar. * waitpid() or similar.

View File

@ -47,6 +47,7 @@
#include "log.h" #include "log.h"
#include "lxc.h" #include "lxc.h"
#include "lxclock.h" #include "lxclock.h"
#include "lxcseccomp.h"
#include "mainloop.h" #include "mainloop.h"
#include "memory_utils.h" #include "memory_utils.h"
#include "monitor.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_ADD_STATE_CLIENT] = "add_state_client",
[LXC_CMD_CONSOLE_LOG] = "console_log", [LXC_CMD_CONSOLE_LOG] = "console_log",
[LXC_CMD_SERVE_STATE_CLIENTS] = "serve_state_clients", [LXC_CMD_SERVE_STATE_CLIENTS] = "serve_state_clients",
[LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER] = "seccomp_notify_add_listener",
}; };
if (cmd >= LXC_CMD_MAX) 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)) if (ret < 0 || (size_t)ret != sizeof(cmd->req))
return -1; return -1;
if (cmd->req.datalen <= 0) if (cmd->req.cmd == LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER) {
return move_fd(client_fd); 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; errno = EMSGSIZE;
ret = lxc_send_nointr(client_fd, (void *)cmd->req.data, ret = lxc_send_nointr(client_fd, (void *)cmd->req.data,
cmd->req.datalen, MSG_NOSIGNAL); cmd->req.datalen, MSG_NOSIGNAL);
if (ret < 0 || ret != (ssize_t)cmd->req.datalen) if (ret < 0 || ret != (ssize_t)cmd->req.datalen)
return -1; return -1;
}
return move_fd(client_fd); 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, 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; 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, 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) }; 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, 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; const char *path;
struct lxc_cmd_rsp rsp; 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, 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; __do_free char *cidata = NULL;
int cilen; 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, 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) }; 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, 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; struct lxc_cmd_rsp rsp;
int stopsignal = SIGKILL; 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, 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 */ /* should never be called */
return -1; 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, 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; int masterfd, ret;
struct lxc_cmd_rsp rsp; 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, 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; 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, 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; 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, 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; int ret;
struct lxc_cmd_rsp rsp = {0}; 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, 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; struct lxc_cmd_rsp rsp;
uint64_t buffer_size = handler->conf->console.buffer_size; 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, 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; int ret;
lxc_state_t state = PTR_TO_INT(req->data); lxc_state_t state = PTR_TO_INT(req->data);
@ -1025,62 +1047,138 @@ reap_client_fd:
return 1; return 1;
} }
static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath,
struct lxc_handler *handler) int fd,
/* unused */ unsigned int command,
/* unused */ unsigned int flags)
{ {
typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *);
#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_epoll_descr *descr)
{
typedef int (*callback)(int, struct lxc_cmd_req *, struct lxc_handler *,
struct lxc_epoll_descr *);
callback cb[LXC_CMD_MAX] = { callback cb[LXC_CMD_MAX] = {
[LXC_CMD_CONSOLE] = lxc_cmd_console_callback, [LXC_CMD_CONSOLE] = lxc_cmd_console_callback,
[LXC_CMD_TERMINAL_WINCH] = lxc_cmd_terminal_winch_callback, [LXC_CMD_TERMINAL_WINCH] = lxc_cmd_terminal_winch_callback,
[LXC_CMD_STOP] = lxc_cmd_stop_callback, [LXC_CMD_STOP] = lxc_cmd_stop_callback,
[LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback, [LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
[LXC_CMD_GET_INIT_PID] = lxc_cmd_get_init_pid_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_CLONE_FLAGS] = lxc_cmd_get_clone_flags_callback,
[LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback, [LXC_CMD_GET_CGROUP] = lxc_cmd_get_cgroup_callback,
[LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback, [LXC_CMD_GET_CONFIG_ITEM] = lxc_cmd_get_config_item_callback,
[LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback, [LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback,
[LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback, [LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback,
[LXC_CMD_ADD_STATE_CLIENT] = lxc_cmd_add_state_client_callback, [LXC_CMD_ADD_STATE_CLIENT] = lxc_cmd_add_state_client_callback,
[LXC_CMD_CONSOLE_LOG] = lxc_cmd_console_log_callback, [LXC_CMD_CONSOLE_LOG] = lxc_cmd_console_log_callback,
[LXC_CMD_SERVE_STATE_CLIENTS] = lxc_cmd_serve_state_clients_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) { if (req->cmd >= LXC_CMD_MAX) {
ERROR("Undefined command id %d", req->cmd); ERROR("Undefined command id %d", req->cmd);
return -1; 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, static void lxc_cmd_fd_cleanup(int fd, struct lxc_handler *handler,
struct lxc_epoll_descr *descr, struct lxc_epoll_descr *descr, const lxc_cmd_t cmd)
const lxc_cmd_t cmd)
{ {
struct lxc_list *cur, *next; struct lxc_list *cur, *next;
lxc_terminal_free(handler->conf, fd); lxc_terminal_free(handler->conf, fd);
lxc_mainloop_del_handler(descr, 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) { switch (cmd) {
struct lxc_state_client *client = cur->elem; 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) if (client->clientfd != fd)
continue; continue;
/* kick client from list */ /* kick client from list */
lxc_list_del(cur); lxc_list_del(cur);
close(client->clientfd); close(client->clientfd);
free(cur->elem); free(cur->elem);
free(cur); free(cur);
/* No need to walk the whole list. If we found the state client /* No need to walk the whole list. If we found the state
* fd there can't be a second one. * client fd there can't be a second one.
*/ */
break;
}
break; break;
default:
close(fd);
} }
} }
@ -1139,7 +1237,7 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
req.data = reqdata; req.data = reqdata;
} }
ret = lxc_cmd_process(fd, &req, handler); ret = lxc_cmd_process(fd, &req, handler, descr);
if (ret) { if (ret) {
/* This is not an error, but only a request to close fd. */ /* This is not an error, but only a request to close fd. */
ret = LXC_MAINLOOP_CONTINUE; ret = LXC_MAINLOOP_CONTINUE;

View File

@ -46,6 +46,7 @@ typedef enum {
LXC_CMD_ADD_STATE_CLIENT, LXC_CMD_ADD_STATE_CLIENT,
LXC_CMD_CONSOLE_LOG, LXC_CMD_CONSOLE_LOG,
LXC_CMD_SERVE_STATE_CLIENTS, LXC_CMD_SERVE_STATE_CLIENTS,
LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER,
LXC_CMD_MAX, LXC_CMD_MAX,
} lxc_cmd_t; } 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_try_cmd(const char *name, const char *lxcpath);
extern int lxc_cmd_console_log(const char *name, const char *lxcpath, extern int lxc_cmd_console_log(const char *name, const char *lxcpath,
struct lxc_console_log *log); 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 */ #endif /* __commands_h */

View File

@ -2752,6 +2752,14 @@ struct lxc_conf *lxc_conf_init(void)
new->lsm_aa_profile = NULL; new->lsm_aa_profile = NULL;
lxc_list_init(&new->lsm_aa_raw); lxc_list_init(&new->lsm_aa_raw);
new->lsm_se_context = NULL; 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 = false;
new->tmp_umount_proc = 0; new->tmp_umount_proc = 0;
new->shmount.path_host = NULL; new->shmount.path_host = NULL;

View File

@ -299,6 +299,14 @@ struct lxc_conf {
unsigned int seccomp_allow_nesting; unsigned int seccomp_allow_nesting;
#if HAVE_SCMP_FILTER_CTX #if HAVE_SCMP_FILTER_CTX
scmp_filter_ctx seccomp_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 #endif
int maincmd_fd; int maincmd_fd;
unsigned int autodev; /* if 1, mount and fill a /dev at start */ unsigned int autodev; /* if 1, mount and fill a /dev at start */

View File

@ -46,6 +46,7 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "af_unix.h"
#include "conf.h" #include "conf.h"
#include "config.h" #include "config.h"
#include "confile.h" #include "confile.h"
@ -147,6 +148,7 @@ lxc_config_define(rootfs_options);
lxc_config_define(rootfs_path); lxc_config_define(rootfs_path);
lxc_config_define(seccomp_profile); lxc_config_define(seccomp_profile);
lxc_config_define(seccomp_allow_nesting); lxc_config_define(seccomp_allow_nesting);
lxc_config_define(seccomp_notify_proxy);
lxc_config_define(selinux_context); lxc_config_define(selinux_context);
lxc_config_define(signal_halt); lxc_config_define(signal_halt);
lxc_config_define(signal_reboot); lxc_config_define(signal_reboot);
@ -234,6 +236,7 @@ static struct lxc_config_t config_jump_table[] = {
{ "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, }, { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
{ "lxc.rootfs.path", set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, }, { "lxc.rootfs.path", set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
{ "lxc.seccomp.allow_nesting", set_config_seccomp_allow_nesting, get_config_seccomp_allow_nesting, clr_config_seccomp_allow_nesting, }, { "lxc.seccomp.allow_nesting", set_config_seccomp_allow_nesting, get_config_seccomp_allow_nesting, clr_config_seccomp_allow_nesting, },
{ "lxc.seccomp.notify.proxy", set_config_seccomp_notify_proxy, get_config_seccomp_notify_proxy, clr_config_seccomp_notify_proxy, },
{ "lxc.seccomp.profile", set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, }, { "lxc.seccomp.profile", set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
{ "lxc.selinux.context", set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, }, { "lxc.selinux.context", set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
{ "lxc.signal.halt", set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, }, { "lxc.signal.halt", set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
@ -784,9 +787,31 @@ static int set_config_seccomp_allow_nesting(const char *key, const char *value,
return -1; return -1;
if (lxc_conf->seccomp_allow_nesting > 1) if (lxc_conf->seccomp_allow_nesting > 1)
return minus_one_set_errno(EINVAL);
return 0;
}
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
const char *offset;
if (lxc_config_value_empty(value))
return clr_config_seccomp_notify_proxy(key, lxc_conf, NULL);
if (strncmp(value, "unix:", 5) != 0)
return minus_one_set_errno(EINVAL);
offset = value + 5;
if (lxc_unix_sockaddr(&lxc_conf->seccomp_notify_proxy_addr, offset) < 0)
return -1; return -1;
return 0; return 0;
#else
return minus_one_set_errno(ENOSYS);
#endif
} }
static int set_config_seccomp_profile(const char *key, const char *value, static int set_config_seccomp_profile(const char *key, const char *value,
@ -3704,6 +3729,19 @@ static int get_config_seccomp_allow_nesting(const char *key, char *retv,
return lxc_get_conf_int(c, retv, inlen, c->seccomp_allow_nesting); return lxc_get_conf_int(c, retv, inlen, c->seccomp_allow_nesting);
} }
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
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]);
#else
return minus_one_set_errno(ENOSYS);
#endif
}
static int get_config_seccomp_profile(const char *key, char *retv, int inlen, static int get_config_seccomp_profile(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data) struct lxc_conf *c, void *data)
{ {
@ -4294,6 +4332,18 @@ static inline int clr_config_seccomp_allow_nesting(const char *key,
return 0; return 0;
} }
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));
return 0;
#else
return minus_one_set_errno(ENOSYS);
#endif
}
static inline int clr_config_seccomp_profile(const char *key, static inline int clr_config_seccomp_profile(const char *key,
struct lxc_conf *c, void *data) struct lxc_conf *c, void *data)
{ {

View File

@ -5227,6 +5227,28 @@ out:
return ret; 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 *lxc_container_new(const char *name, const char *configpath)
{ {
struct lxc_container *c; 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->console_log = lxcapi_console_log;
c->mount = lxcapi_mount; c->mount = lxcapi_mount;
c->umount = lxcapi_umount; c->umount = lxcapi_umount;
c->seccomp_notify = lxcapi_seccomp_notify;
return c; return c;

View File

@ -31,6 +31,10 @@
#include <lxc/attach_options.h> #include <lxc/attach_options.h>
#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
#include <seccomp.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -60,6 +64,21 @@ struct lxc_mount {
int version; 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. * An LXC container.
* *
@ -867,6 +886,8 @@ struct lxc_container {
*/ */
int (*umount)(struct lxc_container *c, const char *target, int (*umount)(struct lxc_container *c, const char *target,
unsigned long mountflags, struct lxc_mount *mnt); unsigned long mountflags, struct lxc_mount *mnt);
int (*seccomp_notify)(struct lxc_container *c, unsigned int cmd, int fd);
}; };
/*! /*!

View File

@ -24,12 +24,20 @@
#ifndef __LXC_LXCSECCOMP_H #ifndef __LXC_LXCSECCOMP_H
#define __LXC_LXCSECCOMP_H #define __LXC_LXCSECCOMP_H
#include <errno.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
#include "conf.h" #include "conf.h"
#ifdef HAVE_SECCOMP #ifdef HAVE_SECCOMP
extern int lxc_seccomp_load(struct lxc_conf *conf); extern int lxc_seccomp_load(struct lxc_conf *conf);
extern int lxc_read_seccomp_config(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_conf *conf);
extern int seccomp_notify_handler(int fd, uint32_t events, void *data,
struct lxc_epoll_descr *descr);
#else #else
static inline int lxc_seccomp_load(struct lxc_conf *conf) 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); free(conf->seccomp);
conf->seccomp = NULL; 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
#endif #endif

View File

@ -407,4 +407,10 @@ enum {
__internal_fd__; \ __internal_fd__; \
}) })
#define minus_one_set_errno(__errno__) \
({ \
errno = __errno__; \
-1; \
})
#endif /* __LXC_MACRO_H */ #endif /* __LXC_MACRO_H */

View File

@ -31,9 +31,12 @@
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include "af_unix.h"
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
#include "lxccontainer.h"
#include "lxcseccomp.h" #include "lxcseccomp.h"
#include "memory_utils.h"
#include "utils.h" #include "utils.h"
#ifdef __MIPSEL__ #ifdef __MIPSEL__
@ -87,6 +90,10 @@ static const char *get_action_name(uint32_t action)
return "trap"; return "trap";
case SCMP_ACT_ERRNO(0): case SCMP_ACT_ERRNO(0):
return "errno"; return "errno";
#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
case SCMP_ACT_USER_NOTIF:
return "notify";
#endif
} }
return "invalid action"; return "invalid action";
@ -116,6 +123,10 @@ static uint32_t get_v2_default_action(char *line)
ret_action = SCMP_ACT_ALLOW; ret_action = SCMP_ACT_ALLOW;
} else if (strncmp(line, "trap", 4) == 0) { } else if (strncmp(line, "trap", 4) == 0) {
ret_action = SCMP_ACT_TRAP; 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]) { } else if (line[0]) {
ERROR("Unrecognized seccomp action \"%s\"", line); ERROR("Unrecognized seccomp action \"%s\"", line);
return -2; return -2;
@ -928,6 +939,19 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
goto bad_rule; 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, if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
conf->seccomp_ctx, &rule)) conf->seccomp_ctx, &rule))
goto bad_rule; goto bad_rule;
@ -1230,6 +1254,19 @@ int lxc_seccomp_load(struct lxc_conf *conf)
} }
#endif #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; return 0;
} }
@ -1244,4 +1281,112 @@ void lxc_seccomp_free(struct lxc_conf *conf)
conf->seccomp_ctx = NULL; conf->seccomp_ctx = NULL;
} }
#endif #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
}
#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
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);
notify_fd = lxc_unix_connect(&handler->conf->seccomp_notify_proxy_addr);
if (notify_fd < 0) {
SYSERROR("Failed to reconnect to seccomp proxy");
return -1;
}
/* 30 second timeout */
if (lxc_socket_set_timeout(notify_fd, 30, 30)) {
SYSERROR("Failed to set socket timeout");
return -1;
}
handler->conf->seccomp_notify_proxy_fd = move_fd(notify_fd);
return 0;
}
#endif
#if HAVE_DECL_SECCOMP_NOTIF_GET_FD
static int seccomp_notify_default_answer(int fd, struct seccomp_notif *req,
struct seccomp_notif_resp *resp,
struct lxc_handler *handler)
{
resp->id = req->id;
resp->error = -ENOSYS;
if (seccomp_notif_send_resp(fd, resp))
SYSERROR("Failed to send default message to seccomp");
return seccomp_notify_reconnect(handler);
}
#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 reconnect_count, ret;
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_notify_proxy_msg msg;
if (listener_proxy_fd < 0) {
ERROR("No seccomp proxy registered");
return minus_one_set_errno(EINVAL);
}
ret = seccomp_notif_receive(fd, req);
if (ret) {
SYSERROR("Failed to read seccomp notification");
goto out;
}
memcpy(&msg.req, req, sizeof(msg.req));
msg.monitor_pid = hdlr->monitor_pid;
msg.init_pid = hdlr->pid;
reconnect_count = 0;
do {
bytes = lxc_send_nointr(listener_proxy_fd, &msg, sizeof(msg),
MSG_NOSIGNAL);
if (bytes != (ssize_t)sizeof(msg)) {
SYSERROR("Failed to forward message to seccomp proxy");
if (seccomp_notify_default_answer(fd, req, resp, hdlr))
goto out;
}
} while (reconnect_count++);
reconnect_count = 0;
do {
bytes = lxc_recv_nointr(listener_proxy_fd, &msg, sizeof(msg), 0);
if (bytes != (ssize_t)sizeof(msg)) {
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_notif_send_resp(fd, resp);
if (ret)
SYSERROR("Failed to send seccomp notification");
out:
return 0;
#else
return -ENOSYS;
#endif
} }

View File

@ -591,6 +591,33 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
goto out_mainloop_console; 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
if (has_console) { if (has_console) {
struct lxc_terminal *console = &handler->conf->console; struct lxc_terminal *console = &handler->conf->console;
@ -1094,6 +1121,9 @@ void lxc_abort(const char *name, struct lxc_handler *handler)
static int do_start(void *data) static int do_start(void *data)
{ {
struct lxc_handler *handler = data;
ATTR_UNUSED __do_close_prot_errno int data_sock0 = handler->data_sock[0],
data_sock1 = handler->data_sock[1];
int ret; int ret;
char path[PATH_MAX]; char path[PATH_MAX];
uid_t new_uid; uid_t new_uid;
@ -1102,7 +1132,6 @@ static int do_start(void *data)
uid_t nsuid = 0; uid_t nsuid = 0;
gid_t nsgid = 0; gid_t nsgid = 0;
int devnull_fd = -1; int devnull_fd = -1;
struct lxc_handler *handler = data;
lxc_sync_fini_parent(handler); lxc_sync_fini_parent(handler);
@ -1278,8 +1307,6 @@ static int do_start(void *data)
/* Setup the container, ip, names, utsname, ... */ /* Setup the container, ip, names, utsname, ... */
ret = lxc_setup(handler); ret = lxc_setup(handler);
close(handler->data_sock[1]);
close(handler->data_sock[0]);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to setup container \"%s\"", handler->name); ERROR("Failed to setup container \"%s\"", handler->name);
goto out_warn_father; goto out_warn_father;
@ -1330,6 +1357,20 @@ static int do_start(void *data)
if (ret < 0) if (ret < 0)
goto out_warn_father; 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); ret = run_lxc_hooks(handler->name, "start", handler->conf, NULL);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to run lxc.hook.start for container \"%s\"", ERROR("Failed to run lxc.hook.start for container \"%s\"",
@ -1592,6 +1633,7 @@ static inline int do_share_ns(void *arg)
*/ */
static int lxc_spawn(struct lxc_handler *handler) static int lxc_spawn(struct lxc_handler *handler)
{ {
__do_close_prot_errno int data_sock0 = -EBADF, data_sock1 = -EBADF;
int i, ret; int i, ret;
char pidstr[20]; char pidstr[20];
bool wants_to_map_ids; bool wants_to_map_ids;
@ -1624,6 +1666,8 @@ static int lxc_spawn(struct lxc_handler *handler)
handler->data_sock); handler->data_sock);
if (ret < 0) if (ret < 0)
goto out_sync_fini; goto out_sync_fini;
data_sock0 = handler->data_sock[0];
data_sock1 = handler->data_sock[1];
ret = resolve_clone_flags(handler); ret = resolve_clone_flags(handler);
if (ret < 0) if (ret < 0)
@ -1888,6 +1932,26 @@ static int lxc_spawn(struct lxc_handler *handler)
goto out_delete_net; 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); ret = handler->ops->post_start(handler, handler->data);
if (ret < 0) if (ret < 0)
goto out_abort; goto out_abort;
@ -1980,11 +2044,6 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
ERROR("Failed to spawn container \"%s\"", name); ERROR("Failed to spawn container \"%s\"", name);
goto out_detach_blockdev; 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; handler->conf->reboot = REBOOT_NONE;