]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Flush pending control interface message for an interface to be removed
authorJouni Malinen <jouni@codeaurora.org>
Thu, 4 Feb 2021 22:28:17 +0000 (00:28 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 25 Mar 2021 22:21:18 +0000 (00:21 +0200)
wpa_supplicant_ctrl_iface_deinit() was executed only if the
per-interface control interface initialization had been completed. This
is not the case if driver initialization fails and that could result in
leaving behind references to the freed wpa_s instance in a corner case
where control interface messages ended up getting queued.

Fix this by calling wpa_supplicant_ctrl_iface_deinit() in all cases to
cancel the potential eloop timeout for wpas_ctrl_msg_queue_timeout with
the reference to the wpa_s pointer. In addition, flush any pending
message from the global queue for this interface since such a message
cannot be of use after this and there is no need to leave them in the
queue until the global control interface gets deinitialized.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
wpa_supplicant/ctrl_iface.h
wpa_supplicant/ctrl_iface_named_pipe.c
wpa_supplicant/ctrl_iface_udp.c
wpa_supplicant/ctrl_iface_unix.c
wpa_supplicant/eapol_test.c
wpa_supplicant/preauth_test.c
wpa_supplicant/wpa_supplicant.c

index 510668d49353eff2b83d726ed03f5d3884bfa48e..dfbd25a03b1b077a93d6d3e4d547f30887b2dcdb 100644 (file)
@@ -70,14 +70,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
 
 /**
  * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface
+ * @wpa_s: Pointer to wpa_supplicant data
  * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
  *
  * Deinitialize the control interface that was initialized with
- * wpa_supplicant_ctrl_iface_init().
+ * wpa_supplicant_ctrl_iface_init() and any data related to the wpa_s instance.
+ * @priv may be %NULL if the control interface has not yet been initialized.
  *
  * Required to be implemented in each control interface backend.
  */
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+                                     struct ctrl_iface_priv *priv);
 
 /**
  * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor
@@ -128,7 +131,8 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 }
 
 static inline void
-wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+                                struct ctrl_iface_priv *priv)
 {
 }
 
index 79ff7871db8d4443db38df1f284ed15e03e50679..bddc0414245ef7e7cb95ef44ea058fbcc5e10aa9 100644 (file)
@@ -462,8 +462,11 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 }
 
 
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+                                     struct ctrl_iface_priv *priv)
 {
+       if (!priv)
+               return;
        while (priv->ctrl_dst)
                ctrl_close_pipe(priv->ctrl_dst);
        if (priv->sec_attr_set)
index 1512080d6b3b772e73a7c5fce3e7c7c0754d3c10..1cbf7fa28d3f9bdd7ff508b8c85654b9f474d063 100644 (file)
@@ -490,8 +490,12 @@ fail:
 }
 
 
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+                                     struct ctrl_iface_priv *priv)
 {
+       if (!priv)
+               return;
+
        if (priv->sock > -1) {
                eloop_unregister_read_sock(priv->sock);
                if (priv->ctrl_dst) {
index 953fd2ccfe50a1ad6cbc1c1343da37d87ef2a449..639573dae75ea99c7468207987d39d2676b6ee53 100644 (file)
@@ -800,12 +800,52 @@ static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
 }
 
 
-void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+static void
+wpas_global_ctrl_iface_flush_queued_msg(struct wpa_global *global,
+                                       struct wpa_supplicant *wpa_s)
+{
+       struct ctrl_iface_global_priv *gpriv;
+       struct ctrl_iface_msg *msg, *prev_msg;
+       unsigned int count = 0;
+
+       if (!global || !global->ctrl_iface)
+               return;
+
+       gpriv = global->ctrl_iface;
+       dl_list_for_each_safe(msg, prev_msg, &gpriv->msg_queue,
+                             struct ctrl_iface_msg, list) {
+               if (msg->wpa_s == wpa_s) {
+                       count++;
+                       dl_list_del(&msg->list);
+                       os_free(msg);
+               }
+       }
+
+       if (count) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: Dropped %u pending message(s) for interface that is being removed",
+                       count);
+       }
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
+                                     struct ctrl_iface_priv *priv)
 {
        struct wpa_ctrl_dst *dst, *prev;
        struct ctrl_iface_msg *msg, *prev_msg;
        struct ctrl_iface_global_priv *gpriv;
 
+       if (!priv) {
+               /* Control interface has not yet been initialized, so there is
+                * nothing to deinitialize here. However, there might be a
+                * pending message for this interface, so get rid of any such
+                * entry before completing interface removal. */
+               wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s);
+               eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, wpa_s, NULL);
+               return;
+       }
+
        if (priv->sock > -1) {
                char *fname;
                char *buf, *dir = NULL;
@@ -877,6 +917,7 @@ free_dst:
                        }
                }
        }
+       wpas_global_ctrl_iface_flush_queued_msg(wpa_s->global, wpa_s);
        eloop_cancel_timeout(wpas_ctrl_msg_queue_timeout, priv->wpa_s, NULL);
        os_free(priv);
 }
index d137ad6ac5abe20786be063ae7cb1c133b64f76c..e256ac50eec425c3c456961bdcb77a6125e5e856 100644 (file)
@@ -674,10 +674,8 @@ static void test_eapol_clean(struct eapol_test_data *e,
        os_free(e->radius_conf);
        e->radius_conf = NULL;
        scard_deinit(wpa_s->scard);
-       if (wpa_s->ctrl_iface) {
-               wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-               wpa_s->ctrl_iface = NULL;
-       }
+       wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
+       wpa_s->ctrl_iface = NULL;
 
        ext_password_deinit(wpa_s->ext_pw);
        wpa_s->ext_pw = NULL;
index de49948f71e48c4a2f65703bb216313b72c07dab..97c16fb80d2768584adf3bfcb3da8281377373da 100644 (file)
@@ -193,10 +193,8 @@ static void test_eapol_clean(struct wpa_supplicant *wpa_s)
        pmksa_candidate_free(wpa_s->wpa);
        wpa_sm_deinit(wpa_s->wpa);
        scard_deinit(wpa_s->scard);
-       if (wpa_s->ctrl_iface) {
-               wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-               wpa_s->ctrl_iface = NULL;
-       }
+       wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
+       wpa_s->ctrl_iface = NULL;
        wpa_config_free(wpa_s->conf);
 }
 
index 90e8a466aba29f55aa02c07ce2ec3063922c2a32..835b33575760599bd06dd65ff2ccf938c75797b4 100644 (file)
@@ -1158,8 +1158,8 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
                    os_strcmp(conf->ctrl_interface,
                              wpa_s->conf->ctrl_interface) != 0);
 
-       if (reconf_ctrl && wpa_s->ctrl_iface) {
-               wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+       if (reconf_ctrl) {
+               wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
                wpa_s->ctrl_iface = NULL;
        }
 
@@ -6748,10 +6748,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
        if (terminate)
                wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
 
-       if (wpa_s->ctrl_iface) {
-               wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
-               wpa_s->ctrl_iface = NULL;
-       }
+       wpa_supplicant_ctrl_iface_deinit(wpa_s, wpa_s->ctrl_iface);
+       wpa_s->ctrl_iface = NULL;
 
 #ifdef CONFIG_MESH
        if (wpa_s->ifmsh) {