Subject: [PATCH] qed: Track allocation size of qed_ll2_buffer

From: Kees Cook <[email-masked]>
Date: Tue, 18 Oct 2022 02:00:48 -0700

In preparation for requiring that build_skb() have a non-zero size
argument, track the qed_ll2_buffer data allocation size explicitly
and pass it into build_skb(). To retain the original result of using
the ksize() side-effect on the skb size, explicitly round up the size
during allocation.

Cc: Ariel Elior <[email-masked]>
Cc: Manish Chopra <[email-masked]>
Cc: "David S. Miller" <[email-masked]>
Cc: Eric Dumazet <[email-masked]>
Cc: Jakub Kicinski <[email-masked]>
Cc: Paolo Abeni <[email-masked]>
Cc: [email-masked]
Signed-off-by: Kees Cook <[email-masked]>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 37 ++++++++++++-----------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index ed274f033626..750391e4d80a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -62,6 +62,7 @@ struct qed_cb_ll2_info {
 struct qed_ll2_buffer {
 	struct list_head list;
 	void *data;
+	u32 len;
 	dma_addr_t phys_addr;
 };
 
@@ -111,20 +112,23 @@ static void qed_ll2b_complete_tx_packet(void *cxt,
 }
 
 static int qed_ll2_alloc_buffer(struct qed_dev *cdev,
-				u8 **data, dma_addr_t *phys_addr)
+				struct qed_ll2_buffer *buffer)
 {
-	*data = kmalloc(cdev->ll2->rx_size, GFP_ATOMIC);
-	if (!(*data)) {
+	buffer->len = kmalloc_size_roundup(cdev->ll2->rx_size);
+	buffer->data = kmalloc(buffer->len, GFP_ATOMIC);
+	if (!buffer->data) {
 		DP_INFO(cdev, "Failed to allocate LL2 buffer data\n");
+		buffer->len = 0;
 		return -ENOMEM;
 	}
 
-	*phys_addr = dma_map_single(&cdev->pdev->dev,
-				    ((*data) + NET_SKB_PAD),
-				    cdev->ll2->rx_size, DMA_FROM_DEVICE);
-	if (dma_mapping_error(&cdev->pdev->dev, *phys_addr)) {
+	buffer->phys_addr = dma_map_single(&cdev->pdev->dev,
+					   buffer->data + NET_SKB_PAD,
+					   buffer->len, DMA_FROM_DEVICE);
+	if (dma_mapping_error(&cdev->pdev->dev, buffer->phys_addr)) {
 		DP_INFO(cdev, "Failed to map LL2 buffer data\n");
-		kfree((*data));
+		kfree(buffer->data);
+		buffer->len = 0;
 		return -ENOMEM;
 	}
 
@@ -139,6 +143,7 @@ static int qed_ll2_dealloc_buffer(struct qed_dev *cdev,
 	dma_unmap_single(&cdev->pdev->dev, buffer->phys_addr,
 			 cdev->ll2->rx_size, DMA_FROM_DEVICE);
 	kfree(buffer->data);
+	buffer->len = 0;
 	list_del(&buffer->list);
 
 	cdev->ll2->rx_cnt--;
@@ -164,11 +169,10 @@ static void qed_ll2b_complete_rx_packet(void *cxt,
 	struct qed_hwfn *p_hwfn = cxt;
 	struct qed_ll2_buffer *buffer = data->cookie;
 	struct qed_dev *cdev = p_hwfn->cdev;
-	dma_addr_t new_phys_addr;
+	struct qed_ll2_buffer new_buffer = { };
 	struct sk_buff *skb;
 	bool reuse = false;
 	int rc = -EINVAL;
-	u8 *new_data;
 
 	DP_VERBOSE(p_hwfn,
 		   (NETIF_MSG_RX_STATUS | QED_MSG_STORAGE | NETIF_MSG_PKTDATA),
@@ -191,8 +195,7 @@ static void qed_ll2b_complete_rx_packet(void *cxt,
 
 	/* Allocate a replacement for buffer; Reuse upon failure */
 	if (!reuse)
-		rc = qed_ll2_alloc_buffer(p_hwfn->cdev, &new_data,
-					  &new_phys_addr);
+		rc = qed_ll2_alloc_buffer(p_hwfn->cdev, &new_buffer);
 
 	/* If need to reuse or there's no replacement buffer, repost this */
 	if (rc)
@@ -200,7 +203,7 @@ static void qed_ll2b_complete_rx_packet(void *cxt,
 	dma_unmap_single(&cdev->pdev->dev, buffer->phys_addr,
 			 cdev->ll2->rx_size, DMA_FROM_DEVICE);
 
-	skb = build_skb(buffer->data, 0);
+	skb = build_skb(buffer->data, buffer->len);
 	if (!skb) {
 		DP_INFO(cdev, "Failed to build SKB\n");
 		kfree(buffer->data);
@@ -235,8 +238,9 @@ static void qed_ll2b_complete_rx_packet(void *cxt,
 
 out_post1:
 	/* Update Buffer information and update FW producer */
-	buffer->data = new_data;
-	buffer->phys_addr = new_phys_addr;
+	buffer->data = new_buffer.data;
+	buffer->len = new_buffer.len;
+	buffer->phys_addr = new_buffer.phys_addr;
 
 out_post:
 	rc = qed_ll2_post_rx_buffer(p_hwfn, cdev->ll2->handle,
@@ -2608,8 +2612,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
 			goto err0;
 		}
 
-		rc = qed_ll2_alloc_buffer(cdev, (u8 **)&buffer->data,
-					  &buffer->phys_addr);
+		rc = qed_ll2_alloc_buffer(cdev, buffer);
 		if (rc) {
 			kfree(buffer);
 			goto err0;
-- 
2.34.1