* Re: [PATCH] wifi: mm81x: validate packet length in mm81x_yaps_read_pkt()
@ 2026-09-09 18:42 netdev-bot+sashiko
0 siblings, 0 replies; 2+ messages in thread
From: netdev-bot+sashiko @ 2026-09-09 18:42 UTC (permalink / raw)
To: elb12345
Cc: lachlan.hodges, dan.callaghan, kvalo, arien.judge, johannes,
linux-wireless, netdev, stable, kuba
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:
Critical: 0 · High: 1 (1) · Medium: 0 (2) · Low: 0
- [High] Incomplete fix / wrong ordering: the header-claimed-length
validation added by this patch runs ~30 lines AFTER…
Pre-existing issues:
- [High] Missing minimum-payload validation lets an undersized device
command response reach mm81x_cmd_resp_process()…
- [Medium] Two RX parse sites disagree on the meaning of struct
mm81x_skb_hdr's `offset` field.
- [Medium] skb leak on the -ENOMEM path of mm81x_yaps_hw_read_pkts().
--
wifi: mm81x: validate packet length in mm81x_yaps_read_pkt()
The patch adds two length checks to mm81x_yaps_read_pkt(): a minimum
length check before the struct mm81x_skb_hdr cast, and a check that the
header-claimed total length does not exceed skb->len before the packet is
trimmed and enqueued. A few questions about the placement of the second
check and about the paths that consume the validated packet.
> diff --git a/drivers/net/wireless/morsemicro/mm81x/yaps.c b/drivers/net/wireless/morsemicro/mm81x/yaps.c
> index e98a2a58726f5..da2c88901d64c 100644
> --- a/drivers/net/wireless/morsemicro/mm81x/yaps.c
> +++ b/drivers/net/wireless/morsemicro/mm81x/yaps.c
> @@ -147,6 +147,13 @@ static int mm81x_yaps_read_pkt(struct mm81x_yaps *yaps, struct sk_buff *skb)
>
> __skb_queue_head_init(&skbq);
>
> + if (skb->len < sizeof(*hdr)) {
> + dev_err(mors->dev, "packet too short for header (%u < %zu)",
> + skb->len, sizeof(*hdr));
> + ret = -EINVAL;
> + goto exit_return_page;
> + }
> +
> hdr = (struct mm81x_skb_hdr *)skb->data;
> if (hdr->sync != MM81X_SKB_HEADER_SYNC) {
> dev_err(mors->dev, "sync value error [0xAA:%d], hdr.len %d",
> @@ -186,6 +193,14 @@ static int mm81x_yaps_read_pkt(struct mm81x_yaps *yaps, struct sk_buff *skb)
> }
>
> skb_len = sizeof(*hdr) + hdr->offset + le16_to_cpu(hdr->len);
> + if (skb_len > skb->len) {
> + dev_err(mors->dev,
> + "header claims %d bytes but packet is only %u",
> + skb_len, skb->len);
> + ret = -EINVAL;
> + goto exit_return_page;
> + }
> +
[Severity: High]
Does this check come too late to protect the checksum walk? In
mm81x_yaps_read_pkt() the checksum helper is called earlier, between the
sync check and the channel switch, while hdr->len is still unvalidated:
if (yaps->mors->hif.validate_skb_checksum &&
!mm81x_skbq_validate_checksum(skb->data)) {
mm81x_skbq_validate_checksum() in skbq.c takes no buffer length at all and
derives its read extent from the device-supplied header:
u16 len = le16_to_cpu(skb_hdr->len) + sizeof(*skb_hdr);
u32 *data_to_xor = (u32 *)data;
...
for (i = 0; i < len; i += 4) {
xor ^= *data_to_xor;
data_to_xor++;
}
The real bound on the buffer is the YAPS delimiter size, which is
independent of hdr->len, in mm81x_yaps_hw_read_pkts():
pkts[i].skb = dev_alloc_skb(pkt_size);
...
skb_put(pkts[i].skb, pkt_size);
So with pkt_size == sizeof(struct mm81x_skb_hdr) and hdr->len == 0xFFFF,
can this read roughly 64 KiB past the end of the skb data allocation before
the new skb_len check runs?
Separately, the same helper dereferences an 802.11 header placed just after
the mm81x header:
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *)(data + sizeof(*skb_hdr));
...
(ieee80211_is_data(hdr->frame_control) ||
with the new minimum check accepting skb->len == sizeof(*hdr) exactly, is
that frame_control read (and the clamped span sizeof(*skb_hdr) +
sizeof(struct ieee80211_qos_hdr) + IEEE80211_CCMP_HDR_LEN) also outside the
packet data?
The path looks live: mors->hif.validate_skb_checksum is set from the
firmware host table in mm81x_fw_update_validate_skb_checksum():
mors->hif.validate_skb_checksum =
validate_checksum->insert_and_validate_checksum;
Would computing and validating skb_len before the
mm81x_skbq_validate_checksum() call, or passing the available length into
that helper and bounding its loop there, close this?
[Severity: High]
This isn't a bug introduced by this patch, but since these checks are the
new choke point for RX length validation: is a minimum payload length also
needed per channel? hdr->len == 0 passes both new checks, and
mm81x_skbq_dispatch_work() then strips the header entirely:
/* Remove mm81x header and padding */
__skb_pull(pfirst, sizeof(*hdr) + hdr->offset);
switch (channel) {
case MM81X_SKB_CHAN_COMMAND:
mm81x_cmd_resp_process(mors, pfirst);
mm81x_cmd_resp_process() in command.c dereferences the response header with
no skb->len check at all:
struct host_cmd_resp *src_resp = (struct host_cmd_resp *)(skb->data);
...
u16 resp_message_id = le16_to_cpu(src_resp->hdr.message_id);
u16 resp_host_id = le16_to_cpu(src_resp->hdr.host_id);
and on the matched-response path the memcpy source length is bounded only
by the destination size and a second device-supplied length:
length = min_t(int, length,
le16_to_cpu(src_resp->hdr.len) +
sizeof(struct host_cmd_header));
memcpy(dest_resp, src_resp, length);
For a zero-length command payload with a large embedded hdr.len, does this
copy adjacent slab memory into the driver's command response structure?
[Severity: Medium]
This is a pre-existing issue, but the length formula being validated here
includes hdr->offset while the checksum helper does not. The dispatch path
and the TX producer both treat offset as padding between the header and the
payload:
skbq.c:mm81x_skbq_dispatch_work()
__skb_pull(pfirst, sizeof(*hdr) + hdr->offset);
skbq.c:mm81x_skbq_skb_tx()
hdr.len = cpu_to_le16(skb->len);
hdr.offset = data - (aligned_head + sizeof(hdr));
whereas mm81x_skbq_validate_checksum() ignores offset:
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *)(data + sizeof(*skb_hdr));
u16 len = le16_to_cpu(skb_hdr->len) + sizeof(*skb_hdr);
For an RX packet with hdr->offset != 0, does the helper then read padding
bytes as frame_control and XOR a byte range shifted by offset, producing a
checksum verdict over the wrong bytes?
> skb_bytes_remaining = mm81x_skbq_space(mq);
>
> if (skb_len > skb_bytes_remaining) {
[Severity: Medium]
This isn't a bug introduced by this patch, but while looking at the caller
of mm81x_yaps_read_pkt(): can the -ENOMEM path of
mm81x_yaps_hw_read_pkts() leak the already allocated RX skbs?
yaps_hw.c:mm81x_yaps_hw_read_pkts() bumps the count after each successful
packet and bails out on allocation failure:
if (pkts[i].skb)
dev_err(yaps->mors->dev, "yaps packet leak");
/* SKB doesn't want padding */
pkts[i].skb = dev_alloc_skb(pkt_size);
if (!pkts[i].skb) {
ret = -ENOMEM;
dev_err(yaps->mors->dev, "yaps no mem for skb");
goto exit;
}
yaps.c:mm81x_yaps_rx_handler() then skips the only loop that takes
ownership of them:
if (ret && ret != -EAGAIN) {
dev_err(yaps->mors->dev, "YAPS read_pkts fail: %d", ret);
goto exit;
}
for (i = 0; i < num_pks_received; ++i) {
mm81x_yaps_read_pkt(yaps, yaps->hw.from_chip_pkts[i].skb);
yaps->hw.from_chip_pkts[i].skb = NULL;
}
Since ownership is only released inside mm81x_yaps_read_pkt() (enqueue or
dev_kfree_skb()), and rx_handler returns true for -ENOMEM so it is called
again, does the next pass simply hit the "yaps packet leak" dev_err and
overwrite the stale pointers? The same appears to apply to the
mm81x_dm_read() overhang error path.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/AS8P251MB0001B650C31E9F37C3B7907BC8B32%40AS8P251MB0001.EURP251.PROD.OUTLOOK.COM
^ permalink raw reply [flat|nested] 2+ messages in thread* [PATCH] wifi: mm81x: validate packet length in mm81x_yaps_read_pkt()
@ 2026-09-06 23:42 Aamir Ahmed
0 siblings, 0 replies; 2+ messages in thread
From: Aamir Ahmed @ 2026-09-06 23:42 UTC (permalink / raw)
To: Lachlan Hodges, Dan Callaghan, Kalle Valo
Cc: Arien Judge, Johannes Berg, linux-wireless, netdev, stable
mm81x_yaps_read_pkt() casts skb->data to struct mm81x_skb_hdr and
accesses header fields without first verifying that the skb contains
enough data for the header structure. A malformed device response with
a valid YAPS delimiter but undersized payload would cause out-of-bounds
reads from heap memory.
Additionally, the function computes the expected packet length from
header-embedded fields (hdr->offset and hdr->len) but never checks
this against the actual skb length. Since skb_trim() only shrinks, a
claimed length exceeding the real data is silently accepted, and the
subsequent __skb_pull() in the dispatch path underflows skb->len.
Add two validation checks:
1. Verify skb->len >= sizeof(struct mm81x_skb_hdr) before accessing
any header fields.
2. Verify the header-claimed total length does not exceed the actual
skb length before enqueuing.
Fixes: b1906cea00b0 ("wifi: mm81x: add mm81x Wi-Fi HaLow driver")
Signed-off-by: Aamir Ahmed <elb12345@hotmail.co.uk>
---
drivers/net/wireless/morsemicro/mm81x/yaps.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/net/wireless/morsemicro/mm81x/yaps.c b/drivers/net/wireless/morsemicro/mm81x/yaps.c
index e98a2a58726f..da2c88901d64 100644
--- a/drivers/net/wireless/morsemicro/mm81x/yaps.c
+++ b/drivers/net/wireless/morsemicro/mm81x/yaps.c
@@ -147,6 +147,13 @@ static int mm81x_yaps_read_pkt(struct mm81x_yaps *yaps, struct sk_buff *skb)
__skb_queue_head_init(&skbq);
+ if (skb->len < sizeof(*hdr)) {
+ dev_err(mors->dev, "packet too short for header (%u < %zu)",
+ skb->len, sizeof(*hdr));
+ ret = -EINVAL;
+ goto exit_return_page;
+ }
+
hdr = (struct mm81x_skb_hdr *)skb->data;
if (hdr->sync != MM81X_SKB_HEADER_SYNC) {
dev_err(mors->dev, "sync value error [0xAA:%d], hdr.len %d",
@@ -186,6 +193,14 @@ static int mm81x_yaps_read_pkt(struct mm81x_yaps *yaps, struct sk_buff *skb)
}
skb_len = sizeof(*hdr) + hdr->offset + le16_to_cpu(hdr->len);
+ if (skb_len > skb->len) {
+ dev_err(mors->dev,
+ "header claims %d bytes but packet is only %u",
+ skb_len, skb->len);
+ ret = -EINVAL;
+ goto exit_return_page;
+ }
+
skb_bytes_remaining = mm81x_skbq_space(mq);
if (skb_len > skb_bytes_remaining) {
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-09 18:42 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-09 18:42 [PATCH] wifi: mm81x: validate packet length in mm81x_yaps_read_pkt() netdev-bot+sashiko
-- strict thread matches above, loose matches on Subject: below --
2026-09-06 23:42 Aamir Ahmed
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox