From: Christian Brauner Date: Mon, 20 Nov 2017 21:16:40 +0000 (+0100) Subject: commands: fix state socket implementation X-Git-Tag: lxc-2.0.10~570 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=06485e3772c3dd5ebe84389078ec322a9663b024;p=thirdparty%2Flxc.git commands: fix state socket implementation Remove dead state clients from state client list. Consider the following scenario: 01 start container 02 issue shutdown request 03 state_client_fd is added to lxc_handler 03 container doesn't respond to shutdown request 04 user aborts shutdown request 05 lxc_cmd_fd_cleanup() removes state_client_fd from lxc_mainloop 06 invalid state_client_fd is still recorded in the lxc_handler 07 user issues lxc_cmd_stop() request via SIGKILL 08 container reaches STOPPED state and sends message to state_client_fd 09 state_client_fd number has been reused by lxc_cmd_stop_callback() 10 invalid data gets dumped to lxc_cmd_stop() Reproducer: Set an invalid shutdown signal to which the init system does not respond with a shutdown via lxc.signal.halt e.g. "lxc.signal.halt = SIGUSR1". Then do: 1. start container root@conventiont|~ > lxc-start -n a1 2. try to shutdown container root@conventiont|~ > lxc-stop -n a1 3. abort shutdown ^C 4. SIGKILL the container (lxc.signal.stop = SIGKILL) root@conventiont|~ > lxc-stop -n a1 -k lxc-stop: a1: commands.c: lxc_cmd_rsp_recv: 165 File too large - Response data for command "stop" is too long: 12641 bytes > 8192 To not let this happen we remove the state_client_fd from the lxc_handler when we detect a cleanup event in lxc_cmd_fd_cleanup(). Signed-off-by: Christian Brauner --- diff --git a/src/lxc/commands.c b/src/lxc/commands.c index e955236f7..d1ffecf41 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -948,11 +948,32 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, } 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) { + struct state_client *client; + struct lxc_list *cur, *next; + lxc_console_free(handler->conf, fd); lxc_mainloop_del_handler(descr, fd); - close(fd); + if (cmd != LXC_CMD_ADD_STATE_CLIENT) { + close(fd); + return; + } + + process_lock(); + lxc_list_for_each_safe(cur, &handler->state_clients, next) { + client = cur->elem; + if (client->clientfd != fd) + continue; + + /* kick client from list */ + close(client->clientfd); + lxc_list_del(cur); + free(cur->elem); + free(cur); + } + process_unlock(); } static int lxc_cmd_handler(int fd, uint32_t events, void *data, @@ -1021,7 +1042,7 @@ out: return ret; out_close: - lxc_cmd_fd_cleanup(fd, handler, descr); + lxc_cmd_fd_cleanup(fd, handler, descr, req.cmd); goto out; }