git: aff56b4f0b25 - main - net80211: fix a race between ieee80211_sta_join and scan entries
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 05 May 2025 14:59:10 UTC
The branch main has been updated by bz:
URL: https://cgit.FreeBSD.org/src/commit/?id=aff56b4f0b25c44c9c2cae9a3f816c4277057a71
commit aff56b4f0b25c44c9c2cae9a3f816c4277057a71
Author: Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-16 19:10:58 +0000
Commit: Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-05-05 14:58:59 +0000
net80211: fix a race between ieee80211_sta_join and scan entries
We were seeing panics during ieee80211_sta_join() which seemed that
the ni->ni_chan was not valid anymore, which was true.
We also saw errors indicating data put into ni_ies became inalid.
The problem was that the ieee80211_scan_entry passed into
ieee80211_sta_join() (in the observed case from setmlme_assoc_sta())
became invalid during ieee80211_alloc_node().
As a result for the ni_chan case the the rateset and len in rates[1]
became invalid. Similarly for the IEs.
Make a (deep)copy of the scan entry in setmlme_assoc_sta() and return
the copy as once we leave ieee80211_scan_iterate() we can no longer
rely on the scan entry to be valid.
Sponsored by: The FreeBSD Foundation
MFC after: 3 days
Reported by: rm, ziaee, bz
Tested by: rm, ziaee, bz
PR: 286063
Reviewed by: adrian (,emaste)
Differential Revision: https://reviews.freebsd.org/D49865
---
sys/net80211/ieee80211_ioctl.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index caa0c77e2897..6c30325e5e32 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -1530,7 +1530,8 @@ struct scanlookup {
const uint8_t *mac;
int esslen;
const uint8_t *essid;
- const struct ieee80211_scan_entry *se;
+ bool found;
+ struct ieee80211_scan_entry se;
};
/*
@@ -1540,6 +1541,10 @@ static void
mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
{
struct scanlookup *look = arg;
+ int rv;
+
+ if (look->found)
+ return;
if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
return;
@@ -1549,7 +1554,14 @@ mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
if (memcmp(look->essid, se->se_ssid+2, look->esslen))
return;
}
- look->se = se;
+ /*
+ * First copy everything and then ensure we get our own copy of se_ies. */
+ look->se = *se;
+ look->se.se_ies.data = 0;
+ look->se.se_ies.len = 0;
+ rv = ieee80211_ies_init(&look->se.se_ies, se->se_ies.data, se->se_ies.len);
+ if (rv != 0) /* No error */
+ look->found = true;
}
static int
@@ -1558,21 +1570,25 @@ setmlme_assoc_sta(struct ieee80211vap *vap,
const uint8_t ssid[IEEE80211_NWID_LEN])
{
struct scanlookup lookup;
+ int rv;
KASSERT(vap->iv_opmode == IEEE80211_M_STA,
("expected opmode STA not %s",
ieee80211_opmode_name[vap->iv_opmode]));
/* NB: this is racey if roaming is !manual */
- lookup.se = NULL;
lookup.mac = mac;
lookup.esslen = ssid_len;
lookup.essid = ssid;
+ memset(&lookup.se, 0, sizeof(lookup.se));
+ lookup.found = false;
ieee80211_scan_iterate(vap, mlmelookup, &lookup);
- if (lookup.se == NULL)
+ if (!lookup.found)
return ENOENT;
mlmedebug(vap, mac, IEEE80211_MLME_ASSOC, 0);
- if (!ieee80211_sta_join(vap, lookup.se->se_chan, lookup.se))
+ rv = ieee80211_sta_join(vap, lookup.se.se_chan, &lookup.se);
+ ieee80211_ies_cleanup(&lookup.se.se_ies);
+ if (rv == 0)
return EIO; /* XXX unique but could be better */
return 0;
}