Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

gve: fix incorrect buffer cleanup in gve_tx_clean_pending_packets for QPL

In DQ-QPL mode, gve_tx_clean_pending_packets() incorrectly uses the RDA
buffer cleanup path. It iterates num_bufs times and attempts to unmap
entries in the dma array.

This leads to two issues:
1. The dma array shares storage with tx_qpl_buf_ids (union).
Interpreting buffer IDs as DMA addresses results in attempting to
unmap incorrect memory locations.
2. num_bufs in QPL mode (counting 2K chunks) can significantly exceed
the size of the dma array, causing out-of-bounds access warnings
(trace below is how we noticed this issue).

UBSAN: array-index-out-of-bounds in
drivers/net/ethernet/drivers/net/ethernet/google/gve/gve_tx_dqo.c:178:5 index 18 is out of
range for type 'dma_addr_t[18]' (aka 'unsigned long long[18]')
Workqueue: gve gve_service_task [gve]
Call Trace:
<TASK>
dump_stack_lvl+0x33/0xa0
__ubsan_handle_out_of_bounds+0xdc/0x110
gve_tx_stop_ring_dqo+0x182/0x200 [gve]
gve_close+0x1be/0x450 [gve]
gve_reset+0x99/0x120 [gve]
gve_service_task+0x61/0x100 [gve]
process_scheduled_works+0x1e9/0x380

Fix this by properly checking for QPL mode and delegating to
gve_free_tx_qpl_bufs() to reclaim the buffers.

Cc: stable@vger.kernel.org
Fixes: a6fb8d5a8b69 ("gve: Tx path for DQO-QPL")
Signed-off-by: Ankit Garg <nktgrg@google.com>
Reviewed-by: Jordan Rhee <jordanrhee@google.com>
Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
Signed-off-by: Joshua Washington <joshwash@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260220215324.1631350-1-joshwash@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Ankit Garg and committed by
Jakub Kicinski
fb868db5 7bb09315

+24 -30
+24 -30
drivers/net/ethernet/google/gve/gve_tx_dqo.c
··· 167 167 } 168 168 } 169 169 170 + static void gve_unmap_packet(struct device *dev, 171 + struct gve_tx_pending_packet_dqo *pkt) 172 + { 173 + int i; 174 + 175 + if (!pkt->num_bufs) 176 + return; 177 + 178 + /* SKB linear portion is guaranteed to be mapped */ 179 + dma_unmap_single(dev, dma_unmap_addr(pkt, dma[0]), 180 + dma_unmap_len(pkt, len[0]), DMA_TO_DEVICE); 181 + for (i = 1; i < pkt->num_bufs; i++) { 182 + netmem_dma_unmap_page_attrs(dev, dma_unmap_addr(pkt, dma[i]), 183 + dma_unmap_len(pkt, len[i]), 184 + DMA_TO_DEVICE, 0); 185 + } 186 + pkt->num_bufs = 0; 187 + } 188 + 170 189 /* gve_tx_free_desc - Cleans up all pending tx requests and buffers. 171 190 */ 172 191 static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx) ··· 195 176 for (i = 0; i < tx->dqo.num_pending_packets; i++) { 196 177 struct gve_tx_pending_packet_dqo *cur_state = 197 178 &tx->dqo.pending_packets[i]; 198 - int j; 199 179 200 - for (j = 0; j < cur_state->num_bufs; j++) { 201 - if (j == 0) { 202 - dma_unmap_single(tx->dev, 203 - dma_unmap_addr(cur_state, dma[j]), 204 - dma_unmap_len(cur_state, len[j]), 205 - DMA_TO_DEVICE); 206 - } else { 207 - dma_unmap_page(tx->dev, 208 - dma_unmap_addr(cur_state, dma[j]), 209 - dma_unmap_len(cur_state, len[j]), 210 - DMA_TO_DEVICE); 211 - } 212 - } 180 + if (tx->dqo.qpl) 181 + gve_free_tx_qpl_bufs(tx, cur_state); 182 + else 183 + gve_unmap_packet(tx->dev, cur_state); 184 + 213 185 if (cur_state->skb) { 214 186 dev_consume_skb_any(cur_state->skb); 215 187 cur_state->skb = NULL; ··· 1165 1155 } else { 1166 1156 tx->dqo.pending_packets[next_index].prev = prev_index; 1167 1157 } 1168 - } 1169 - 1170 - static void gve_unmap_packet(struct device *dev, 1171 - struct gve_tx_pending_packet_dqo *pkt) 1172 - { 1173 - int i; 1174 - 1175 - /* SKB linear portion is guaranteed to be mapped */ 1176 - dma_unmap_single(dev, dma_unmap_addr(pkt, dma[0]), 1177 - dma_unmap_len(pkt, len[0]), DMA_TO_DEVICE); 1178 - for (i = 1; i < pkt->num_bufs; i++) { 1179 - netmem_dma_unmap_page_attrs(dev, dma_unmap_addr(pkt, dma[i]), 1180 - dma_unmap_len(pkt, len[i]), 1181 - DMA_TO_DEVICE, 0); 1182 - } 1183 - pkt->num_bufs = 0; 1184 1158 } 1185 1159 1186 1160 /* Completion types and expected behavior: