gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] 02/02: UTIL: fix #8786 (use-after-free during shutdown)


From: gnunet
Subject: [gnunet] 02/02: UTIL: fix #8786 (use-after-free during shutdown)
Date: Wed, 08 May 2024 18:04:35 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

commit db2eb78ec9bade0c6779bdd76a49021a900fcd6b
Author: Christian Grothoff <grothoff@gnunet.org>
AuthorDate: Wed May 8 14:52:39 2024 +0200

    UTIL: fix #8786 (use-after-free during shutdown)
---
 src/lib/util/service.c | 119 ++++++++++++++++++++++++++-----------------------
 1 file changed, 63 insertions(+), 56 deletions(-)

diff --git a/src/lib/util/service.c b/src/lib/util/service.c
index 7ed61919f..363210c61 100644
--- a/src/lib/util/service.c
+++ b/src/lib/util/service.c
@@ -350,7 +350,7 @@ struct GNUNET_SERVICE_Client
  * monitoring.
  *
  * @param sh service to check clients for
- * @return #GNUNET_YES if we have non-monitoring clients left
+ * @return true if we have non-monitoring clients left
  */
 static enum GNUNET_GenericReturnValue
 have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
@@ -359,11 +359,13 @@ have_non_monitor_clients (struct GNUNET_SERVICE_Handle 
*sh)
        NULL != client;
        client = client->next)
   {
+    if (NULL != client->drop_task)
+      continue;
     if (client->is_monitor)
       continue;
-    return GNUNET_YES;
+    return true;
   }
-  return GNUNET_NO;
+  return false;
 }
 
 
@@ -419,7 +421,7 @@ service_shutdown (void *cls)
   case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
     if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
       do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
-    if (GNUNET_NO == have_non_monitor_clients (sh))
+    if (! have_non_monitor_clients (sh))
       GNUNET_SERVICE_shutdown (sh);
     break;
   }
@@ -1892,6 +1894,46 @@ GNUNET_SERVICE_start (const char *service_name,
 }
 
 
+/**
+ * Asynchronously finish dropping the client.
+ *
+ * @param cls the `struct GNUNET_SERVICE_Client`.
+ */
+static void
+finish_client_drop (void *cls)
+{
+  struct GNUNET_SERVICE_Client *c = cls;
+  struct GNUNET_SERVICE_Handle *sh = c->sh;
+
+  c->drop_task = NULL;
+  GNUNET_CONTAINER_DLL_remove (sh->clients_head,
+                               sh->clients_tail,
+                               c);
+  GNUNET_assert (NULL == c->send_task);
+  GNUNET_assert (NULL == c->recv_task);
+  GNUNET_assert (NULL == c->warn_task);
+  GNUNET_MST_destroy (c->mst);
+  GNUNET_MQ_destroy (c->mq);
+  if (! c->persist)
+  {
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_NETWORK_socket_close (c->sock));
+    if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
+        (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
+      do_resume (sh,
+                 SUSPEND_STATE_EMFILE);
+  }
+  else
+  {
+    GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
+  }
+  GNUNET_free (c);
+  if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
+      (! have_non_monitor_clients (sh)))
+    GNUNET_SERVICE_shutdown (sh);
+}
+
+
 void
 GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
 {
@@ -1899,7 +1941,12 @@ GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
 
   GNUNET_SERVICE_suspend (srv);
   while (NULL != (client = srv->clients_head))
-    GNUNET_SERVICE_client_drop (client);
+  {
+    if (NULL == client->drop_task)
+      GNUNET_SERVICE_client_drop (client);
+    GNUNET_SCHEDULER_cancel (client->drop_task);
+    finish_client_drop (client);
+  }
   teardown_service (srv);
   GNUNET_free (srv->handlers);
   GNUNET_free (srv);
@@ -2433,42 +2480,6 @@ GNUNET_SERVICE_client_disable_continue_warning (struct 
GNUNET_SERVICE_Client *c)
 }
 
 
-/**
- * Asynchronously finish dropping the client.
- *
- * @param cls the `struct GNUNET_SERVICE_Client`.
- */
-static void
-finish_client_drop (void *cls)
-{
-  struct GNUNET_SERVICE_Client *c = cls;
-  struct GNUNET_SERVICE_Handle *sh = c->sh;
-
-  c->drop_task = NULL;
-  GNUNET_assert (NULL == c->send_task);
-  GNUNET_assert (NULL == c->recv_task);
-  GNUNET_assert (NULL == c->warn_task);
-  GNUNET_MST_destroy (c->mst);
-  GNUNET_MQ_destroy (c->mq);
-  if (! c->persist)
-  {
-    GNUNET_break (GNUNET_OK ==
-                  GNUNET_NETWORK_socket_close (c->sock));
-    if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
-        (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
-      do_resume (sh, SUSPEND_STATE_EMFILE);
-  }
-  else
-  {
-    GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
-  }
-  GNUNET_free (c);
-  if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
-      (GNUNET_NO == have_non_monitor_clients (sh)))
-    GNUNET_SERVICE_shutdown (sh);
-}
-
-
 void
 GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
 {
@@ -2493,15 +2504,7 @@ GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client 
*c)
            backtrace_strings[i]);
   }
 #endif
-  if (NULL != c->drop_task)
-  {
-    /* asked to drop twice! */
-    GNUNET_assert (0);
-    return;
-  }
-  GNUNET_CONTAINER_DLL_remove (sh->clients_head,
-                               sh->clients_tail,
-                               c);
+  GNUNET_assert (NULL == c->drop_task);
   if (NULL != sh->disconnect_cb)
     sh->disconnect_cb (sh->cb_cls,
                        c,
@@ -2529,12 +2532,16 @@ GNUNET_SERVICE_client_drop (struct 
GNUNET_SERVICE_Client *c)
 void
 GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
 {
-  struct GNUNET_SERVICE_Client *client;
-
   if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
-    do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
-  while (NULL != (client = sh->clients_head))
-    GNUNET_SERVICE_client_drop (client);
+    do_suspend (sh,
+                SUSPEND_STATE_SHUTDOWN);
+  for (struct GNUNET_SERVICE_Client *client = sh->clients_head;
+       NULL != client;
+       client = client->next)
+  {
+    if (NULL == client->drop_task)
+      GNUNET_SERVICE_client_drop (client);
+  }
 }
 
 
@@ -2543,7 +2550,7 @@ GNUNET_SERVICE_client_mark_monitor (struct 
GNUNET_SERVICE_Client *c)
 {
   c->is_monitor = true;
   if (((0 != (SUSPEND_STATE_SHUTDOWN & c->sh->suspend_state)) &&
-       (GNUNET_NO == have_non_monitor_clients (c->sh))))
+       (! have_non_monitor_clients (c->sh))))
     GNUNET_SERVICE_shutdown (c->sh);
 }
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]