From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: netdev@vger.kernel.org
Cc: Yehezkel Bernat <YehezkelShB@gmail.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Mika Westerberg <mika.westerberg@linux.intel.com>
Subject: [PATCH 1/2] net: thunderbolt: Stop queueing Rx buffers if allocation fails
Date: Tue, 3 Nov 2026 13:56:19 +0100 [thread overview]
Message-ID: <20261103125621.1111198-1-mika.westerberg@linux.intel.com> (raw)
Sashiko pointed out that there is a bug in the driver when Rx buffer
allocation fails, we silently release the memory but leave the
descriptor in the hardware ring. This could cause all kinds of memory
corruption to happen. Fix this by making tbnet_alloc_rx_buffers() not
release the buffers already queued and modify the call sites accordingly.
Fixes: e69b6c02b4c3 ("net: Add support for networking over Thunderbolt cable")
Closes: https://sashiko.dev/#/patchset/20260902082128.1148463-1-mika.westerberg%40linux.intel.com
Cc: stable@vger.kernel.org
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/net/thunderbolt/main.c | 49 +++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
index cf51b9c39f4e..30b3568a83fc 100644
--- a/drivers/net/thunderbolt/main.c
+++ b/drivers/net/thunderbolt/main.c
@@ -506,7 +506,7 @@ static unsigned int tbnet_available_buffers(const struct tbnet_ring *ring)
static int tbnet_alloc_rx_buffers(struct tbnet *net, unsigned int nbuffers)
{
struct tbnet_ring *ring = &net->rx_ring;
- int ret;
+ int ret = 0;
while (nbuffers--) {
struct device *dma_dev = tb_ring_dma_device(ring->ring);
@@ -524,14 +524,16 @@ static int tbnet_alloc_rx_buffers(struct tbnet *net, unsigned int nbuffers)
tf->page = dev_alloc_pages(TBNET_RX_PAGE_ORDER);
if (!tf->page) {
ret = -ENOMEM;
- goto err_free;
+ break;
}
dma_addr = dma_map_page(dma_dev, tf->page, 0,
TBNET_RX_PAGE_SIZE, DMA_FROM_DEVICE);
if (dma_mapping_error(dma_dev, dma_addr)) {
+ __free_pages(tf->page, TBNET_RX_PAGE_ORDER);
+ tf->page = NULL;
ret = -ENOMEM;
- goto err_free;
+ break;
}
tf->frame.buffer_phy = dma_addr;
@@ -546,10 +548,6 @@ static int tbnet_alloc_rx_buffers(struct tbnet *net, unsigned int nbuffers)
}
tb_ring_notify(ring->ring);
- return 0;
-
-err_free:
- tbnet_free_buffers(ring);
return ret;
}
@@ -678,7 +676,7 @@ static void tbnet_connected_work(struct work_struct *work)
ret = tbnet_alloc_tx_buffers(net);
if (ret)
- goto err_free_rx_buffers;
+ goto err_stop_rings;
ret = tb_xdomain_enable_paths(net->xd, net->local_transmit_path,
net->tx_ring.ring->hop,
@@ -686,7 +684,7 @@ static void tbnet_connected_work(struct work_struct *work)
net->rx_ring.ring->hop);
if (ret) {
netdev_err(net->dev, "failed to enable DMA paths\n");
- goto err_free_tx_buffers;
+ goto err_stop_rings;
}
netif_carrier_on(net->dev);
@@ -695,13 +693,11 @@ static void tbnet_connected_work(struct work_struct *work)
netdev_dbg(net->dev, "network traffic started\n");
return;
-err_free_tx_buffers:
- tbnet_free_buffers(&net->tx_ring);
-err_free_rx_buffers:
- tbnet_free_buffers(&net->rx_ring);
err_stop_rings:
tb_ring_stop(net->rx_ring.ring);
tb_ring_stop(net->tx_ring.ring);
+ tbnet_free_buffers(&net->rx_ring);
+ tbnet_free_buffers(&net->tx_ring);
tb_xdomain_release_in_hopid(net->xd, net->remote_transmit_path);
tbnet_connect_failed(net);
}
@@ -826,9 +822,13 @@ static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf,
static int tbnet_poll(struct napi_struct *napi, int budget)
{
struct tbnet *net = container_of(napi, struct tbnet, napi);
- unsigned int cleaned_count = tbnet_available_buffers(&net->rx_ring);
struct device *dma_dev = tb_ring_dma_device(net->rx_ring.ring);
- unsigned int rx_packets = 0;
+ unsigned int cleaned_count, rx_packets = 0;
+ bool no_buffers = false;
+
+ /* Buffers a previous run was not able to return to the ring */
+ cleaned_count = tb_ring_size(net->rx_ring.ring) -
+ tbnet_available_buffers(&net->rx_ring);
while (rx_packets < budget) {
const struct thunderbolt_ip_frame_header *hdr;
@@ -845,8 +845,14 @@ static int tbnet_poll(struct napi_struct *napi, int budget)
* time.
*/
if (cleaned_count >= MAX_SKB_FRAGS) {
- tbnet_alloc_rx_buffers(net, cleaned_count);
+ int ret;
+
+ ret = tbnet_alloc_rx_buffers(net, cleaned_count);
cleaned_count = 0;
+ if (ret) {
+ no_buffers = true;
+ break;
+ }
}
frame = tb_ring_poll(net->rx_ring.ring);
@@ -917,12 +923,19 @@ static int tbnet_poll(struct napi_struct *napi, int budget)
}
}
- if (cleaned_count)
- tbnet_alloc_rx_buffers(net, cleaned_count);
+ if (cleaned_count && tbnet_alloc_rx_buffers(net, cleaned_count))
+ no_buffers = true;
if (rx_packets >= budget)
return budget;
+ /*
+ * We were not able to fill the RX ring for more buffers on this
+ * run. Keep the polling enabled to retry the allocation.
+ */
+ if (no_buffers && !tbnet_available_buffers(&net->rx_ring))
+ return budget;
+
napi_complete_done(napi, rx_packets);
/* Re-enable the ring interrupt */
tb_ring_poll_complete(net->rx_ring.ring);
--
2.50.1
next reply other threads:[~2026-11-03 12:56 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 12:56 Mika Westerberg [this message]
2026-11-03 12:56 ` [PATCH 2/2] net: thunderbolt: Prevent Tx descriptor leak in tbnet_start_xmit() Mika Westerberg
2026-11-03 12:57 ` [PATCH 1/2] net: thunderbolt: Stop queueing Rx buffers if allocation fails netdev-bot+sinfo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261103125621.1111198-1-mika.westerberg@linux.intel.com \
--to=mika.westerberg@linux.intel.com \
--cc=YehezkelShB@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox