| From ef48faa412e10c9905bd3fd5dd6ca2dbe15f8d5a Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 5 Feb 2026 20:17:19 +0800 |
| Subject: net: hns3: fix double free issue for tx spare buffer |
| |
| From: Jian Shen <shenjian15@huawei.com> |
| |
| [ Upstream commit 6d2f142b1e4b203387a92519d9d2e34752a79dbb ] |
| |
| In hns3_set_ringparam(), a temporary copy (tmp_rings) of the ring structure |
| is created for rollback. However, the tx_spare pointer in the original |
| ring handle is incorrectly left pointing to the old backup memory. |
| |
| Later, if memory allocation fails in hns3_init_all_ring() during the setup, |
| the error path attempts to free all newly allocated rings. Since tx_spare |
| contains a stale (non-NULL) pointer from the backup, it is mistaken for |
| a newly allocated buffer and is erroneously freed, leading to a double-free |
| of the backup memory. |
| |
| The root cause is that the tx_spare field was not cleared after its value |
| was saved in tmp_rings, leaving a dangling pointer. |
| |
| Fix this by setting tx_spare to NULL in the original ring structure |
| when the creation of the new `tx_spare` fails. This ensures the |
| error cleanup path only frees genuinely newly allocated buffers. |
| |
| Fixes: 907676b130711 ("net: hns3: use tx bounce buffer for small packets") |
| Signed-off-by: Jian Shen <shenjian15@huawei.com> |
| Signed-off-by: Jijie Shao <shaojijie@huawei.com> |
| Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> |
| Link: https://patch.msgid.link/20260205121719.3285730-1-shaojijie@huawei.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 +++++++++-- |
| 1 file changed, 9 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c |
| index 7a9573dcab741..e879b04e21b0c 100644 |
| --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c |
| +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c |
| @@ -1048,13 +1048,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) |
| int order; |
| |
| if (!alloc_size) |
| - return; |
| + goto not_init; |
| |
| order = get_order(alloc_size); |
| if (order > MAX_PAGE_ORDER) { |
| if (net_ratelimit()) |
| dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n"); |
| - return; |
| + goto not_init; |
| } |
| |
| tx_spare = devm_kzalloc(ring_to_dev(ring), sizeof(*tx_spare), |
| @@ -1092,6 +1092,13 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring) |
| devm_kfree(ring_to_dev(ring), tx_spare); |
| devm_kzalloc_error: |
| ring->tqp->handle->kinfo.tx_spare_buf_size = 0; |
| +not_init: |
| + /* When driver init or reset_init, the ring->tx_spare is always NULL; |
| + * but when called from hns3_set_ringparam, it's usually not NULL, and |
| + * will be restored if hns3_init_all_ring() failed. So it's safe to set |
| + * ring->tx_spare to NULL here. |
| + */ |
| + ring->tx_spare = NULL; |
| } |
| |
| /* Use hns3_tx_spare_space() to make sure there is enough buffer |
| -- |
| 2.51.0 |
| |