Unverified Commit cca31bf0 by Stéphane Graber Committed by GitHub

Merge pull request #3697 from brauner/2021-02-25/fixes

commands: improvements and fixes
parents 2be31fed 885bb002
...@@ -113,7 +113,7 @@ int lxc_abstract_unix_connect(const char *path) ...@@ -113,7 +113,7 @@ int lxc_abstract_unix_connect(const char *path)
} }
int lxc_abstract_unix_send_fds_iov(int fd, const int *sendfds, int num_sendfds, int lxc_abstract_unix_send_fds_iov(int fd, const int *sendfds, int num_sendfds,
struct iovec *iov, size_t iovlen) struct iovec *const iov, size_t iovlen)
{ {
__do_free char *cmsgbuf = NULL; __do_free char *cmsgbuf = NULL;
int ret; int ret;
...@@ -176,6 +176,12 @@ static ssize_t lxc_abstract_unix_recv_fds_iov(int fd, ...@@ -176,6 +176,12 @@ static ssize_t lxc_abstract_unix_recv_fds_iov(int fd,
size_t cmsgbufsize = CMSG_SPACE(sizeof(struct ucred)) + size_t cmsgbufsize = CMSG_SPACE(sizeof(struct ucred)) +
CMSG_SPACE(ret_fds->fd_count_max * sizeof(int)); CMSG_SPACE(ret_fds->fd_count_max * sizeof(int));
if (ret_fds->flags & ~UNIX_FDS_ACCEPT_MASK)
return ret_errno(EINVAL);
if (hweight32((ret_fds->flags & ~UNIX_FDS_ACCEPT_NONE)) > 1)
return ret_errno(EINVAL);
cmsgbuf = zalloc(cmsgbufsize); cmsgbuf = zalloc(cmsgbufsize);
if (!cmsgbuf) if (!cmsgbuf)
return ret_errno(ENOMEM); return ret_errno(ENOMEM);
...@@ -202,7 +208,7 @@ again: ...@@ -202,7 +208,7 @@ again:
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
__u32 idx; __u32 idx;
/* /*
* This causes some compilers to complaing about * This causes some compilers to complain about
* increased alignment requirements but I haven't found * increased alignment requirements but I haven't found
* a better way to deal with this yet. Suggestions * a better way to deal with this yet. Suggestions
* welcome! * welcome!
...@@ -225,7 +231,22 @@ again: ...@@ -225,7 +231,22 @@ again:
return syserrno_set(-EFBIG, "Received excessive number of file descriptors"); return syserrno_set(-EFBIG, "Received excessive number of file descriptors");
} }
if (msg.msg_flags & MSG_CTRUNC) {
for (idx = 0; idx < num_raw; idx++)
close(fds_raw[idx]);
return syserrno_set(-EFBIG, "Control message was truncated; closing all fds and rejecting incomplete message");
}
if (ret_fds->fd_count_max > num_raw) { if (ret_fds->fd_count_max > num_raw) {
if (!(ret_fds->flags & UNIX_FDS_ACCEPT_LESS)) {
for (idx = 0; idx < num_raw; idx++)
close(fds_raw[idx]);
return syserrno_set(-EINVAL, "Received fewer file descriptors than we expected %u != %u",
ret_fds->fd_count_max, num_raw);
}
/* /*
* Make sure any excess entries in the fd array * Make sure any excess entries in the fd array
* are set to -EBADF so our cleanup functions * are set to -EBADF so our cleanup functions
...@@ -234,16 +255,33 @@ again: ...@@ -234,16 +255,33 @@ again:
for (idx = num_raw; idx < ret_fds->fd_count_max; idx++) for (idx = num_raw; idx < ret_fds->fd_count_max; idx++)
ret_fds->fd[idx] = -EBADF; ret_fds->fd[idx] = -EBADF;
WARN("Received fewer file descriptors than we expected %u != %u", ret_fds->fd_count_max, num_raw); ret_fds->flags |= UNIX_FDS_RECEIVED_LESS;
} else if (ret_fds->fd_count_max < num_raw) { } else if (ret_fds->fd_count_max < num_raw) {
if (!(ret_fds->flags & UNIX_FDS_ACCEPT_MORE)) {
for (idx = 0; idx < num_raw; idx++)
close(fds_raw[idx]);
return syserrno_set(-EINVAL, "Received more file descriptors than we expected %u != %u",
ret_fds->fd_count_max, num_raw);
}
/* Make sure we close any excess fds we received. */ /* Make sure we close any excess fds we received. */
for (idx = ret_fds->fd_count_max; idx < num_raw; idx++) for (idx = ret_fds->fd_count_max; idx < num_raw; idx++)
close(fds_raw[idx]); close(fds_raw[idx]);
WARN("Received more file descriptors than we expected %u != %u", ret_fds->fd_count_max, num_raw);
/* Cap the number of received file descriptors. */ /* Cap the number of received file descriptors. */
num_raw = ret_fds->fd_count_max; num_raw = ret_fds->fd_count_max;
ret_fds->flags |= UNIX_FDS_RECEIVED_MORE;
} else {
ret_fds->flags |= UNIX_FDS_RECEIVED_EXACT;
}
if (hweight32((ret_fds->flags & ~UNIX_FDS_ACCEPT_MASK)) > 1) {
for (idx = 0; idx < num_raw; idx++)
close(fds_raw[idx]);
return syserrno_set(-EINVAL, "Invalid flag combination; closing to not risk leaking fds %u != %u",
ret_fds->fd_count_max, num_raw);
} }
memcpy(ret_fds->fd, CMSG_DATA(cmsg), num_raw * sizeof(int)); memcpy(ret_fds->fd, CMSG_DATA(cmsg), num_raw * sizeof(int));
...@@ -252,6 +290,15 @@ again: ...@@ -252,6 +290,15 @@ again:
} }
} }
if (ret_fds->fd_count_ret == 0) {
ret_fds->flags |= UNIX_FDS_RECEIVED_NONE;
/* We expected to receive file descriptors. */
if ((ret_fds->flags & UNIX_FDS_ACCEPT_MASK) &&
!(ret_fds->flags & UNIX_FDS_ACCEPT_NONE))
return syserrno_set(-EINVAL, "Received no file descriptors");
}
return ret; return ret;
} }
......
...@@ -12,15 +12,88 @@ ...@@ -12,15 +12,88 @@
#include "macro.h" #include "macro.h"
#include "memory_utils.h" #include "memory_utils.h"
#define KERNEL_SCM_MAX_FD 253
/* Allow the caller to set expectations. */
/*
* UNIX_FDS_ACCEPT_EXACT will only succeed if the exact amount of fds has been
* received (unless combined with UNIX_FDS_ACCEPT_NONE).
*/
#define UNIX_FDS_ACCEPT_EXACT ((__u32)(1 << 0)) /* default */
/*
* UNIX_FDS_ACCEPT_LESS will also succeed if less than the requested number of
* fd has been received. If the UNIX_FDS_ACCEPT_NONE flag is not raised than at
* least one fd must be received.
* */
#define UNIX_FDS_ACCEPT_LESS ((__u32)(1 << 1))
/*
* UNIX_FDS_ACCEPT_MORE will also succeed if more than the requested number of
* fds have been received. Any additional fds will be silently closed. If the
* UNIX_FDS_ACCEPT_NONE flag is not raised than at least one fd must be
* received.
*/
#define UNIX_FDS_ACCEPT_MORE ((__u32)(1 << 2)) /* wipe any extra fds */
/* /*
* Technically 253 is the kernel limit but we want to the struct to be a * UNIX_FDS_ACCEPT_NONE can be specified with any of the above flags and
* multiple of 8. * indicates that the caller will accept no file descriptors to be received.
*/ */
#define KERNEL_SCM_MAX_FD 252 #define UNIX_FDS_ACCEPT_NONE ((__u32)(1 << 3))
/* UNIX_FDS_ACCEPT_MASK is the value of all the above flags or-ed together. */
#define UNIX_FDS_ACCEPT_MASK (UNIX_FDS_ACCEPT_EXACT | UNIX_FDS_ACCEPT_LESS | UNIX_FDS_ACCEPT_MORE | UNIX_FDS_ACCEPT_NONE)
/* Allow the callee to communicate reality. */
/* UNIX_FDS_RECEIVED_EXACT indicates that the exact number of fds was received. */
#define UNIX_FDS_RECEIVED_EXACT ((__u32)(1 << 16))
/*
* UNIX_FDS_RECEIVED_LESS indicates that less than the requested number of fd
* has been received.
*/
#define UNIX_FDS_RECEIVED_LESS ((__u32)(1 << 17))
/*
* UNIX_FDS_RECEIVED_MORE indicates that more than the requested number of fd
* has been received.
*/
#define UNIX_FDS_RECEIVED_MORE ((__u32)(1 << 18))
/* UNIX_FDS_RECEIVED_NONE indicates that no fds have been received. */
#define UNIX_FDS_RECEIVED_NONE ((__u32)(1 << 19))
/**
* Defines a generic struct to receive file descriptors from unix sockets.
* @fd_count_max : Either the exact or maximum number of file descriptors the
* caller is willing to accept. Must be smaller than
* KERNEL_SCM_MAX_FDs; larger values will be rejected.
* Filled in by the caller.
* @fd_count_ret : The actually received number of file descriptors.
* Filled in by the callee.
* @flags : Flags to negotiate expectations about the number of file
* descriptors to receive.
* Filled in by the caller and callee. The caller's flag space
* is UNIX_FDS_ACCEPT_* other values will be rejected. The
* caller may only set one of {EXACT, LESS, MORE}. In addition
* they can raise the NONE flag. Any combination of {EXACT,
* LESS, MORE} will be rejected.
* The callee's flag space is UNIX_FDS_RECEIVED_*. Only ever
* one of those values will be set.
* @fd : Array to store received file descriptors into. Filled by the
* callee on success. If less file descriptors are received
* than requested in @fd_count_max the callee will ensure that
* all additional slots will be set to -EBADF. Nonetheless, the
* caller should only ever use @fd_count_ret to iterate through
* @fd after a successful receive.
*/
struct unix_fds { struct unix_fds {
__u32 fd_count_max; __u32 fd_count_max;
__u32 fd_count_ret; __u32 fd_count_ret;
__u32 flags;
__s32 fd[KERNEL_SCM_MAX_FD]; __s32 fd[KERNEL_SCM_MAX_FD];
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
......
...@@ -118,6 +118,38 @@ static int __transfer_cgroup_fd(struct unix_fds *fds, struct cgroup_fd *fd) ...@@ -118,6 +118,38 @@ static int __transfer_cgroup_fd(struct unix_fds *fds, struct cgroup_fd *fd)
return 0; return 0;
} }
static ssize_t lxc_cmd_rsp_recv_fds(int fd_sock, struct unix_fds *fds,
struct lxc_cmd_rsp *rsp,
const char *cur_cmdstr)
{
ssize_t ret;
ret = lxc_abstract_unix_recv_fds(fd_sock, fds, rsp, sizeof(*rsp));
if (ret < 0)
return ret;
/*
* If we end up here with fewer or more file descriptors the caller
* must have set flags to indicate that they are fine with this.
* Otherwise the call would have failed.
*/
if (fds->flags & UNIX_FDS_RECEIVED_EXACT)
return log_info(ret, "Received exact number of file descriptors %u == %u",
fds->fd_count_max, fds->fd_count_ret);
if (fds->flags & UNIX_FDS_RECEIVED_LESS)
return log_info(ret, "Received less file descriptors %u < %u",
fds->fd_count_ret, fds->fd_count_max);
if (fds->flags & UNIX_FDS_RECEIVED_MORE)
return log_info(ret, "Received more file descriptors (excessive fds were automatically closed) %u > %u",
fds->fd_count_ret, fds->fd_count_max);
INFO("Command \"%s\" received response", cur_cmdstr);
return ret;
}
/* /*
* lxc_cmd_rsp_recv: Receive a response to a command * lxc_cmd_rsp_recv: Receive a response to a command
* *
...@@ -134,15 +166,17 @@ static int __transfer_cgroup_fd(struct unix_fds *fds, struct cgroup_fd *fd) ...@@ -134,15 +166,17 @@ static int __transfer_cgroup_fd(struct unix_fds *fds, struct cgroup_fd *fd)
* As a special case, the response for LXC_CMD_GET_TTY_FD is created here as * As a special case, the response for LXC_CMD_GET_TTY_FD is created here as
* it contains an fd for the ptx pty passed through the unix socket. * it contains an fd for the ptx pty passed through the unix socket.
*/ */
static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) static ssize_t lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
{ {
__do_free void *__private_ptr = NULL; __do_free void *__private_ptr = NULL;
struct lxc_cmd_tty_rsp_data *data_console = NULL; struct lxc_cmd_tty_rsp_data *data_console = NULL;
call_cleaner(put_unix_fds) struct unix_fds *fds = &(struct unix_fds){}; call_cleaner(put_unix_fds) struct unix_fds *fds = &(struct unix_fds){
.fd[0 ... KERNEL_SCM_MAX_FD - 1] = -EBADF,
};
struct lxc_cmd_rsp *rsp = &cmd->rsp; struct lxc_cmd_rsp *rsp = &cmd->rsp;
int cur_cmd = cmd->req.cmd, fret = 0; int cur_cmd = cmd->req.cmd;
const char *cur_cmdstr; const char *cur_cmdstr;
int ret; ssize_t bytes_recv;
/* /*
* Determine whether this command will receive file descriptors and how * Determine whether this command will receive file descriptors and how
...@@ -163,12 +197,24 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -163,12 +197,24 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
case LXC_CMD_GET_SECCOMP_NOTIFY_FD: case LXC_CMD_GET_SECCOMP_NOTIFY_FD:
__fallthrough; __fallthrough;
case LXC_CMD_GET_DEVPTS_FD: case LXC_CMD_GET_DEVPTS_FD:
__fallthrough; fds->fd_count_max = 1;
/*
* The kernel might not support the required features or the
* server might be too old.
*/
fds->flags = UNIX_FDS_ACCEPT_EXACT | UNIX_FDS_ACCEPT_NONE;
break;
case LXC_CMD_GET_TTY_FD: case LXC_CMD_GET_TTY_FD:
/*
* The requested terminal can be busy so it's perfectly fine
* for LXC_CMD_GET_TTY to receive no file descriptor.
*/
fds->fd_count_max = 1; fds->fd_count_max = 1;
fds->flags = UNIX_FDS_ACCEPT_EXACT | UNIX_FDS_ACCEPT_NONE;
break; break;
case LXC_CMD_GET_CGROUP_CTX: case LXC_CMD_GET_CGROUP_CTX:
fds->fd_count_max = CGROUP_CTX_MAX_FD; fds->fd_count_max = CGROUP_CTX_MAX_FD;
fds->flags |= UNIX_FDS_ACCEPT_LESS;
break; break;
default: default:
fds->fd_count_max = 0; fds->fd_count_max = 0;
...@@ -176,22 +222,9 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -176,22 +222,9 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
} }
/* Receive the first response including file descriptors if any. */ /* Receive the first response including file descriptors if any. */
ret = lxc_abstract_unix_recv_fds(sock, fds, rsp, sizeof(*rsp)); bytes_recv = lxc_cmd_rsp_recv_fds(sock, fds, rsp, cur_cmdstr);
if (ret < 0) if (bytes_recv < 0)
return syserrno(ret, "Failed to receive response for command \"%s\"", cur_cmdstr); return bytes_recv;
/*
* Verify that we actually received any file descriptors if the command
* expects to do so.
*/
if (fds->fd_count_max == 0) {
WARN("Command \"%s\" received response", cur_cmdstr);
} else if (fds->fd_count_ret == 0) {
TRACE("Command \"%s\" received response without any of the expected %u file descriptors", cur_cmdstr, fds->fd_count_max);
fret = -EBADF;
} else {
TRACE("Command \"%s\" received response with %u of %u expected file descriptors", cur_cmdstr, fds->fd_count_ret, fds->fd_count_max);
}
/* /*
* Ensure that no excessive data is sent unless someone retrieves the * Ensure that no excessive data is sent unless someone retrieves the
...@@ -199,7 +232,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -199,7 +232,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
*/ */
if ((rsp->datalen > LXC_CMD_DATA_MAX) && if ((rsp->datalen > LXC_CMD_DATA_MAX) &&
(cur_cmd != LXC_CMD_CONSOLE_LOG)) (cur_cmd != LXC_CMD_CONSOLE_LOG))
return syserrno_set(fret ?: -E2BIG, "Response data for command \"%s\" is too long: %d bytes > %d", return syserrno_set(-E2BIG, "Response data for command \"%s\" is too long: %d bytes > %d",
cur_cmdstr, rsp->datalen, LXC_CMD_DATA_MAX); cur_cmdstr, rsp->datalen, LXC_CMD_DATA_MAX);
/* /*
...@@ -216,23 +249,20 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -216,23 +249,20 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
case LXC_CMD_GET_DEVPTS_FD: /* no data */ case LXC_CMD_GET_DEVPTS_FD: /* no data */
__fallthrough; __fallthrough;
case LXC_CMD_GET_SECCOMP_NOTIFY_FD: /* no data */ case LXC_CMD_GET_SECCOMP_NOTIFY_FD: /* no data */
if (!fret)
rsp->data = INT_TO_PTR(move_fd(fds->fd[0])); rsp->data = INT_TO_PTR(move_fd(fds->fd[0]));
return log_debug(0, "Finished processing \"%s\" with file descriptor %d", cur_cmdstr, PTR_TO_INT(rsp->data));
/* Return for any command that doesn't expect additional data. */
return log_debug(fret ?: ret, "Finished processing \"%s\" with file descriptor %d", cur_cmdstr, PTR_TO_INT(rsp->data));
case LXC_CMD_GET_CGROUP_FD: /* data */ case LXC_CMD_GET_CGROUP_FD: /* data */
__fallthrough; __fallthrough;
case LXC_CMD_GET_LIMIT_CGROUP_FD: /* data */ case LXC_CMD_GET_LIMIT_CGROUP_FD: /* data */
if (rsp->datalen > sizeof(struct cgroup_fd)) if (rsp->datalen > sizeof(struct cgroup_fd))
return syserrno_set(fret ?: -EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr); return syserrno_set(-EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr);
/* Don't pointlessly allocate. */ /* Don't pointlessly allocate. */
rsp->data = (void *)cmd->req.data; rsp->data = (void *)cmd->req.data;
break; break;
case LXC_CMD_GET_CGROUP_CTX: /* data */ case LXC_CMD_GET_CGROUP_CTX: /* data */
if (rsp->datalen > sizeof(struct cgroup_ctx)) if (rsp->datalen > sizeof(struct cgroup_ctx))
return syserrno_set(fret ?: -EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr); return syserrno_set(-EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr);
/* Don't pointlessly allocate. */ /* Don't pointlessly allocate. */
rsp->data = (void *)cmd->req.data; rsp->data = (void *)cmd->req.data;
...@@ -240,14 +270,14 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -240,14 +270,14 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
case LXC_CMD_GET_TTY_FD: /* data */ case LXC_CMD_GET_TTY_FD: /* data */
/* /*
* recv() returns 0 bytes when a tty cannot be allocated, * recv() returns 0 bytes when a tty cannot be allocated,
* rsp->ret is < 0 when the peer permission check failed * rsp->ret is < 0 when the peer permission check failed.
*/ */
if (ret == 0 || rsp->ret < 0) if (bytes_recv == 0 || rsp->ret < 0)
return 0; return 0;
__private_ptr = malloc(sizeof(struct lxc_cmd_tty_rsp_data)); __private_ptr = malloc(sizeof(struct lxc_cmd_tty_rsp_data));
if (!__private_ptr) if (!__private_ptr)
return syserrno_set(fret ?: -ENOMEM, "Failed to receive response for command \"%s\"", cur_cmdstr); return syserrno_set(-ENOMEM, "Failed to receive response for command \"%s\"", cur_cmdstr);
data_console = (struct lxc_cmd_tty_rsp_data *)__private_ptr; data_console = (struct lxc_cmd_tty_rsp_data *)__private_ptr;
data_console->ptxfd = move_fd(fds->fd[0]); data_console->ptxfd = move_fd(fds->fd[0]);
data_console->ttynum = PTR_TO_INT(rsp->data); data_console->ttynum = PTR_TO_INT(rsp->data);
...@@ -267,48 +297,40 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -267,48 +297,40 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
break; break;
} }
if (rsp->datalen == 0) { if (rsp->datalen > 0) {
DEBUG("Command \"%s\" requested no additional data", cur_cmdstr); int err;
/*
* Note that LXC_CMD_GET_TTY_FD historically allocates memory
* to return info to the caller. That's why we jump to no_data
* so we ensure that the allocated data is wiped if we return
* early here.
*/
goto no_data;
}
/* /*
* All commands ending up here expect data so rsp->data must be valid. * All commands ending up here expect data so rsp->data must be valid.
* Either static or allocated memory. * Either static or allocated memory.
*/ */
if (!rsp->data) if (!rsp->data)
return syserrno_set(fret ?: -ENOMEM, "Failed to prepare response buffer for command \"%s\"", cur_cmdstr); return syserrno_set(-ENOMEM, "Failed to prepare response buffer for command \"%s\"",
cur_cmdstr);
ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0); bytes_recv = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0);
if (ret != rsp->datalen) if (bytes_recv != rsp->datalen)
return syserrno(-errno, "Failed to receive response data for command \"%s\": %d != %d", cur_cmdstr, ret, rsp->datalen); return syserrno(-errno, "Failed to receive response data for command \"%s\": %zd != %d",
cur_cmdstr, bytes_recv, rsp->datalen);
switch (cur_cmd) { switch (cur_cmd) {
case LXC_CMD_GET_CGROUP_CTX: case LXC_CMD_GET_CGROUP_CTX:
if (!fret) err = __transfer_cgroup_ctx_fds(fds, rsp->data);
ret = __transfer_cgroup_ctx_fds(fds, rsp->data);
/* Make sure any received fds are wiped by us. */
break; break;
case LXC_CMD_GET_CGROUP_FD: case LXC_CMD_GET_CGROUP_FD:
__fallthrough; __fallthrough;
case LXC_CMD_GET_LIMIT_CGROUP_FD: case LXC_CMD_GET_LIMIT_CGROUP_FD:
if (!fret) err = __transfer_cgroup_fd(fds, rsp->data);
ret = __transfer_cgroup_fd(fds, rsp->data);
/* Make sure any received fds are wiped by us. */
break; break;
default:
err = 0;
}
if (err < 0)
return syserrno(err, "Failed to transfer file descriptors for command \"%s\"", cur_cmdstr);
} }
no_data:
if (!fret && ret >= 0)
move_ptr(__private_ptr); move_ptr(__private_ptr);
return bytes_recv;
return fret ?: ret;
} }
/* /*
...@@ -376,6 +398,17 @@ static inline int rsp_one_fd(int fd, int fd_send, struct lxc_cmd_rsp *rsp) ...@@ -376,6 +398,17 @@ static inline int rsp_one_fd(int fd, int fd_send, struct lxc_cmd_rsp *rsp)
return LXC_CMD_REAP_CLIENT_FD; return LXC_CMD_REAP_CLIENT_FD;
} }
static inline int rsp_one_fd_keep(int fd, int fd_send, struct lxc_cmd_rsp *rsp)
{
int ret;
ret = rsp_one_fd(fd, fd_send, rsp);
if (ret == LXC_CMD_REAP_CLIENT_FD)
ret = LXC_CMD_KEEP_CLIENT_FD;
return ret;
}
__access_r(3, 2) static int rsp_many_fds(int fd, __u32 fds_len, __access_r(3, 2) static int rsp_many_fds(int fd, __u32 fds_len,
const __s32 fds[static 2], const __s32 fds[static 2],
struct lxc_cmd_rsp *rsp) struct lxc_cmd_rsp *rsp)
...@@ -456,12 +489,12 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd, ...@@ -456,12 +489,12 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
* the slot with lxc_cmd_fd_cleanup(). The socket fd will be returned in the * the slot with lxc_cmd_fd_cleanup(). The socket fd will be returned in the
* cmd response structure. * cmd response structure.
*/ */
static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped, static ssize_t lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, bool *stopped,
const char *lxcpath, const char *hashed_sock_name) const char *lxcpath, const char *hashed_sock_name)
{ {
__do_close int client_fd = -EBADF; __do_close int client_fd = -EBADF;
int ret = -1;
bool stay_connected = false; bool stay_connected = false;
ssize_t ret;
if (cmd->req.cmd == LXC_CMD_GET_TTY_FD || if (cmd->req.cmd == LXC_CMD_GET_TTY_FD ||
cmd->req.cmd == LXC_CMD_ADD_STATE_CLIENT) cmd->req.cmd == LXC_CMD_ADD_STATE_CLIENT)
...@@ -471,11 +504,10 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped, ...@@ -471,11 +504,10 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
client_fd = lxc_cmd_send(name, cmd, lxcpath, hashed_sock_name); client_fd = lxc_cmd_send(name, cmd, lxcpath, hashed_sock_name);
if (client_fd < 0) { if (client_fd < 0) {
if (errno == ECONNREFUSED || errno == EPIPE) if (IN_SET(errno, ECONNREFUSED, EPIPE))
*stopped = 1; *stopped = 1;
return log_trace_errno(-1, errno, "Command \"%s\" failed to connect command socket", return systrace(-errno, "Command \"%s\" failed to connect command socket", lxc_cmd_str(cmd->req.cmd));
lxc_cmd_str(cmd->req.cmd));
} }
ret = lxc_cmd_rsp_recv(client_fd, cmd); ret = lxc_cmd_rsp_recv(client_fd, cmd);
...@@ -493,10 +525,11 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped, ...@@ -493,10 +525,11 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
int lxc_try_cmd(const char *name, const char *lxcpath) int lxc_try_cmd(const char *name, const char *lxcpath)
{ {
int stopped, ret; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { .cmd = LXC_CMD_GET_INIT_PID }, struct lxc_cmd_rr cmd;
};
lxc_cmd_init(&cmd, LXC_CMD_GET_INIT_PID);
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (stopped) if (stopped)
...@@ -508,7 +541,8 @@ int lxc_try_cmd(const char *name, const char *lxcpath) ...@@ -508,7 +541,8 @@ int lxc_try_cmd(const char *name, const char *lxcpath)
if (ret > 0) if (ret > 0)
return 0; return 0;
/* At this point we weren't denied access, and the container *was* /*
* At this point we weren't denied access, and the container *was*
* started. There was some inexplicable error in the protocol. I'm not * started. There was some inexplicable error in the protocol. I'm not
* clear on whether we should return -1 here, but we didn't receive a * clear on whether we should return -1 here, but we didn't receive a
* -EACCES, so technically it's not that we're not allowed to control * -EACCES, so technically it's not that we're not allowed to control
...@@ -552,16 +586,12 @@ static int validate_string_request(int fd, const struct lxc_cmd_req *req) ...@@ -552,16 +586,12 @@ static int validate_string_request(int fd, const struct lxc_cmd_req *req)
*/ */
pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath) pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
pid_t pid = -1; ssize_t ret;
struct lxc_cmd_rr cmd = { pid_t pid;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_INIT_PID
}, lxc_cmd_init(&cmd, LXC_CMD_GET_INIT_PID);
.rsp = {
.data = PID_TO_PTR(pid)
}
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -571,7 +601,8 @@ pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath) ...@@ -571,7 +601,8 @@ pid_t lxc_cmd_get_init_pid(const char *name, const char *lxcpath)
if (pid < 0) if (pid < 0)
return -1; return -1;
/* We need to assume that pid_t can actually hold any pid given to us /*
* We need to assume that pid_t can actually hold any pid given to us
* by the kernel. If it can't it's a libc bug. * by the kernel. If it can't it's a libc bug.
*/ */
return (pid_t)pid; return (pid_t)pid;
...@@ -590,28 +621,22 @@ static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req, ...@@ -590,28 +621,22 @@ static int lxc_cmd_get_init_pid_callback(int fd, struct lxc_cmd_req *req,
int lxc_cmd_get_init_pidfd(const char *name, const char *lxcpath) int lxc_cmd_get_init_pidfd(const char *name, const char *lxcpath)
{ {
int pidfd; bool stopped = false;
int ret, stopped; int pidfd, ret;
struct lxc_cmd_rr cmd = { struct lxc_cmd_rr cmd;
.req = {
.cmd = LXC_CMD_GET_INIT_PIDFD, lxc_cmd_init(&cmd, LXC_CMD_GET_INIT_PIDFD);
},
.rsp = {
.data = INT_TO_PTR(-EBADF),
.ret = ENOSYS,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
return log_debug_errno(-1, errno, "Failed to process init pidfd command"); return sysdebug("Failed to process init pidfd command");
if (cmd.rsp.ret < 0) if (cmd.rsp.ret < 0)
return syserrno_set(cmd.rsp.ret, "Failed to receive init pidfd"); return sysdebug_set(cmd.rsp.ret, "Failed to receive init pidfd");
pidfd = PTR_TO_INT(cmd.rsp.data); pidfd = PTR_TO_INT(cmd.rsp.data);
if (pidfd < 0) if (pidfd < 0)
return syserrno_set(pidfd, "Failed to receive init pidfd"); return sysdebug_set(pidfd, "Failed to receive init pidfd");
return pidfd; return pidfd;
} }
...@@ -633,12 +658,11 @@ static int lxc_cmd_get_init_pidfd_callback(int fd, struct lxc_cmd_req *req, ...@@ -633,12 +658,11 @@ static int lxc_cmd_get_init_pidfd_callback(int fd, struct lxc_cmd_req *req,
int lxc_cmd_get_devpts_fd(const char *name, const char *lxcpath) int lxc_cmd_get_devpts_fd(const char *name, const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_DEVPTS_FD,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_DEVPTS_FD);
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -668,12 +692,11 @@ static int lxc_cmd_get_devpts_fd_callback(int fd, struct lxc_cmd_req *req, ...@@ -668,12 +692,11 @@ static int lxc_cmd_get_devpts_fd_callback(int fd, struct lxc_cmd_req *req,
int lxc_cmd_get_seccomp_notify_fd(const char *name, const char *lxcpath) int lxc_cmd_get_seccomp_notify_fd(const char *name, const char *lxcpath)
{ {
#ifdef HAVE_SECCOMP_NOTIFY #ifdef HAVE_SECCOMP_NOTIFY
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_SECCOMP_NOTIFY_FD,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_SECCOMP_NOTIFY_FD);
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -710,17 +733,12 @@ static int lxc_cmd_get_seccomp_notify_fd_callback(int fd, struct lxc_cmd_req *re ...@@ -710,17 +733,12 @@ static int lxc_cmd_get_seccomp_notify_fd_callback(int fd, struct lxc_cmd_req *re
int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath, int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath,
size_t size_ret_ctx, struct cgroup_ctx *ret_ctx) size_t size_ret_ctx, struct cgroup_ctx *ret_ctx)
{ {
struct lxc_cmd_rr cmd = { bool stopped = false;
.req = { ssize_t ret;
.cmd = LXC_CMD_GET_CGROUP_CTX, struct lxc_cmd_rr cmd;
.datalen = size_ret_ctx,
.data = ret_ctx, lxc_cmd_init(&cmd, LXC_CMD_GET_CGROUP_CTX);
}, lxc_cmd_data(&cmd, size_ret_ctx, ret_ctx);
.rsp = {
.ret = -ENOSYS,
},
};
int ret, stopped;
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -741,7 +759,7 @@ static int lxc_cmd_get_cgroup_ctx_callback(int fd, struct lxc_cmd_req *req, ...@@ -741,7 +759,7 @@ static int lxc_cmd_get_cgroup_ctx_callback(int fd, struct lxc_cmd_req *req,
}; };
struct cgroup_ops *cgroup_ops = handler->cgroup_ops; struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
struct cgroup_ctx ctx_server = {}; struct cgroup_ctx ctx_server = {};
int ret; ssize_t ret;
ret = copy_struct_from_client(sizeof(struct cgroup_ctx), &ctx_server, ret = copy_struct_from_client(sizeof(struct cgroup_ctx), &ctx_server,
req->datalen, req->data); req->datalen, req->data);
...@@ -770,12 +788,11 @@ static int lxc_cmd_get_cgroup_ctx_callback(int fd, struct lxc_cmd_req *req, ...@@ -770,12 +788,11 @@ static int lxc_cmd_get_cgroup_ctx_callback(int fd, struct lxc_cmd_req *req,
*/ */
int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath) int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_CLONE_FLAGS,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_CLONE_FLAGS);
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -795,23 +812,18 @@ static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req, ...@@ -795,23 +812,18 @@ static int lxc_cmd_get_clone_flags_callback(int fd, struct lxc_cmd_req *req,
return lxc_cmd_rsp_send_reap(fd, &rsp); return lxc_cmd_rsp_send_reap(fd, &rsp);
} }
static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath, static char *lxc_cmd_get_cgroup_path_callback(const char *name,
const char *subsystem, const char *lxcpath,
const char *controller,
lxc_cmd_t command) lxc_cmd_t command)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = command,
.data = subsystem,
.datalen = 0,
},
};
cmd.req.data = subsystem; lxc_cmd_init(&cmd, command);
cmd.req.datalen = 0; if (controller)
if (subsystem) lxc_cmd_data(&cmd, strlen(controller) + 1, controller);
cmd.req.datalen = strlen(subsystem) + 1;
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -826,8 +838,8 @@ static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath, ...@@ -826,8 +838,8 @@ static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath,
* it sees an unknown command and just closes the * it sees an unknown command and just closes the
* socket, sending us an EOF. * socket, sending us an EOF.
*/ */
return lxc_cmd_get_cgroup_path_do(name, lxcpath, return lxc_cmd_get_cgroup_path_callback(name, lxcpath,
subsystem, controller,
LXC_CMD_GET_CGROUP); LXC_CMD_GET_CGROUP);
} }
return NULL; return NULL;
...@@ -841,50 +853,50 @@ static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath, ...@@ -841,50 +853,50 @@ static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath,
/* /*
* lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a * lxc_cmd_get_cgroup_path: Calculate a container's cgroup path for a
* particular subsystem. This is the cgroup path relative to the root * particular controller. This is the cgroup path relative to the root
* of the cgroup filesystem. * of the cgroup filesystem.
* *
* @name : name of container to connect to * @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running * @lxcpath : the lxcpath in which the container is running
* @subsystem : the subsystem being asked about * @controller : the controller being asked about
* *
* Returns the path on success, NULL on failure. The caller must free() the * Returns the path on success, NULL on failure. The caller must free() the
* returned path. * returned path.
*/ */
char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath, char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
const char *subsystem) const char *controller)
{ {
return lxc_cmd_get_cgroup_path_do(name, lxcpath, subsystem, return lxc_cmd_get_cgroup_path_callback(name, lxcpath, controller,
LXC_CMD_GET_CGROUP); LXC_CMD_GET_CGROUP);
} }
/* /*
* lxc_cmd_get_limit_cgroup_path: Calculate a container's limit cgroup * lxc_cmd_get_limit_cgroup_path: Calculate a container's limit cgroup
* path for a particular subsystem. This is the cgroup path relative to the * path for a particular controller. This is the cgroup path relative to the
* root of the cgroup filesystem. This may be the same as the path returned by * root of the cgroup filesystem. This may be the same as the path returned by
* lxc_cmd_get_cgroup_path if the container doesn't have a limit path prefix * lxc_cmd_get_cgroup_path if the container doesn't have a limit path prefix
* set. * set.
* *
* @name : name of container to connect to * @name : name of container to connect to
* @lxcpath : the lxcpath in which the container is running * @lxcpath : the lxcpath in which the container is running
* @subsystem : the subsystem being asked about * @controller : the controller being asked about
* *
* Returns the path on success, NULL on failure. The caller must free() the * Returns the path on success, NULL on failure. The caller must free() the
* returned path. * returned path.
*/ */
char *lxc_cmd_get_limit_cgroup_path(const char *name, const char *lxcpath, char *lxc_cmd_get_limit_cgroup_path(const char *name, const char *lxcpath,
const char *subsystem) const char *controller)
{ {
return lxc_cmd_get_cgroup_path_do(name, lxcpath, subsystem, return lxc_cmd_get_cgroup_path_callback(name, lxcpath, controller,
LXC_CMD_GET_LIMIT_CGROUP); LXC_CMD_GET_LIMIT_CGROUP);
} }
static int lxc_cmd_get_cgroup_callback_do(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, struct lxc_epoll_descr *descr,
bool limiting_cgroup) bool limiting_cgroup)
{ {
int ret; ssize_t ret;
const char *path; const char *path;
const void *reqdata; const void *reqdata;
struct lxc_cmd_rsp rsp; struct lxc_cmd_rsp rsp;
...@@ -919,14 +931,14 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req, ...@@ -919,14 +931,14 @@ 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) struct lxc_epoll_descr *descr)
{ {
return lxc_cmd_get_cgroup_callback_do(fd, req, handler, descr, false); return __lxc_cmd_get_cgroup_callback(fd, req, handler, descr, false);
} }
static int lxc_cmd_get_limit_cgroup_callback(int fd, struct lxc_cmd_req *req, static int lxc_cmd_get_limit_cgroup_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
return lxc_cmd_get_cgroup_callback_do(fd, req, handler, descr, true); return __lxc_cmd_get_cgroup_callback(fd, req, handler, descr, true);
} }
/* /*
...@@ -942,13 +954,15 @@ static int lxc_cmd_get_limit_cgroup_callback(int fd, struct lxc_cmd_req *req, ...@@ -942,13 +954,15 @@ static int lxc_cmd_get_limit_cgroup_callback(int fd, struct lxc_cmd_req *req,
char *lxc_cmd_get_config_item(const char *name, const char *item, char *lxc_cmd_get_config_item(const char *name, const char *item,
const char *lxcpath) const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { .cmd = LXC_CMD_GET_CONFIG_ITEM, struct lxc_cmd_rr cmd;
.data = item,
.datalen = strlen(item) + 1, if (is_empty_string(item))
}, return NULL;
};
lxc_cmd_init(&cmd, LXC_CMD_GET_CONFIG_ITEM);
lxc_cmd_data(&cmd, strlen(item) + 1, item);
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1004,12 +1018,11 @@ out: ...@@ -1004,12 +1018,11 @@ out:
*/ */
int lxc_cmd_get_state(const char *name, const char *lxcpath) int lxc_cmd_get_state(const char *name, const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_STATE,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_STATE);
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0 && stopped) if (ret < 0 && stopped)
...@@ -1048,12 +1061,11 @@ static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req, ...@@ -1048,12 +1061,11 @@ static int lxc_cmd_get_state_callback(int fd, struct lxc_cmd_req *req,
*/ */
int lxc_cmd_stop(const char *name, const char *lxcpath) int lxc_cmd_stop(const char *name, const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_STOP,
}, lxc_cmd_init(&cmd, LXC_CMD_STOP);
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) { if (ret < 0) {
...@@ -1145,13 +1157,12 @@ static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req, ...@@ -1145,13 +1157,12 @@ static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req,
int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd, const char *lxcpath) int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd, const char *lxcpath)
{ {
__do_free struct lxc_cmd_tty_rsp_data *rspdata = NULL; __do_free struct lxc_cmd_tty_rsp_data *rspdata = NULL;
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_TTY_FD,
.data = INT_TO_PTR(*ttynum), lxc_cmd_init(&cmd, LXC_CMD_GET_TTY_FD);
}, lxc_cmd_data(&cmd, ENCODE_INTO_PTR_LEN, INT_TO_PTR(*ttynum));
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1171,32 +1182,32 @@ int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd, const char *lxcpa ...@@ -1171,32 +1182,32 @@ int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd, const char *lxcpa
*fd = rspdata->ptxfd; *fd = rspdata->ptxfd;
*ttynum = rspdata->ttynum; *ttynum = rspdata->ttynum;
return log_info(ret, "Alloced fd %d for tty %d via socket %d", *fd, rspdata->ttynum, ret); return log_info(ret, "Alloced fd %d for tty %d via socket %zd", *fd, rspdata->ttynum, ret);
} }
static int lxc_cmd_get_tty_fd_callback(int fd, struct lxc_cmd_req *req, static int lxc_cmd_get_tty_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
int ptxfd, ret;
struct lxc_cmd_rsp rsp = { struct lxc_cmd_rsp rsp = {
.ret = -EBADF, .ret = -EBADF,
}; };
int ttynum = PTR_TO_INT(req->data); int ptxfd, ret, ttynum;
ttynum = PTR_TO_INT(req->data);
ptxfd = lxc_terminal_allocate(handler->conf, fd, &ttynum); ptxfd = lxc_terminal_allocate(handler->conf, fd, &ttynum);
if (ptxfd < 0) if (ptxfd < 0)
return lxc_cmd_rsp_send_reap(fd, &rsp); return lxc_cmd_rsp_send_reap(fd, &rsp);
rsp.ret = 0; rsp.ret = 0;
rsp.data = INT_TO_PTR(ttynum); rsp.data = INT_TO_PTR(ttynum);
ret = lxc_abstract_unix_send_fds(fd, &ptxfd, 1, &rsp, sizeof(rsp)); ret = rsp_one_fd_keep(fd, ptxfd, &rsp);
if (ret < 0) { if (ret < 0) {
lxc_terminal_free(handler->conf, fd); lxc_terminal_free(handler->conf, fd);
return ret; return ret;
} }
return log_debug(0, "Send tty to client"); return log_debug(ret, "Send tty to client");
} }
/* /*
...@@ -1208,12 +1219,11 @@ static int lxc_cmd_get_tty_fd_callback(int fd, struct lxc_cmd_req *req, ...@@ -1208,12 +1219,11 @@ static int lxc_cmd_get_tty_fd_callback(int fd, struct lxc_cmd_req *req,
*/ */
char *lxc_cmd_get_name(const char *hashed_sock_name) char *lxc_cmd_get_name(const char *hashed_sock_name)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_NAME,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_NAME);
};
ret = lxc_cmd(NULL, &cmd, &stopped, NULL, hashed_sock_name); ret = lxc_cmd(NULL, &cmd, &stopped, NULL, hashed_sock_name);
if (ret < 0) if (ret < 0)
...@@ -1249,12 +1259,11 @@ static int lxc_cmd_get_name_callback(int fd, struct lxc_cmd_req *req, ...@@ -1249,12 +1259,11 @@ static int lxc_cmd_get_name_callback(int fd, struct lxc_cmd_req *req,
*/ */
char *lxc_cmd_get_lxcpath(const char *hashed_sock_name) char *lxc_cmd_get_lxcpath(const char *hashed_sock_name)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_LXCPATH,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_LXCPATH);
};
ret = lxc_cmd(NULL, &cmd, &stopped, NULL, hashed_sock_name); ret = lxc_cmd(NULL, &cmd, &stopped, NULL, hashed_sock_name);
if (ret < 0) if (ret < 0)
...@@ -1284,15 +1293,13 @@ int lxc_cmd_add_state_client(const char *name, const char *lxcpath, ...@@ -1284,15 +1293,13 @@ int lxc_cmd_add_state_client(const char *name, const char *lxcpath,
int *state_client_fd) int *state_client_fd)
{ {
__do_close int clientfd = -EBADF; __do_close int clientfd = -EBADF;
int state, stopped; bool stopped = false;
int state;
ssize_t ret; ssize_t ret;
struct lxc_cmd_rr cmd = { struct lxc_cmd_rr cmd;
.req = {
.cmd = LXC_CMD_ADD_STATE_CLIENT, lxc_cmd_init(&cmd, LXC_CMD_ADD_STATE_CLIENT);
.data = states, lxc_cmd_data(&cmd, (sizeof(lxc_state_t) * MAX_STATE), states);
.datalen = (sizeof(lxc_state_t) * MAX_STATE)
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (states[STOPPED] != 0 && stopped != 0) if (states[STOPPED] != 0 && stopped != 0)
...@@ -1353,23 +1360,22 @@ reap_fd: ...@@ -1353,23 +1360,22 @@ reap_fd:
int lxc_cmd_add_bpf_device_cgroup(const char *name, const char *lxcpath, int lxc_cmd_add_bpf_device_cgroup(const char *name, const char *lxcpath,
struct device_item *device) struct device_item *device)
{ {
int stopped = 0; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_ADD_BPF_DEVICE_CGROUP,
.data = device,
.datalen = sizeof(struct device_item),
},
};
int ret;
if (strlen(device->access) > STRLITERALLEN("rwm")) if (strlen(device->access) > STRLITERALLEN("rwm"))
return log_error_errno(-1, EINVAL, "Invalid access mode specified %s", return syserrno_set(-EINVAL, "Invalid access mode specified %s", device->access);
device->access);
lxc_cmd_init(&cmd, LXC_CMD_ADD_BPF_DEVICE_CGROUP);
lxc_cmd_data(&cmd, sizeof(struct device_item), device);
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0 || cmd.rsp.ret < 0) if (ret < 0)
return log_error_errno(-1, errno, "Failed to add new bpf device cgroup rule"); return syserrno_set(ret, "Failed to process new bpf device cgroup command");
if (cmd.rsp.ret < 0)
return syserrno_set(cmd.rsp.ret, "Failed to add new bpf device cgroup rule");
return 0; return 0;
} }
...@@ -1407,17 +1413,17 @@ out: ...@@ -1407,17 +1413,17 @@ out:
int lxc_cmd_console_log(const char *name, const char *lxcpath, int lxc_cmd_console_log(const char *name, const char *lxcpath,
struct lxc_console_log *log) struct lxc_console_log *log)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_console_log data; struct lxc_cmd_console_log data = {
.clear = log->clear,
.read = log->read,
.read_max = *log->read_max,
};
ssize_t ret;
struct lxc_cmd_rr cmd; struct lxc_cmd_rr cmd;
data.clear = log->clear; lxc_cmd_init(&cmd, LXC_CMD_CONSOLE_LOG);
data.read = log->read; lxc_cmd_data(&cmd, sizeof(struct lxc_cmd_console_log), &data);
data.read_max = *log->read_max;
cmd.req.cmd = LXC_CMD_CONSOLE_LOG;
cmd.req.data = &data;
cmd.req.datalen = sizeof(struct lxc_cmd_console_log);
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1483,14 +1489,12 @@ out: ...@@ -1483,14 +1489,12 @@ out:
int lxc_cmd_serve_state_clients(const char *name, const char *lxcpath, int lxc_cmd_serve_state_clients(const char *name, const char *lxcpath,
lxc_state_t state) lxc_state_t state)
{ {
int stopped; bool stopped = false;
ssize_t ret; ssize_t ret;
struct lxc_cmd_rr cmd = { struct lxc_cmd_rr cmd;
.req = {
.cmd = LXC_CMD_SERVE_STATE_CLIENTS, lxc_cmd_init(&cmd, LXC_CMD_SERVE_STATE_CLIENTS);
.data = INT_TO_PTR(state) lxc_cmd_data(&cmd, ENCODE_INTO_PTR_LEN, INT_TO_PTR(state));
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1521,13 +1525,12 @@ int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath, ...@@ -1521,13 +1525,12 @@ int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath,
{ {
#ifdef HAVE_SECCOMP_NOTIFY #ifdef HAVE_SECCOMP_NOTIFY
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER,
.data = INT_TO_PTR(fd), lxc_cmd_init(&cmd, LXC_CMD_SECCOMP_NOTIFY_ADD_LISTENER);
}, lxc_cmd_data(&cmd, ENCODE_INTO_PTR_LEN, INT_TO_PTR(fd));
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1581,13 +1584,12 @@ out: ...@@ -1581,13 +1584,12 @@ out:
int lxc_cmd_freeze(const char *name, const char *lxcpath, int timeout) int lxc_cmd_freeze(const char *name, const char *lxcpath, int timeout)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_FREEZE,
.data = INT_TO_PTR(timeout), lxc_cmd_init(&cmd, LXC_CMD_FREEZE);
}, lxc_cmd_data(&cmd, ENCODE_INTO_PTR_LEN, INT_TO_PTR(timeout));
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret <= 0 || cmd.rsp.ret < 0) if (ret <= 0 || cmd.rsp.ret < 0)
...@@ -1614,13 +1616,12 @@ static int lxc_cmd_freeze_callback(int fd, struct lxc_cmd_req *req, ...@@ -1614,13 +1616,12 @@ static int lxc_cmd_freeze_callback(int fd, struct lxc_cmd_req *req,
int lxc_cmd_unfreeze(const char *name, const char *lxcpath, int timeout) int lxc_cmd_unfreeze(const char *name, const char *lxcpath, int timeout)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_UNFREEZE,
.data = INT_TO_PTR(timeout), lxc_cmd_init(&cmd, LXC_CMD_UNFREEZE);
}, lxc_cmd_data(&cmd, ENCODE_INTO_PTR_LEN, INT_TO_PTR(timeout));
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret <= 0 || cmd.rsp.ret < 0) if (ret <= 0 || cmd.rsp.ret < 0)
...@@ -1648,17 +1649,12 @@ static int lxc_cmd_unfreeze_callback(int fd, struct lxc_cmd_req *req, ...@@ -1648,17 +1649,12 @@ static int lxc_cmd_unfreeze_callback(int fd, struct lxc_cmd_req *req,
int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath, int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath,
size_t size_ret_fd, struct cgroup_fd *ret_fd) size_t size_ret_fd, struct cgroup_fd *ret_fd)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_CGROUP_FD,
.datalen = sizeof(struct cgroup_fd), lxc_cmd_init(&cmd, LXC_CMD_GET_CGROUP_FD);
.data = ret_fd, lxc_cmd_data(&cmd, sizeof(struct cgroup_fd), ret_fd);
},
.rsp = {
ret = -ENOSYS,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1673,17 +1669,12 @@ int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath, ...@@ -1673,17 +1669,12 @@ int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath,
int lxc_cmd_get_limit_cgroup_fd(const char *name, const char *lxcpath, int lxc_cmd_get_limit_cgroup_fd(const char *name, const char *lxcpath,
size_t size_ret_fd, struct cgroup_fd *ret_fd) size_t size_ret_fd, struct cgroup_fd *ret_fd)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_LIMIT_CGROUP_FD,
.datalen = sizeof(struct cgroup_fd), lxc_cmd_init(&cmd, LXC_CMD_GET_LIMIT_CGROUP_FD);
.data = ret_fd, lxc_cmd_data(&cmd, sizeof(struct cgroup_fd), ret_fd);
},
.rsp = {
ret = -ENOSYS,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1743,15 +1734,11 @@ static int lxc_cmd_get_limit_cgroup_fd_callback(int fd, struct lxc_cmd_req *req, ...@@ -1743,15 +1734,11 @@ static int lxc_cmd_get_limit_cgroup_fd_callback(int fd, struct lxc_cmd_req *req,
int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath) int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_CGROUP2_FD,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_CGROUP2_FD);
.rsp = {
ret = -ENOSYS,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1765,15 +1752,11 @@ int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath) ...@@ -1765,15 +1752,11 @@ int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath)
int lxc_cmd_get_limit_cgroup2_fd(const char *name, const char *lxcpath) int lxc_cmd_get_limit_cgroup2_fd(const char *name, const char *lxcpath)
{ {
int ret, stopped; bool stopped = false;
struct lxc_cmd_rr cmd = { ssize_t ret;
.req = { struct lxc_cmd_rr cmd;
.cmd = LXC_CMD_GET_LIMIT_CGROUP2_FD,
}, lxc_cmd_init(&cmd, LXC_CMD_GET_LIMIT_CGROUP2_FD);
.rsp = {
.ret = -ENOSYS,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
...@@ -1785,7 +1768,7 @@ int lxc_cmd_get_limit_cgroup2_fd(const char *name, const char *lxcpath) ...@@ -1785,7 +1768,7 @@ int lxc_cmd_get_limit_cgroup2_fd(const char *name, const char *lxcpath)
return PTR_TO_INT(cmd.rsp.data); return PTR_TO_INT(cmd.rsp.data);
} }
static int lxc_cmd_get_cgroup2_fd_callback_do(int fd, struct lxc_cmd_req *req, static int __lxc_cmd_get_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr, struct lxc_epoll_descr *descr,
bool limiting_cgroup) bool limiting_cgroup)
...@@ -1815,16 +1798,14 @@ static int lxc_cmd_get_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req, ...@@ -1815,16 +1798,14 @@ static int lxc_cmd_get_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
return lxc_cmd_get_cgroup2_fd_callback_do(fd, req, handler, descr, return __lxc_cmd_get_cgroup2_fd_callback(fd, req, handler, descr, false);
false);
} }
static int lxc_cmd_get_limit_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req, static int lxc_cmd_get_limit_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
return lxc_cmd_get_cgroup2_fd_callback_do(fd, req, handler, descr, return __lxc_cmd_get_cgroup2_fd_callback(fd, req, handler, descr, true);
true);
} }
static int lxc_cmd_rsp_send_enosys(int fd, int id) static int lxc_cmd_rsp_send_enosys(int fd, int id)
...@@ -2018,7 +1999,7 @@ static int lxc_cmd_accept(int fd, uint32_t events, void *data, ...@@ -2018,7 +1999,7 @@ static int lxc_cmd_accept(int fd, uint32_t events, void *data,
return ret; return ret;
} }
int lxc_cmd_init(const char *name, const char *lxcpath, const char *suffix) int lxc_server_init(const char *name, const char *lxcpath, const char *suffix)
{ {
__do_close int fd = -EBADF; __do_close int fd = -EBADF;
int ret; int ret;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#ifndef __LXC_COMMANDS_H #ifndef __LXC_COMMANDS_H
#define __LXC_COMMANDS_H #define __LXC_COMMANDS_H
#include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
* have specific reasons to keep the file descriptor alive. * have specific reasons to keep the file descriptor alive.
*/ */
#define LXC_CMD_REAP_CLIENT_FD 1 #define LXC_CMD_REAP_CLIENT_FD 1
#define LXC_CMD_KEEP_CLIENT_FD 2
typedef enum { typedef enum {
LXC_CMD_GET_TTY_FD = 0, LXC_CMD_GET_TTY_FD = 0,
...@@ -56,6 +58,8 @@ struct lxc_cmd_req { ...@@ -56,6 +58,8 @@ struct lxc_cmd_req {
const void *data; const void *data;
}; };
#define ENCODE_INTO_PTR_LEN 0
struct lxc_cmd_rsp { struct lxc_cmd_rsp {
int ret; /* 0 on success, -errno on failure */ int ret; /* 0 on success, -errno on failure */
int datalen; int datalen;
...@@ -67,6 +71,20 @@ struct lxc_cmd_rr { ...@@ -67,6 +71,20 @@ struct lxc_cmd_rr {
struct lxc_cmd_rsp rsp; struct lxc_cmd_rsp rsp;
}; };
static inline void lxc_cmd_init(struct lxc_cmd_rr *cmd, lxc_cmd_t command)
{
*cmd = (struct lxc_cmd_rr){
.req = {.cmd = command },
.rsp = {.ret = -ENOSYS },
};
}
static inline void lxc_cmd_data(struct lxc_cmd_rr *cmd, int len_data, const void *data)
{
cmd->req.data = data;
cmd->req.datalen = len_data;
}
struct lxc_cmd_tty_rsp_data { struct lxc_cmd_tty_rsp_data {
int ptxfd; int ptxfd;
int ttynum; int ttynum;
...@@ -85,10 +103,10 @@ __hidden extern int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd, ...@@ -85,10 +103,10 @@ __hidden extern int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd,
const char *lxcpath); const char *lxcpath);
/* /*
* Get the 'real' cgroup path (as seen in /proc/self/cgroup) for a container * Get the 'real' cgroup path (as seen in /proc/self/cgroup) for a container
* for a particular subsystem * for a particular controller
*/ */
__hidden extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath, __hidden extern char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
const char *subsystem); const char *controller);
__hidden extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath); __hidden extern int lxc_cmd_get_clone_flags(const char *name, const char *lxcpath);
__hidden extern char *lxc_cmd_get_config_item(const char *name, const char *item, __hidden extern char *lxc_cmd_get_config_item(const char *name, const char *item,
const char *lxcpath); const char *lxcpath);
...@@ -122,7 +140,7 @@ __hidden extern int lxc_cmd_serve_state_clients(const char *name, const char *lx ...@@ -122,7 +140,7 @@ __hidden extern int lxc_cmd_serve_state_clients(const char *name, const char *lx
struct lxc_epoll_descr; struct lxc_epoll_descr;
struct lxc_handler; struct lxc_handler;
__hidden extern int lxc_cmd_init(const char *name, const char *lxcpath, const char *suffix); __hidden extern int lxc_server_init(const char *name, const char *lxcpath, const char *suffix);
__hidden extern int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr, __hidden extern int lxc_cmd_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
struct lxc_handler *handler); struct lxc_handler *handler);
__hidden extern int lxc_try_cmd(const char *name, const char *lxcpath); __hidden extern int lxc_try_cmd(const char *name, const char *lxcpath);
...@@ -147,7 +165,7 @@ __hidden extern int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath, ...@@ -147,7 +165,7 @@ __hidden extern int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath,
struct cgroup_fd *ret_fd); struct cgroup_fd *ret_fd);
__hidden extern char *lxc_cmd_get_limit_cgroup_path(const char *name, __hidden extern char *lxc_cmd_get_limit_cgroup_path(const char *name,
const char *lxcpath, const char *lxcpath,
const char *subsystem); const char *controller);
__hidden extern int lxc_cmd_get_limit_cgroup2_fd(const char *name, __hidden extern int lxc_cmd_get_limit_cgroup2_fd(const char *name,
const char *lxcpath); const char *lxcpath);
__hidden extern int lxc_cmd_get_limit_cgroup_fd(const char *name, __hidden extern int lxc_cmd_get_limit_cgroup_fd(const char *name,
......
...@@ -508,10 +508,10 @@ __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \ ...@@ -508,10 +508,10 @@ __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
__internal_ret__; \ __internal_ret__; \
}) })
#define sysdebug(__ret__, format, ...) \ #define systrace(__ret__, format, ...) \
({ \ ({ \
typeof(__ret__) __internal_ret__ = (__ret__); \ typeof(__ret__) __internal_ret__ = (__ret__); \
SYSDEBUG(format, ##__VA_ARGS__); \ SYSTRACE(format, ##__VA_ARGS__); \
__internal_ret__; \ __internal_ret__; \
}) })
...@@ -525,7 +525,7 @@ __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \ ...@@ -525,7 +525,7 @@ __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
#define syserrno_set(__ret__, format, ...) \ #define syserrno_set(__ret__, format, ...) \
({ \ ({ \
typeof(__ret__) __internal_ret__ = (__ret__); \ typeof(__ret__) __internal_ret__ = (__ret__); \
errno = abs(__ret__); \ errno = labs(__ret__); \
SYSERROR(format, ##__VA_ARGS__); \ SYSERROR(format, ##__VA_ARGS__); \
__internal_ret__; \ __internal_ret__; \
}) })
...@@ -533,11 +533,39 @@ __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \ ...@@ -533,11 +533,39 @@ __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
#define syswarn_set(__ret__, format, ...) \ #define syswarn_set(__ret__, format, ...) \
({ \ ({ \
typeof(__ret__) __internal_ret__ = (__ret__); \ typeof(__ret__) __internal_ret__ = (__ret__); \
errno = abs(__ret__); \ errno = labs(__ret__); \
SYSWARN(format, ##__VA_ARGS__); \ SYSWARN(format, ##__VA_ARGS__); \
__internal_ret__; \ __internal_ret__; \
}) })
#define syserror(format, ...) \
({ \
SYSERROR(format, ##__VA_ARGS__); \
(-errno); \
})
#define syserror_set(__ret__, format, ...) \
({ \
typeof(__ret__) __internal_ret__ = (__ret__); \
errno = labs(__ret__); \
SYSERROR(format, ##__VA_ARGS__); \
__internal_ret__; \
})
#define sysdebug(format, ...) \
({ \
SYSDEBUG(format, ##__VA_ARGS__); \
(-errno); \
})
#define sysdebug_set(__ret__, format, ...) \
({ \
typeof(__ret__) __internal_ret__ = (__ret__); \
errno = labs(__ret__); \
SYSDEBUG(format, ##__VA_ARGS__); \
__internal_ret__; \
})
#define log_error(__ret__, format, ...) \ #define log_error(__ret__, format, ...) \
({ \ ({ \
typeof(__ret__) __internal_ret__ = (__ret__); \ typeof(__ret__) __internal_ret__ = (__ret__); \
......
...@@ -708,4 +708,29 @@ enum { ...@@ -708,4 +708,29 @@ enum {
_min1 < _min2 ? _min1 : _min2; \ _min1 < _min2 ? _min1 : _min2; \
}) })
#define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))
/*
* Compile time versions of __arch_hweightN()
*/
#define __const_hweight8(w) \
((unsigned int) \
((!!((w) & (1ULL << 0))) + \
(!!((w) & (1ULL << 1))) + \
(!!((w) & (1ULL << 2))) + \
(!!((w) & (1ULL << 3))) + \
(!!((w) & (1ULL << 4))) + \
(!!((w) & (1ULL << 5))) + \
(!!((w) & (1ULL << 6))) + \
(!!((w) & (1ULL << 7)))))
#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8 ))
#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16))
#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32))
#define hweight8(w) __const_hweight8(w)
#define hweight16(w) __const_hweight16(w)
#define hweight32(w) __const_hweight32(w)
#define hweight64(w) __const_hweight64(w)
#endif /* __LXC_MACRO_H */ #endif /* __LXC_MACRO_H */
...@@ -715,7 +715,7 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, ...@@ -715,7 +715,7 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old,
} }
if (handler->conf->reboot == REBOOT_NONE) { if (handler->conf->reboot == REBOOT_NONE) {
handler->conf->maincmd_fd = lxc_cmd_init(name, lxcpath, "command"); handler->conf->maincmd_fd = lxc_server_init(name, lxcpath, "command");
if (handler->conf->maincmd_fd < 0) { if (handler->conf->maincmd_fd < 0) {
ERROR("Failed to set up command socket"); ERROR("Failed to set up command socket");
goto on_error; goto on_error;
......
...@@ -45,17 +45,21 @@ set -e ...@@ -45,17 +45,21 @@ set -e
allocate_pty="nopty" allocate_pty="nopty"
ATTACH_LOG=$(mktemp --dry-run)
FAIL() { FAIL() {
echo -n "Failed " >&2 echo -n "Failed " >&2
echo "$*" >&2 echo "$*" >&2
cat "${ATTACH_LOG}"
rm -f "${ATTACH_LOG}" || true
lxc-destroy -n busy -f lxc-destroy -n busy -f
exit 1 exit 1
} }
# Create a container, start it and wait for it to be in running state. # Create a container, start it and wait for it to be in running state.
lxc-create -t busybox -n busy || FAIL "creating busybox container" lxc-create -t busybox -n busy -l trace -o "${ATTACH_LOG}" || FAIL "creating busybox container"
lxc-start -n busy -d || FAIL "starting busybox container" lxc-start -n busy -d -l trace -o "${ATTACH_LOG}" || FAIL "starting busybox container"
lxc-wait -n busy -s RUNNING || FAIL "waiting for busybox container to run" lxc-wait -n busy -s RUNNING -l trace -o "${ATTACH_LOG}" || FAIL "waiting for busybox container to run"
if [ -t 0 ] && [ -t 1 ] && [ -t 2 ]; then if [ -t 0 ] && [ -t 1 ] && [ -t 2 ]; then
allocate_pty="pty" allocate_pty="pty"
...@@ -68,7 +72,7 @@ fi ...@@ -68,7 +72,7 @@ fi
# stdout --> attached to pty # stdout --> attached to pty
# stderr --> attached to pty # stderr --> attached to pty
for i in `seq 1 100`; do for i in `seq 1 100`; do
attach=$(lxc-attach -n busy -- hostname || FAIL "to allocate or setup pty") attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname || FAIL "to allocate or setup pty")
if [ "$attach" != "busy" ]; then if [ "$attach" != "busy" ]; then
FAIL "lxc-attach -n busy -- hostname" FAIL "lxc-attach -n busy -- hostname"
fi fi
...@@ -77,7 +81,7 @@ done ...@@ -77,7 +81,7 @@ done
# stdin --> /dev/null # stdin --> /dev/null
# stdout --> attached to pty # stdout --> attached to pty
# stderr --> attached to pty # stderr --> attached to pty
attach=$(lxc-attach -n busy -- hostname < /dev/null || FAIL "to allocate or setup pty") attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname < /dev/null || FAIL "to allocate or setup pty")
if [ "$attach" != "busy" ]; then if [ "$attach" != "busy" ]; then
FAIL "lxc-attach -n busy -- hostname < /dev/null" FAIL "lxc-attach -n busy -- hostname < /dev/null"
fi fi
...@@ -85,7 +89,7 @@ fi ...@@ -85,7 +89,7 @@ fi
# stdin --> attached to pty # stdin --> attached to pty
# stdout --> /dev/null # stdout --> /dev/null
# stderr --> attached to pty # stderr --> attached to pty
attach=$(lxc-attach -n busy -- hostname > /dev/null || FAIL "to allocate or setup pty") attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname > /dev/null || FAIL "to allocate or setup pty")
if [ -n "$attach" ]; then if [ -n "$attach" ]; then
FAIL "lxc-attach -n busy -- hostname > /dev/null" FAIL "lxc-attach -n busy -- hostname > /dev/null"
fi fi
...@@ -93,7 +97,7 @@ fi ...@@ -93,7 +97,7 @@ fi
# stdin --> attached to pty # stdin --> attached to pty
# stdout --> attached to pty # stdout --> attached to pty
# stderr --> /dev/null # stderr --> /dev/null
attach=$(lxc-attach -n busy -- hostname 2> /dev/null || FAIL "to allocate or setup pty") attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname 2> /dev/null || FAIL "to allocate or setup pty")
if [ "$attach" != "busy" ]; then if [ "$attach" != "busy" ]; then
FAIL "lxc-attach -n busy -- hostname 2> /dev/null < /dev/null" FAIL "lxc-attach -n busy -- hostname 2> /dev/null < /dev/null"
fi fi
...@@ -101,7 +105,7 @@ fi ...@@ -101,7 +105,7 @@ fi
# stdin --> /dev/null # stdin --> /dev/null
# stdout --> attached to pty # stdout --> attached to pty
# stderr --> /dev/null # stderr --> /dev/null
attach=$(lxc-attach -n busy -- hostname 2> /dev/null < /dev/null || FAIL "to allocate or setup pty") attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname 2> /dev/null < /dev/null || FAIL "to allocate or setup pty")
if [ "$attach" != "busy" ]; then if [ "$attach" != "busy" ]; then
FAIL "lxc-attach -n busy -- hostname 2> /dev/null < /dev/null" FAIL "lxc-attach -n busy -- hostname 2> /dev/null < /dev/null"
fi fi
...@@ -114,7 +118,7 @@ fi ...@@ -114,7 +118,7 @@ fi
# stdin --> attached to pty # stdin --> attached to pty
# stdout --> /dev/null # stdout --> /dev/null
# stderr --> attached to pty # stderr --> attached to pty
attach=$( ( lxc-attach -n busy -- sh -c 'hostname >&2' > /dev/null ) 2>&1 || FAIL "to allocate or setup pty") attach=$( ( lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'hostname >&2' > /dev/null ) 2>&1 || FAIL "to allocate or setup pty")
if [ "$attach" != "busy" ]; then if [ "$attach" != "busy" ]; then
FAIL "lxc-attach -n busy -- sh -c 'hostname >&2' > /dev/null" FAIL "lxc-attach -n busy -- sh -c 'hostname >&2' > /dev/null"
fi fi
...@@ -126,7 +130,7 @@ fi ...@@ -126,7 +130,7 @@ fi
# stdin --> attached to pty # stdin --> attached to pty
# stdout --> attach to pty # stdout --> attach to pty
# stderr --> /dev/null # stderr --> /dev/null
attach=$( ( lxc-attach -n busy -- sh -c 'hostname >&2' 2> /dev/null ) 2>&1 || FAIL "to allocate or setup pty") attach=$( ( lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'hostname >&2' 2> /dev/null ) 2>&1 || FAIL "to allocate or setup pty")
if [ -n "$attach" ]; then if [ -n "$attach" ]; then
FAIL "lxc-attach -n busy -- sh -c 'hostname >&2' 2> /dev/null" FAIL "lxc-attach -n busy -- sh -c 'hostname >&2' 2> /dev/null"
fi fi
...@@ -136,7 +140,7 @@ fi ...@@ -136,7 +140,7 @@ fi
# stdout --> /dev/null # stdout --> /dev/null
# stderr --> attached to pty # stderr --> attached to pty
# (As we expect the exit code of the command to be 1 we ignore it.) # (As we expect the exit code of the command to be 1 we ignore it.)
attach=$(lxc-attach -n busy -- sh -c 'rm 2>&1' > /dev/null || true) attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'rm 2>&1' > /dev/null || true)
if [ -n "$attach" ]; then if [ -n "$attach" ]; then
FAIL "lxc-attach -n busy -- sh -c 'rm 2>&1' > /dev/null" FAIL "lxc-attach -n busy -- sh -c 'rm 2>&1' > /dev/null"
fi fi
...@@ -146,7 +150,7 @@ fi ...@@ -146,7 +150,7 @@ fi
# - stdout --> attached to pty # - stdout --> attached to pty
# - stderr --> /dev/null # - stderr --> /dev/null
# (As we expect the exit code of the command to be 1 we ignore it.) # (As we expect the exit code of the command to be 1 we ignore it.)
attach=$(lxc-attach -n busy -- sh -c 'rm 2>&1' 2> /dev/null || true) attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'rm 2>&1' 2> /dev/null || true)
if [ -z "$attach" ]; then if [ -z "$attach" ]; then
FAIL "lxc-attach -n busy -- sh -c 'rm 2>&1' 2> /dev/null" FAIL "lxc-attach -n busy -- sh -c 'rm 2>&1' 2> /dev/null"
fi fi
...@@ -154,7 +158,7 @@ fi ...@@ -154,7 +158,7 @@ fi
# stdin --> $in # stdin --> $in
# stdout --> attached to pty # stdout --> attached to pty
# stderr --> attached to pty # stderr --> attached to pty
attach=$(echo hostname | lxc-attach -n busy -- || FAIL "to allocate or setup pty") attach=$(echo hostname | lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- || FAIL "to allocate or setup pty")
if [ "$attach" != "busy" ]; then if [ "$attach" != "busy" ]; then
FAIL "echo hostname | lxc-attach -n busy --" FAIL "echo hostname | lxc-attach -n busy --"
fi fi
...@@ -165,7 +169,7 @@ fi ...@@ -165,7 +169,7 @@ fi
out=$(mktemp /tmp/out_XXXX) out=$(mktemp /tmp/out_XXXX)
err=$(mktemp /tmp/err_XXXX) err=$(mktemp /tmp/err_XXXX)
trap "rm -f $out $err" EXIT INT QUIT PIPE trap "rm -f $out $err" EXIT INT QUIT PIPE
lxc-attach -n busy -- sh -c 'echo OUT; echo ERR >&2' > $out 2> $err || FAIL "to allocate or setup pty" lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'echo OUT; echo ERR >&2' > $out 2> $err || FAIL "to allocate or setup pty"
outcontent=$(cat $out) outcontent=$(cat $out)
errcontent=$(cat $err) errcontent=$(cat $err)
if [ "$outcontent" != "OUT" ] || [ "$errcontent" != "ERR" ]; then if [ "$outcontent" != "OUT" ] || [ "$errcontent" != "ERR" ]; then
...@@ -181,7 +185,7 @@ rm -f $out $err ...@@ -181,7 +185,7 @@ rm -f $out $err
out=$(mktemp /tmp/out_XXXX) out=$(mktemp /tmp/out_XXXX)
err=$(mktemp /tmp/err_XXXX) err=$(mktemp /tmp/err_XXXX)
trap "rm -f $out $err" EXIT INT QUIT PIPE trap "rm -f $out $err" EXIT INT QUIT PIPE
echo "hostname; rm" | lxc-attach -n busy > $out 2> $err || true echo "hostname; rm" | lxc-attach -n busy -l trace -o "${ATTACH_LOG}" > $out 2> $err || true
outcontent=$(cat $out) outcontent=$(cat $out)
errcontent=$(cat $err) errcontent=$(cat $err)
if [ "$outcontent" != "busy" ] || [ -z "$errcontent" ]; then if [ "$outcontent" != "busy" ] || [ -z "$errcontent" ]; then
...@@ -191,5 +195,6 @@ fi ...@@ -191,5 +195,6 @@ fi
rm -f $out $err rm -f $out $err
lxc-destroy -n busy -f lxc-destroy -n busy -f
rm -f "${ATTACH_LOG}" || true
exit 0 exit 0
...@@ -87,6 +87,7 @@ cleanup() { ...@@ -87,6 +87,7 @@ cleanup() {
echo "FAIL" echo "FAIL"
exit 1 exit 1
fi fi
rm -f "${UNPRIV_LOG}" || true
echo "PASS" echo "PASS"
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment