]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
commands: fix state socket implementation
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 20 Nov 2017 21:16:40 +0000 (22:16 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 20 Nov 2017 22:28:07 +0000 (23:28 +0100)
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 <christian.brauner@ubuntu.com>
src/lxc/commands.c

index e955236f7ba628f2465f9576c55c91c56beac9ce..d1ffecf41254cc09c28b0d6a620689abb4aebaa5 100644 (file)
@@ -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;
 }