]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: Avoid infinite loop with radio_remove_works(p2p-listen)
authorShivani Baranwal <quic_shivbara@quicinc.com>
Fri, 27 Sep 2024 08:17:02 +0000 (13:47 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 28 Nov 2024 20:59:09 +0000 (22:59 +0200)
Commit 3242793cb8df ("P2P: Remove pending p2p-listen radio work on
stopping listen") added removal of all pending p2p-listen radio works
when P2P listen is stopped. It looks like there is a possible code path
that results in wpas_p2p_listen_work_done() not being able to mark the
possibly pending and already started p2p-listen radio work completed.

It is not clear what exactly could cause this, but if something manages
to clear wpa_s->p2p_listen_work, this could happen. Theoretically,
having two started p2p-listen works might also cause something like
this, but that should not happen either. In any case, if this happens,
the call to radio_remove_works() from wpas_stop_listen() would end up
calling the radio work callback handler (i.e., wpas_start_listen_cb() in
this case) to deinit the work for the same work multiple times and if
that radio work item has been started, this would result in a recursive
call back to wpas_stop_listen() and infinite recursion killing the
process.

Even though the desired fix would be to get rid of whatever ends up
messing up wpa_s->p2p_listen_work, it is not clear what that could be.
Regardless, since this has show up in testing, recover from this cleanly
without hitting infinite recursion.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index dab64971e56498af20ce25d93609e5278d4323d0..2eadf5ef5d8e1299ad31dd4780ca316c1fea0ff4 100644 (file)
@@ -3224,10 +3224,13 @@ static void wpas_stop_listen(void *ctx)
 
        wpas_p2p_listen_work_done(wpa_s);
 
-       if (radio_work_pending(wpa_s, "p2p-listen")) {
+       if (!wpa_s->p2p_removing_listen_work &&
+           radio_work_pending(wpa_s, "p2p-listen")) {
+               wpa_s->p2p_removing_listen_work = true;
                wpa_printf(MSG_DEBUG,
                           "P2P: p2p-listen is still pending - remove it");
                radio_remove_works(wpa_s, "p2p-listen", 0);
+               wpa_s->p2p_removing_listen_work = false;
        }
 }
 
index c6ae8c37e2215136e24a2c77e04987e7fae8bd46..38ad4857ca285f9ccbdc00fd5bd7afb8bc948e96 100644 (file)
@@ -1189,6 +1189,7 @@ struct wpa_supplicant {
        struct wpa_radio_work *p2p_scan_work;
        struct wpa_radio_work *p2p_listen_work;
        struct wpa_radio_work *p2p_send_action_work;
+       bool p2p_removing_listen_work;
 
        u16 p2p_oob_dev_pw_id; /* OOB Device Password Id for group formation */
        struct wpabuf *p2p_oob_dev_pw; /* OOB Device Password for group