wifi: p54: validate curve data length in the calibration curve converters

p54_convert_rev0() and p54_convert_rev1() read calibration curve
data from the device-supplied EEPROM entry using channel and
points-per-channel counts taken verbatim from that same entry, so
an entry that declares more data than it carries drives an
out-of-bounds read past the EEPROM buffer (verified with a KASAN
reproducer of the conversion loop). The sibling converters
p54_convert_output_limits() and p54_convert_db() already validate
their counts against the entry length; this path was missed.

Reject the entry when the counts do not fit in the entry data.

Fixes: eff1a59c48 ("[P54]: add mac80211-based driver for prism54 softmac hardware")
Cc: stable@vger.kernel.org
Assisted-by: GLM:5.3
Signed-off-by: Shengzhuo Wei <me@cherr.cc>
Link: https://patch.msgid.link/20260831-p54-pda-validation-v2-1-dae566b388c8@cherr.cc
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Shengzhuo Wei 2026-08-31 02:42:12 +08:00 committed by Johannes Berg
parent c46cfaf8db
commit ce858fa6b8

View File

@ -414,17 +414,22 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
}
static int p54_convert_rev0(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
struct pda_pa_curve_data *curve_data, size_t len)
{
struct p54_common *priv = dev->priv;
struct p54_pa_curve_data_sample *dst;
struct pda_pa_curve_data_sample_rev0 *src;
size_t needed = curve_data->channels *
(sizeof(*src) * curve_data->points_per_channel + 2);
size_t cd_len = sizeof(*curve_data) +
(curve_data->points_per_channel*sizeof(*dst) + 2) *
curve_data->channels;
unsigned int i, j;
void *source, *target;
if (len < sizeof(*curve_data) + needed)
return -EINVAL;
priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
GFP_KERNEL);
if (!priv->curve_data)
@ -466,17 +471,22 @@ static int p54_convert_rev0(struct ieee80211_hw *dev,
}
static int p54_convert_rev1(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
struct pda_pa_curve_data *curve_data, size_t len)
{
struct p54_common *priv = dev->priv;
struct p54_pa_curve_data_sample *dst;
struct pda_pa_curve_data_sample_rev1 *src;
size_t needed = curve_data->channels *
(sizeof(*src) * curve_data->points_per_channel + 3);
size_t cd_len = sizeof(*curve_data) +
(curve_data->points_per_channel*sizeof(*dst) + 2) *
curve_data->channels;
unsigned int i, j;
void *source, *target;
if (len < sizeof(*curve_data) + needed)
return -EINVAL;
priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
GFP_KERNEL);
if (!priv->curve_data)
@ -763,6 +773,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
case PDR_PRISM_PA_CAL_CURVE_DATA: {
struct pda_pa_curve_data *curve_data =
(struct pda_pa_curve_data *)entry->data;
if (data_len < sizeof(*curve_data)) {
err = -EINVAL;
goto err;
@ -770,10 +781,10 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
switch (curve_data->cal_method_rev) {
case 0:
err = p54_convert_rev0(dev, curve_data);
err = p54_convert_rev0(dev, curve_data, data_len);
break;
case 1:
err = p54_convert_rev1(dev, curve_data);
err = p54_convert_rev1(dev, curve_data, data_len);
break;
default:
wiphy_err(dev->wiphy,