rsu: Don't modify read-only firmware block.

The firmware header loaded into an rsu(4) device has to be customized
to reflect device settings.  The driver was overwriting the header
from the shared firmware image before sending it to the device.  If
two devices attached at the same time with different settings, one
device could potentially get a corrupted header.  The recent changes
in a095390344 exposed this bug in the
form of a panic as the firmware blobs are now marked read-only in
object files and mapped read-only by the kernel.

To avoid the bug, change the driver to allocate a copy of the firmware
header on the stack that is initialized before writing it to the
device.

PR:		252163
Reported by:	vidwer+fbsdbugs@gmail.com
Tested by:	vidwer+fbsdbugs@gmail.com
Reviewed by:	hselasky, bz, emaste
Sponsored by:	DARPA
Differential Revision:	https://reviews.freebsd.org/D27850
This commit is contained in:
John Baldwin 2020-12-30 15:18:02 -08:00
parent 4f250d9436
commit 282381aa53

View File

@ -3343,7 +3343,7 @@ static int
rsu_load_firmware(struct rsu_softc *sc)
{
const struct r92s_fw_hdr *hdr;
struct r92s_fw_priv *dmem;
struct r92s_fw_priv dmem;
struct ieee80211com *ic = &sc->sc_ic;
const uint8_t *imem, *emem;
uint32_t imemsz, ememsz;
@ -3389,7 +3389,7 @@ rsu_load_firmware(struct rsu_softc *sc)
hdr->minute);
/* Make sure that driver and firmware are in sync. */
if (hdr->privsz != htole32(sizeof(*dmem))) {
if (hdr->privsz != htole32(sizeof(dmem))) {
device_printf(sc->sc_dev, "unsupported firmware image\n");
error = EINVAL;
goto fail;
@ -3475,24 +3475,23 @@ rsu_load_firmware(struct rsu_softc *sc)
}
/* Update DMEM section before loading. */
dmem = __DECONST(struct r92s_fw_priv *, &hdr->priv);
memset(dmem, 0, sizeof(*dmem));
dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172;
dmem->nendpoints = sc->sc_nendpoints;
dmem->chip_version = sc->cut;
dmem->rf_config = sc->sc_rftype;
dmem->vcs_type = R92S_VCS_TYPE_AUTO;
dmem->vcs_mode = R92S_VCS_MODE_RTS_CTS;
dmem->turbo_mode = 0;
dmem->bw40_en = !! (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40);
dmem->amsdu2ampdu_en = !! (sc->sc_ht);
dmem->ampdu_en = !! (sc->sc_ht);
dmem->agg_offload = !! (sc->sc_ht);
dmem->qos_en = 1;
dmem->ps_offload = 1;
dmem->lowpower_mode = 1; /* XXX TODO: configurable? */
memset(&dmem, 0, sizeof(dmem));
dmem.hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172;
dmem.nendpoints = sc->sc_nendpoints;
dmem.chip_version = sc->cut;
dmem.rf_config = sc->sc_rftype;
dmem.vcs_type = R92S_VCS_TYPE_AUTO;
dmem.vcs_mode = R92S_VCS_MODE_RTS_CTS;
dmem.turbo_mode = 0;
dmem.bw40_en = !! (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40);
dmem.amsdu2ampdu_en = !! (sc->sc_ht);
dmem.ampdu_en = !! (sc->sc_ht);
dmem.agg_offload = !! (sc->sc_ht);
dmem.qos_en = 1;
dmem.ps_offload = 1;
dmem.lowpower_mode = 1; /* XXX TODO: configurable? */
/* Load DMEM section. */
error = rsu_fw_loadsection(sc, (uint8_t *)dmem, sizeof(*dmem));
error = rsu_fw_loadsection(sc, (uint8_t *)&dmem, sizeof(dmem));
if (error != 0) {
device_printf(sc->sc_dev,
"could not load firmware section %s\n", "DMEM");