]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: rswitch: Avoid use-after-free in rswitch_poll()
authorRadu Rendec <rrendec@redhat.com>
Tue, 2 Jul 2024 21:08:37 +0000 (17:08 -0400)
committerJakub Kicinski <kuba@kernel.org>
Thu, 4 Jul 2024 02:15:22 +0000 (19:15 -0700)
The use-after-free is actually in rswitch_tx_free(), which is inlined in
rswitch_poll(). Since `skb` and `gq->skbs[gq->dirty]` are in fact the
same pointer, the skb is first freed using dev_kfree_skb_any(), then the
value in skb->len is used to update the interface statistics.

Let's move around the instructions to use skb->len before the skb is
freed.

This bug is trivial to reproduce using KFENCE. It will trigger a splat
every few packets. A simple ARP request or ICMP echo request is enough.

Fixes: 271e015b9153 ("net: rswitch: Add unmap_addrs instead of dma address in each desc")
Signed-off-by: Radu Rendec <rrendec@redhat.com>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Link: https://patch.msgid.link/20240702210838.2703228-1-rrendec@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/renesas/rswitch.c

index dcab638c57fe829d85a794942dfd1726951249b2..24c90d8f5a442eec61f2923c8a13e641b63b811d 100644 (file)
@@ -871,13 +871,13 @@ static void rswitch_tx_free(struct net_device *ndev)
                dma_rmb();
                skb = gq->skbs[gq->dirty];
                if (skb) {
+                       rdev->ndev->stats.tx_packets++;
+                       rdev->ndev->stats.tx_bytes += skb->len;
                        dma_unmap_single(ndev->dev.parent,
                                         gq->unmap_addrs[gq->dirty],
                                         skb->len, DMA_TO_DEVICE);
                        dev_kfree_skb_any(gq->skbs[gq->dirty]);
                        gq->skbs[gq->dirty] = NULL;
-                       rdev->ndev->stats.tx_packets++;
-                       rdev->ndev->stats.tx_bytes += skb->len;
                }
                desc->desc.die_dt = DT_EEMPTY;
        }