]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
boot-server: Handle client disconnecting while trigger pending
authorRay Strode <rstrode@redhat.com>
Wed, 2 Sep 2020 17:44:37 +0000 (13:44 -0400)
committerRay Strode <halfline@gmail.com>
Fri, 18 Sep 2020 20:48:59 +0000 (20:48 +0000)
At the moment if a client disconnects while the daemon is completely
an asynchronous request, the daemon crashes trying to access a freed
connection object.

This commit changes the boot server code to keep the connection object
alive after the client disconnects, if there's pending work to do.

https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/125

src/ply-boot-server.c

index 0e85e748561752d9edacd0b0a83cd706ce29d92d..173063f715db6f0503f2e72cc17cb0866498e295 100644 (file)
@@ -50,6 +50,7 @@ typedef struct
         int                reference_count;
 
         uint32_t           credentials_read : 1;
+        uint32_t           disconnected : 1;
 } ply_boot_connection_t;
 
 struct _ply_boot_server
@@ -315,30 +316,43 @@ ply_boot_connection_on_password_answer (ply_boot_connection_t *connection,
 {
         ply_trace ("got password answer");
 
-        ply_boot_connection_send_answer (connection, password);
+        if (!connection->disconnected)
+                ply_boot_connection_send_answer (connection, password);
+
         if (password != NULL)
                 ply_list_append_data (connection->server->cached_passwords,
                                       strdup (password));
+
+        ply_boot_connection_drop_reference (connection);
 }
 
 static void
 ply_boot_connection_on_deactivated (ply_boot_connection_t *connection)
 {
         ply_trace ("deactivated");
-        if (!ply_write (connection->fd,
-                        PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
-                        strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
-                ply_trace ("could not finish writing deactivate reply: %m");
+
+        if (!connection->disconnected) {
+                if (!ply_write (connection->fd,
+                                PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
+                                strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
+                        ply_trace ("could not finish writing deactivate reply: %m");
+        }
+
+        ply_boot_connection_drop_reference (connection);
 }
 
 static void
 ply_boot_connection_on_quit_complete (ply_boot_connection_t *connection)
 {
         ply_trace ("quit complete");
-        if (!ply_write (connection->fd,
-                        PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
-                        strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
-                ply_trace ("could not finish writing quit reply: %m");
+        if (!connection->disconnected) {
+                if (!ply_write (connection->fd,
+                                PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
+                                strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
+                        ply_trace ("could not finish writing quit reply: %m");
+        }
+
+        ply_boot_connection_drop_reference (connection);
 }
 
 static void
@@ -346,7 +360,10 @@ ply_boot_connection_on_question_answer (ply_boot_connection_t *connection,
                                         const char            *answer)
 {
         ply_trace ("got question answer: %s", answer);
-        ply_boot_connection_send_answer (connection, answer);
+        if (!connection->disconnected)
+                ply_boot_connection_send_answer (connection, answer);
+
+        ply_boot_connection_drop_reference (connection);
 }
 
 static void
@@ -354,7 +371,10 @@ ply_boot_connection_on_keystroke_answer (ply_boot_connection_t *connection,
                                          const char            *key)
 {
         ply_trace ("got key: %s", key);
-        ply_boot_connection_send_answer (connection, key);
+        if (!connection->disconnected)
+                ply_boot_connection_send_answer (connection, key);
+
+        ply_boot_connection_drop_reference (connection);
 }
 
 static void
@@ -487,6 +507,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
                                          (ply_trigger_handler_t)
                                          ply_boot_connection_on_deactivated,
                                          connection);
+                ply_boot_connection_take_reference (connection);
 
                 if (server->deactivate_handler != NULL)
                         server->deactivate_handler (server->user_data, deactivate_trigger, server);
@@ -514,6 +535,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
                                          (ply_trigger_handler_t)
                                          ply_boot_connection_on_quit_complete,
                                          connection);
+                ply_boot_connection_take_reference (connection);
 
                 if (server->quit_handler != NULL)
                         server->quit_handler (server->user_data, retain_splash, quit_trigger, server);
@@ -533,6 +555,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
                                          (ply_trigger_handler_t)
                                          ply_boot_connection_on_password_answer,
                                          connection);
+                ply_boot_connection_take_reference (connection);
 
                 if (server->ask_for_password_handler != NULL) {
                         server->ask_for_password_handler (server->user_data,
@@ -617,6 +640,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
                                          (ply_trigger_handler_t)
                                          ply_boot_connection_on_question_answer,
                                          connection);
+                ply_boot_connection_take_reference (connection);
 
                 if (server->ask_question_handler != NULL) {
                         server->ask_question_handler (server->user_data,
@@ -649,6 +673,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
                                          (ply_trigger_handler_t)
                                          ply_boot_connection_on_keystroke_answer,
                                          connection);
+                ply_boot_connection_take_reference (connection);
 
                 if (server->watch_for_keystroke_handler != NULL) {
                         server->watch_for_keystroke_handler (server->user_data,
@@ -730,6 +755,8 @@ ply_boot_connection_on_hangup (ply_boot_connection_t *connection)
         assert (connection != NULL);
         assert (connection->server != NULL);
 
+        connection->disconnected = true;
+
         server = connection->server;
 
         node = ply_list_find_node (server->connections, connection);