wifi: p54: validate firmware record lengths

The p54 firmware parser accesses component ID and component version
records without checking that their lengths cover the fields being read.
A malformed record can therefore make the parser read past the record.

Validate the component ID and component version record lengths before
accessing their data. The descriptor record is also checked against the
shortest descriptor length found in the supported firmware images.

Reject descriptor values that underflow the RX offset or produce an empty
RX range before updating the driver state.

Assisted-by: LLM Codex
Signed-off-by: Heyang Tan <thy15333007817@163.com>
Tested-by: Christian Lamparter <chunkeey@gmail.com>
Link: https://patch.msgid.link/20260918083349.891-1-thy15333007817@163.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Heyang Tan 2026-09-18 16:33:49 +08:00 committed by Johannes Berg
parent ee3aadc43e
commit db7b86bd97

View File

@ -52,6 +52,13 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
u32 code = le32_to_cpu(bootrec->code);
switch (code) {
case BR_CODE_COMPONENT_ID:
if (len < sizeof(struct bootrec_comp_id) /
sizeof(*bootrec->data)) {
wiphy_err(priv->hw->wiphy,
"firmware component ID is too short\n");
return -EINVAL;
}
priv->fw_interface = be32_to_cpup((__be32 *)
bootrec->data);
switch (priv->fw_interface) {
@ -72,16 +79,41 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
}
break;
case BR_CODE_COMPONENT_VERSION:
if (len < DIV_ROUND_UP(sizeof(struct bootrec_comp_ver),
sizeof(*bootrec->data))) {
wiphy_err(priv->hw->wiphy,
"firmware component version is too short\n");
return -EINVAL;
}
/* 24 bytes should be enough for all firmwares */
if (strnlen((unsigned char *) bootrec->data, 24) < 24)
fw_version = (unsigned char *) bootrec->data;
if (strnlen((unsigned char *)bootrec->data,
sizeof(struct bootrec_comp_ver)) <
sizeof(struct bootrec_comp_ver))
fw_version = (unsigned char *)bootrec->data;
break;
case BR_CODE_DESCR: {
struct bootrec_desc *desc =
(struct bootrec_desc *)bootrec->data;
priv->rx_start = le32_to_cpu(desc->rx_start);
/* FIXME add sanity checking */
priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
u32 rx_start, rx_end;
/* 0xa is the shortest descriptor in supported firmware. */
if (len < 0xa) {
wiphy_err(priv->hw->wiphy,
"firmware descriptor is too short\n");
return -EINVAL;
}
rx_start = le32_to_cpu(desc->rx_start);
rx_end = le32_to_cpu(desc->rx_end);
if (rx_end < 0x3500 || rx_end - 0x3500 <= rx_start) {
wiphy_err(priv->hw->wiphy,
"firmware descriptor has invalid RX range\n");
return -EINVAL;
}
priv->rx_start = rx_start;
priv->rx_end = rx_end - 0x3500;
priv->headroom = desc->headroom;
priv->tailroom = desc->tailroom;
priv->privacy_caps = desc->privacy_caps;