From a2c770294acffc60661a567d7bc6706166a81654 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 17 Dec 2019 21:34:38 +0000 Subject: [PATCH] an(4): Require privileges for all SIOCGAIRONET requests. SIOCGAIRONET allows userspace to query an(4) for various device properties and configuration, which appears to potentially include sensitive information such as WEP keys (an(4) seems to predate WPA). Also avoid races by copying in the request structure to a temporary buffer before locking and modifying the device softc. Reported by: Ilja Van Sprundel MFC after: 3 days Sponsored by: The FreeBSD Foundation --- sys/dev/an/if_an.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c index a2418e4119cd..70866f1d002b 100644 --- a/sys/dev/an/if_an.c +++ b/sys/dev/an/if_an.c @@ -1875,6 +1875,7 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) int len; int i, max; struct an_softc *sc; + struct an_req *areq; struct ifreq *ifr; struct thread *td = curthread; struct ieee80211req *ireq; @@ -1934,17 +1935,21 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = 0; break; case SIOCGAIRONET: - error = copyin(ifr_data_get_ptr(ifr), &sc->areq, - sizeof(sc->areq)); - if (error != 0) + error = priv_check(td, PRIV_DRIVER); + if (error) break; + areq = malloc(sizeof(*areq), M_TEMP, M_WAITOK); + error = copyin(ifr_data_get_ptr(ifr), areq, sizeof(*areq)); + if (error != 0) { + free(areq, M_TEMP); + break; + } AN_LOCK(sc); + memcpy(&sc->areq, areq, sizeof(sc->areq)); #ifdef ANCACHE if (sc->areq.an_type == AN_RID_ZERO_CACHE) { - error = priv_check(td, PRIV_DRIVER); - if (error) - break; sc->an_sigitems = sc->an_nextitem = 0; + free(areq, M_TEMP); break; } else if (sc->areq.an_type == AN_RID_READ_CACHE) { char *pt = (char *)&sc->areq.an_val; @@ -1960,12 +1965,14 @@ an_ioctl(struct ifnet *ifp, u_long command, caddr_t data) #endif if (an_read_record(sc, (struct an_ltv_gen *)&sc->areq)) { AN_UNLOCK(sc); + free(areq, M_TEMP); error = EINVAL; break; } + memcpy(areq, &sc->areq, sizeof(*areq)); AN_UNLOCK(sc); - error = copyout(&sc->areq, ifr_data_get_ptr(ifr), - sizeof(sc->areq)); + error = copyout(areq, ifr_data_get_ptr(ifr), sizeof(*areq)); + free(areq, M_TEMP); break; case SIOCSAIRONET: if ((error = priv_check(td, PRIV_DRIVER)))