[PATCH 1/3] wpa_supplicant: prevent work removal recursion
Benjamin Berg
benjamin at sipsolutions.net
Wed Feb 18 02:26:05 PST 2026
From: Benjamin Berg <benjamin.berg at intel.com>
The DPP deinit code will try to clean up the work when it is already
started. In the interest of code-reuse, this code will recursively
ensure that the work item is removed.
Guard against this type of recursion by unlinking the radio work from
the list before calling the callback with deinit set to 1. In the same
way, prevent a call to radio_work_done during removal to be a problem.
Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
Reviewed-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
wpa_supplicant/wpa_supplicant.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 353ea90e7d..0cadfc9bb7 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -7185,7 +7185,6 @@ static void radio_work_free(struct wpa_radio_work *work)
work->wpa_s->radio->num_active_works);
}
- dl_list_del(&work->list);
os_free(work);
}
@@ -7378,6 +7377,7 @@ void radio_remove_works(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
work->type, work, work->started ? " (started)" : "");
+ dl_list_del(&work->list);
work->cb(work, 1);
radio_work_free(work);
}
@@ -7397,6 +7397,7 @@ void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
continue;
wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
work->type, work, work->started ? " (started)" : "");
+ dl_list_del(&work->list);
radio_work_free(work);
break;
}
@@ -7422,6 +7423,7 @@ static void radio_remove_pending_connect(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "Remove radio work '%s'@%p ssid=%s",
work->type, work,
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ dl_list_del(&work->list);
work->cb(work, 1);
radio_work_free(work);
}
@@ -7557,11 +7559,16 @@ void radio_work_done(struct wpa_radio_work *work)
struct os_reltime now, diff;
unsigned int started = work->started;
+ /* If next is poisoned, then we are free'ing it already */
+ if (work->list.next == NULL)
+ return;
+
os_get_reltime(&now);
os_reltime_sub(&now, &work->time, &diff);
wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
work->type, work, started ? "done" : "canceled",
diff.sec, diff.usec);
+ dl_list_del(&work->list);
radio_work_free(work);
if (started)
radio_work_check_next(wpa_s);
--
2.53.0
More information about the Hostap
mailing list