wifi: iwlwifi: mei: skip data read if length is too short

When calculating the SAP data length, the code subtracts
sizeof(*ethhdr) from len. If the SAP data header indicates a length
that is shorter than ethernet header length, this will result in an
unsigned underflow which will lead to a kernel panic when trying to
put the data into the SKB. Fix it by skipping a message if the
indicated length is too short.
In addition, if the message type is not SAP_MSG_DATA_PACKET or skb
allocation fails, the loop skips to the next message but without
reading the message payload. This may result in reading the payload
as the next message header, which will lead to errors in parsing the
next messages. Fix it by skipping the message payload as well.

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260715220243.f66b10736047.I4a1dde517c36561d41358dd82a5cec8b6c886c14@changeid
This commit is contained in:
Avraham Stern 2026-07-15 22:04:28 +03:00 committed by Miri Korenblit
parent 7d8cc301bc
commit c00a5d65b7

View File

@ -1041,11 +1041,14 @@ static void iwl_mei_read_from_q(const u8 *q_head, u32 q_sz,
u32 rd = *_rd;
if (rd + len <= q_sz) {
memcpy(buf, q_head + rd, len);
if (buf)
memcpy(buf, q_head + rd, len);
rd += len;
} else {
memcpy(buf, q_head + rd, q_sz - rd);
memcpy(buf + q_sz - rd, q_head, len - (q_sz - rd));
if (buf) {
memcpy(buf, q_head + rd, q_sz - rd);
memcpy(buf + q_sz - rd, q_head, len - (q_sz - rd));
}
rd = len - (q_sz - rd);
}
@ -1086,24 +1089,29 @@ static void iwl_mei_handle_sap_data(struct mei_cl_device *cldev,
break;
}
valid_rx_sz -= len;
if (len < sizeof(*ethhdr)) {
dev_err(&cldev->dev,
"Data len is smaller than an ethernet header? len = %d\n",
len);
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
continue;
}
valid_rx_sz -= len;
if (le16_to_cpu(hdr.type) != SAP_MSG_DATA_PACKET) {
dev_err(&cldev->dev, "Unsupported Rx data: type %d, len %d\n",
le16_to_cpu(hdr.type), len);
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
continue;
}
/* We need enough room for the WiFi header + SNAP + IV */
skb = netdev_alloc_skb(netdev, len + QOS_HDR_IV_SNAP_LEN);
if (!skb)
if (!skb) {
iwl_mei_read_from_q(q_head, q_sz, &rd, wr, NULL, len);
continue;
}
skb_reserve(skb, QOS_HDR_IV_SNAP_LEN);
ethhdr = skb_push(skb, sizeof(*ethhdr));