summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoravos <avos@FreeBSD.org>2016-06-20 22:39:32 +0000
committeravos <avos@FreeBSD.org>2016-06-20 22:39:32 +0000
commit39bab70fa61a7bb48f204c2cacbe2f14c50f942f (patch)
tree3ae87ae3fd4f95236cd12b7fd7d13a9c27a26c29
parent2fdd277a83f97fdad90c486e5e0babaf2b9b8d54 (diff)
downloadFreeBSD-src-39bab70fa61a7bb48f204c2cacbe2f14c50f942f.zip
FreeBSD-src-39bab70fa61a7bb48f204c2cacbe2f14c50f942f.tar.gz
urtwn: fix panic on device detach.
Remove frames from active/pending Tx queues and free related node references when vap is destroyed to prevent various use-after-free scenarios. Reported and tested by: Aleksander Alekseev <afiskon@devzen.ru> PR: 208632 Approved by: re (gjb)
-rw-r--r--sys/dev/urtwn/if_urtwn.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/sys/dev/urtwn/if_urtwn.c b/sys/dev/urtwn/if_urtwn.c
index 999bb6e..6ca31fa 100644
--- a/sys/dev/urtwn/if_urtwn.c
+++ b/sys/dev/urtwn/if_urtwn.c
@@ -208,6 +208,10 @@ static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *,
const uint8_t [IEEE80211_ADDR_LEN],
const uint8_t [IEEE80211_ADDR_LEN]);
static void urtwn_vap_delete(struct ieee80211vap *);
+static void urtwn_vap_clear_tx(struct urtwn_softc *,
+ struct ieee80211vap *);
+static void urtwn_vap_clear_tx_queue(struct urtwn_softc *,
+ urtwn_datahead *, struct ieee80211vap *);
static struct mbuf * urtwn_rx_copy_to_mbuf(struct urtwn_softc *,
struct r92c_rx_stat *, int);
static struct mbuf * urtwn_report_intr(struct usb_xfer *,
@@ -824,8 +828,16 @@ urtwn_vap_delete(struct ieee80211vap *vap)
struct urtwn_softc *sc = ic->ic_softc;
struct urtwn_vap *uvp = URTWN_VAP(vap);
+ /* Guarantee that nothing will go through this vap. */
+ ieee80211_new_state(vap, IEEE80211_S_INIT, -1);
+ ieee80211_draintask(ic, &vap->iv_nstate_task);
+
+ URTWN_LOCK(sc);
if (uvp->bcn_mbuf != NULL)
m_freem(uvp->bcn_mbuf);
+ /* Cancel any unfinished Tx. */
+ urtwn_vap_clear_tx(sc, vap);
+ URTWN_UNLOCK(sc);
if (vap->iv_opmode == IEEE80211_M_IBSS)
ieee80211_draintask(ic, &uvp->tsf_task_adhoc);
if (URTWN_CHIP_HAS_RATECTL(sc))
@@ -834,6 +846,41 @@ urtwn_vap_delete(struct ieee80211vap *vap)
free(uvp, M_80211_VAP);
}
+static void
+urtwn_vap_clear_tx(struct urtwn_softc *sc, struct ieee80211vap *vap)
+{
+
+ URTWN_ASSERT_LOCKED(sc);
+
+ urtwn_vap_clear_tx_queue(sc, &sc->sc_tx_active, vap);
+ urtwn_vap_clear_tx_queue(sc, &sc->sc_tx_pending, vap);
+}
+
+static void
+urtwn_vap_clear_tx_queue(struct urtwn_softc *sc, urtwn_datahead *head,
+ struct ieee80211vap *vap)
+{
+ struct urtwn_data *dp, *tmp;
+
+ STAILQ_FOREACH_SAFE(dp, head, next, tmp) {
+ if (dp->ni != NULL) {
+ if (dp->ni->ni_vap == vap) {
+ ieee80211_free_node(dp->ni);
+ dp->ni = NULL;
+
+ if (dp->m != NULL) {
+ m_freem(dp->m);
+ dp->m = NULL;
+ }
+
+ STAILQ_REMOVE(head, dp, urtwn_data, next);
+ STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, dp,
+ next);
+ }
+ }
+ }
+}
+
static struct mbuf *
urtwn_rx_copy_to_mbuf(struct urtwn_softc *sc, struct r92c_rx_stat *stat,
int totlen)
OpenPOWER on IntegriCloud