3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-29 13:59:24 +01:00

scan: Don't crash on scan_cancel

If scan_cancel is called on a scan_request that is 'finished' but with
the GET_SCAN command still in flight, it will trigger a crash as
follows:
Received Deauthentication event, reason: 2, from_ap: true
src/station.c:station_disconnect_event() 11
src/station.c:station_disassociated() 11
src/station.c:station_reset_connection_state() 11
src/station.c:station_roam_state_clear() 11
src/scan.c:scan_cancel() Trying to cancel scan id 6 for wdev 200000002
src/scan.c:scan_cancel() Scan is at the top of the queue, but not triggered
src/scan.c:get_scan_done() get_scan_done
Aborting (signal 11) [/home/denkenz/iwd-master/src/iwd]
++++++++ backtrace ++++++++
 #0  0x7f9871aef3f0 in /lib64/libc.so.6
 #1  0x41f470 in station_roam_scan_notify() at /home/denkenz/iwd-master/src/station.c:2285
 #2  0x43936a in scan_finished() at /home/denkenz/iwd-master/src/scan.c:1709
 #3  0x439495 in get_scan_done() at /home/denkenz/iwd-master/src/scan.c:1739
 #4  0x4bdef5 in destroy_request() at /home/denkenz/iwd-master/ell/genl.c:676
 #5  0x4c070b in l_genl_family_cancel() at /home/denkenz/iwd-master/ell/genl.c:1960
 #6  0x437069 in scan_cancel() at /home/denkenz/iwd-master/src/scan.c:842
 #7  0x41dc2e in station_roam_state_clear() at /home/denkenz/iwd-master/src/station.c:1594
 #8  0x41dd2b in station_reset_connection_state() at /home/denkenz/iwd-master/src/station.c:1619
 #9  0x41dea4 in station_disassociated() at /home/denkenz/iwd-master/src/station.c:1644

The happens because get_scan_done callback is still called as a result of
l_genl_cancel.  Add a re-entrancy guard in the form of 'canceled'
variable in struct scan_request.  If set, get_scan_done will skip invoking
scan_finished.

It isn't clear what 'l_queue_peek_head() == results->sr' check was trying
to accomplish.  If GET_SCAN dump was scheduled, then it should be
reported.  Drop it.
This commit is contained in:
Denis Kenzior 2022-01-19 16:00:41 -06:00
parent e1593df4bd
commit af375a1cde

View File

@ -79,6 +79,7 @@ struct scan_request {
scan_notify_func_t callback; scan_notify_func_t callback;
void *userdata; void *userdata;
scan_destroy_func_t destroy; scan_destroy_func_t destroy;
bool canceled : 1; /* Is scan_cancel being called on this request? */
bool passive:1; /* Active or Passive scan? */ bool passive:1; /* Active or Passive scan? */
struct l_queue *cmds; struct l_queue *cmds;
/* The time the current scan was started. Reported in TRIGGER_SCAN */ /* The time the current scan was started. Reported in TRIGGER_SCAN */
@ -833,6 +834,9 @@ bool scan_cancel(uint64_t wdev_id, uint32_t id)
if (sr == l_queue_peek_head(sc->requests)) { if (sr == l_queue_peek_head(sc->requests)) {
l_debug("Scan is at the top of the queue, but not triggered"); l_debug("Scan is at the top of the queue, but not triggered");
/* l_genl_family_cancel will trigger destroy callbacks */
sr->canceled = true;
if (sc->start_cmd_id) if (sc->start_cmd_id)
l_genl_family_cancel(nl80211, sc->start_cmd_id); l_genl_family_cancel(nl80211, sc->start_cmd_id);
@ -1735,7 +1739,7 @@ static void get_scan_done(void *user)
sc->get_scan_cmd_id = 0; sc->get_scan_cmd_id = 0;
if (!results->sr || l_queue_peek_head(sc->requests) == results->sr) if (!results->sr || !results->sr->canceled)
scan_finished(sc, 0, results->bss_list, scan_finished(sc, 0, results->bss_list,
results->freqs, results->sr); results->freqs, results->sr);
else else