[PATCH v2] wifi: ath10k: validate WMI header before reading it

Pengpeng Hou posted 1 patch 1 day, 2 hours ago
drivers/net/wireless/ath/ath10k/wmi-tlv.c |  8 ++---
drivers/net/wireless/ath/ath10k/wmi.c     | 45 +++++++++++++++----------------
drivers/net/wireless/ath/ath10k/wmi.h     |  2 ++
3 files changed, 25 insertions(+), 30 deletions(-)
[PATCH v2] wifi: ath10k: validate WMI header before reading it
Posted by Pengpeng Hou 1 day, 2 hours ago
The WMI receive handlers read cmd_id from skb->data before checking that
the skb contains a complete struct wmi_cmd_hdr. The outer HTC payload
check does not establish the nested WMI header length.

Add one helper that uses skb_pull_data() to validate and consume the
header before reading it. Decode and mask the command ID in the helper,
then use it in all five WMI receive variants. Each caller keeps its
existing skb ownership on a short packet.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
Changes since v1: https://lore.kernel.org/all/20260722042029.36066-1-pengpeng@iscas.ac.cn/
- use skb_pull_data() following the established ath12k receive pattern
- mask the command ID in the shared helper
- preserve all five callers' existing short-packet cleanup
- rebase onto the current ath-next tree

 drivers/net/wireless/ath/ath10k/wmi-tlv.c |  8 ++---
 drivers/net/wireless/ath/ath10k/wmi.c     | 45 +++++++++++++++----------------
 drivers/net/wireless/ath/ath10k/wmi.h     |  2 ++
 3 files changed, 25 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 01f2d1fa9d7d..272dab37dc19 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -638,14 +638,10 @@ static int ath10k_wmi_tlv_event_peer_delete_resp(struct ath10k *ar,
 
 static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct wmi_cmd_hdr *cmd_hdr;
-	enum wmi_tlv_event_id id;
 	bool consumed;
+	u32 id;
 
-	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
-	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
-
-	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+	if (!ath10k_wmi_pull_cmd_hdr(skb, &id))
 		goto out;
 
 	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index e57588c19c80..296a89106736 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -5873,15 +5873,24 @@ static inline void ath10k_wmi_queue_set_coverage_class_work(struct ath10k *ar)
 	}
 }
 
-static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
+bool ath10k_wmi_pull_cmd_hdr(struct sk_buff *skb, u32 *id)
 {
-	struct wmi_cmd_hdr *cmd_hdr;
-	enum wmi_event_id id;
+	const struct wmi_cmd_hdr *cmd_hdr;
 
-	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
-	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
+	cmd_hdr = skb_pull_data(skb, sizeof(*cmd_hdr));
+	if (!cmd_hdr)
+		return false;
+
+	*id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
+
+	return true;
+}
+
+static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+	u32 id;
 
-	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+	if (!ath10k_wmi_pull_cmd_hdr(skb, &id))
 		goto out;
 
 	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -6002,14 +6011,10 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
 
 static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct wmi_cmd_hdr *cmd_hdr;
-	enum wmi_10x_event_id id;
 	bool consumed;
+	u32 id;
 
-	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
-	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
-
-	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+	if (!ath10k_wmi_pull_cmd_hdr(skb, &id))
 		goto out;
 
 	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -6133,14 +6138,10 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
 
 static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct wmi_cmd_hdr *cmd_hdr;
-	enum wmi_10_2_event_id id;
 	bool consumed;
+	u32 id;
 
-	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
-	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
-
-	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+	if (!ath10k_wmi_pull_cmd_hdr(skb, &id))
 		goto out;
 
 	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
@@ -6282,14 +6283,10 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
 
 static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-	struct wmi_cmd_hdr *cmd_hdr;
-	enum wmi_10_4_event_id id;
 	bool consumed;
+	u32 id;
 
-	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
-	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
-
-	if (!skb_pull(skb, sizeof(struct wmi_cmd_hdr)))
+	if (!ath10k_wmi_pull_cmd_hdr(skb, &id))
 		goto out;
 
 	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 7f50a1de6b97..4ecc94712f76 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -7440,6 +7440,7 @@ struct ath10k_vif;
 struct ath10k_fw_stats_pdev;
 struct ath10k_fw_stats_peer;
 struct ath10k_fw_stats;
+struct sk_buff;
 
 int ath10k_wmi_attach(struct ath10k *ar);
 void ath10k_wmi_detach(struct ath10k *ar);
@@ -7449,6 +7450,7 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
 
 struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
 int ath10k_wmi_connect(struct ath10k *ar);
+bool ath10k_wmi_pull_cmd_hdr(struct sk_buff *skb, u32 *id);
 
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
 int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
-- 
2.50.1 (Apple Git-155)