diff mbox

ravb: Fix use-after-free on `ifconfig eth0 down`

Message ID 20170605220810.3933-1-erosca@de.adit-jv.com (mailing list archive)
State Accepted
Delegated to: Geert Uytterhoeven
Headers show

Commit Message

Eugeniu Rosca June 5, 2017, 10:08 p.m. UTC
Commit a47b70ea86bd ("ravb: unmap descriptors when freeing rings") has
introduced the issue seen in [1] reproduced on H3ULCB board.

Fix this by relocating the RX skb ringbuffer free operation, so that
swiotlb page unmapping can be done first. Freeing of aligned TX buffers
is not relevant to the issue seen in [1]. Still, reposition TX free
calls as well, to have all kfree() operations performed consistently
_after_ dma_unmap_*()/dma_free_*().

[1] Console screenshot with the problem reproduced:

salvator-x login: root
root@salvator-x:~# ifconfig eth0 up
Micrel KSZ9031 Gigabit PHY e6800000.ethernet-ffffffff:00: \
       attached PHY driver [Micrel KSZ9031 Gigabit PHY]   \
       (mii_bus:phy_addr=e6800000.ethernet-ffffffff:00, irq=235)
IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
root@salvator-x:~#
root@salvator-x:~# ifconfig eth0 down

Comments

Sergei Shtylyov June 6, 2017, 9:35 a.m. UTC | #1
Hello!

On 6/6/2017 1:08 AM, Eugeniu Rosca wrote:

> Commit a47b70ea86bd ("ravb: unmap descriptors when freeing rings") has
> introduced the issue seen in [1] reproduced on H3ULCB board.
>
> Fix this by relocating the RX skb ringbuffer free operation, so that
> swiotlb page unmapping can be done first. Freeing of aligned TX buffers
> is not relevant to the issue seen in [1]. Still, reposition TX free
> calls as well, to have all kfree() operations performed consistently
> _after_ dma_unmap_*()/dma_free_*().

    Perhaps it's a material of a separate cleanup patch?

> [1] Console screenshot with the problem reproduced:
>
> salvator-x login: root
> root@salvator-x:~# ifconfig eth0 up
> Micrel KSZ9031 Gigabit PHY e6800000.ethernet-ffffffff:00: \
>        attached PHY driver [Micrel KSZ9031 Gigabit PHY]   \
>        (mii_bus:phy_addr=e6800000.ethernet-ffffffff:00, irq=235)
> IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
> root@salvator-x:~#
> root@salvator-x:~# ifconfig eth0 down
> ==================================================================
> BUG: KASAN: use-after-free in swiotlb_tbl_unmap_single+0xc4/0x35c
> Write of size 1538 at addr ffff8006d884f780 by task ifconfig/1649
>
> CPU: 0 PID: 1649 Comm: ifconfig Not tainted 4.12.0-rc4-00004-g112eb07287d1 #32
> Hardware name: Renesas H3ULCB board based on r8a7795 (DT)
> Call trace:
> [<ffff20000808f11c>] dump_backtrace+0x0/0x3a4
> [<ffff20000808f4d4>] show_stack+0x14/0x1c
> [<ffff20000865970c>] dump_stack+0xf8/0x150
> [<ffff20000831f8b0>] print_address_description+0x7c/0x330
> [<ffff200008320010>] kasan_report+0x2e0/0x2f4
> [<ffff20000831eac0>] check_memory_region+0x20/0x14c
> [<ffff20000831f054>] memcpy+0x48/0x68
> [<ffff20000869ed50>] swiotlb_tbl_unmap_single+0xc4/0x35c
> [<ffff20000869fcf4>] unmap_single+0x90/0xa4
> [<ffff20000869fd14>] swiotlb_unmap_page+0xc/0x14
> [<ffff2000080a2974>] __swiotlb_unmap_page+0xcc/0xe4
> [<ffff2000088acdb8>] ravb_ring_free+0x514/0x870
> [<ffff2000088b25dc>] ravb_close+0x288/0x36c
> [<ffff200008aaf8c4>] __dev_close_many+0x14c/0x174
> [<ffff200008aaf9b4>] __dev_close+0xc8/0x144
> [<ffff200008ac2100>] __dev_change_flags+0xd8/0x194
> [<ffff200008ac221c>] dev_change_flags+0x60/0xb0
> [<ffff200008ba2dec>] devinet_ioctl+0x484/0x9d4
> [<ffff200008ba7b78>] inet_ioctl+0x190/0x194
> [<ffff200008a78c44>] sock_do_ioctl+0x78/0xa8
> [<ffff200008a7a128>] sock_ioctl+0x110/0x3c4
> [<ffff200008365a70>] vfs_ioctl+0x90/0xa0
> [<ffff200008365dbc>] do_vfs_ioctl+0x148/0xc38
> [<ffff2000083668f0>] SyS_ioctl+0x44/0x74
> [<ffff200008083770>] el0_svc_naked+0x24/0x28
>
> The buggy address belongs to the page:
> page:ffff7e001b6213c0 count:0 mapcount:0 mapping:          (null) index:0x0
> flags: 0x4000000000000000()
> raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff
> raw: 0000000000000000 ffff7e001b6213e0 0000000000000000 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
>  ffff8006d884f680: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>  ffff8006d884f700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>> ffff8006d884f780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>                    ^
>  ffff8006d884f800: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>  ffff8006d884f880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ==================================================================
> Disabling lock debugging due to kernel taint
> root@salvator-x:~#
>
> Fixes: a47b70ea86bd ("ravb: unmap descriptors when freeing rings")
> Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
[...]

Acked-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

MBR, Sergei
David Miller June 6, 2017, 8:03 p.m. UTC | #2
From: Eugeniu Rosca <erosca@de.adit-jv.com>
Date: Tue, 6 Jun 2017 00:08:10 +0200

> Commit a47b70ea86bd ("ravb: unmap descriptors when freeing rings") has
> introduced the issue seen in [1] reproduced on H3ULCB board.
> 
> Fix this by relocating the RX skb ringbuffer free operation, so that
> swiotlb page unmapping can be done first. Freeing of aligned TX buffers
> is not relevant to the issue seen in [1]. Still, reposition TX free
> calls as well, to have all kfree() operations performed consistently
> _after_ dma_unmap_*()/dma_free_*().
> 
> [1] Console screenshot with the problem reproduced:
> 
> salvator-x login: root
> root@salvator-x:~# ifconfig eth0 up
> Micrel KSZ9031 Gigabit PHY e6800000.ethernet-ffffffff:00: \
>        attached PHY driver [Micrel KSZ9031 Gigabit PHY]   \
>        (mii_bus:phy_addr=e6800000.ethernet-ffffffff:00, irq=235)
> IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
> root@salvator-x:~#
> root@salvator-x:~# ifconfig eth0 down
> ==================================================================
> BUG: KASAN: use-after-free in swiotlb_tbl_unmap_single+0xc4/0x35c
...
> ==================================================================
> Disabling lock debugging due to kernel taint
> root@salvator-x:~#
> 
> Fixes: a47b70ea86bd ("ravb: unmap descriptors when freeing rings")
> Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>

Applied and queued up for -stable, thanks.
Eugeniu Rosca June 6, 2017, 11:27 p.m. UTC | #3
On Tue, Jun 06, 2017 at 12:35:30PM +0300, Sergei Shtylyov wrote:
> Hello!
> 
> On 6/6/2017 1:08 AM, Eugeniu Rosca wrote:
> 
> >Commit a47b70ea86bd ("ravb: unmap descriptors when freeing rings") has
> >introduced the issue seen in [1] reproduced on H3ULCB board.
> >
> >Fix this by relocating the RX skb ringbuffer free operation, so that
> >swiotlb page unmapping can be done first. Freeing of aligned TX buffers
> >is not relevant to the issue seen in [1]. Still, reposition TX free
> >calls as well, to have all kfree() operations performed consistently
> >_after_ dma_unmap_*()/dma_free_*().
> 
>    Perhaps it's a material of a separate cleanup patch?

Many thanks for feedback. For the moment, with a number of sanitizers
and debugging options enabled (UBSAN, KASAN, KMEMLEAK, DMA_API_DEBUG), I
couldn't find any other obvious ravb driver failures in basic usecases
(didn't stress-test it though).

Regarding the reordering of kfree vs dma_* API calls, which might be
needed in other parts of the driver, this possibly will be highlighted
by special usecases like repetitive suspend/resume or the like. I will
happily share any other fixes, if such are developed on our side.

Best regards,
Eugeniu.
diff mbox

Patch

==================================================================
BUG: KASAN: use-after-free in swiotlb_tbl_unmap_single+0xc4/0x35c
Write of size 1538 at addr ffff8006d884f780 by task ifconfig/1649

CPU: 0 PID: 1649 Comm: ifconfig Not tainted 4.12.0-rc4-00004-g112eb07287d1 #32
Hardware name: Renesas H3ULCB board based on r8a7795 (DT)
Call trace:
[<ffff20000808f11c>] dump_backtrace+0x0/0x3a4
[<ffff20000808f4d4>] show_stack+0x14/0x1c
[<ffff20000865970c>] dump_stack+0xf8/0x150
[<ffff20000831f8b0>] print_address_description+0x7c/0x330
[<ffff200008320010>] kasan_report+0x2e0/0x2f4
[<ffff20000831eac0>] check_memory_region+0x20/0x14c
[<ffff20000831f054>] memcpy+0x48/0x68
[<ffff20000869ed50>] swiotlb_tbl_unmap_single+0xc4/0x35c
[<ffff20000869fcf4>] unmap_single+0x90/0xa4
[<ffff20000869fd14>] swiotlb_unmap_page+0xc/0x14
[<ffff2000080a2974>] __swiotlb_unmap_page+0xcc/0xe4
[<ffff2000088acdb8>] ravb_ring_free+0x514/0x870
[<ffff2000088b25dc>] ravb_close+0x288/0x36c
[<ffff200008aaf8c4>] __dev_close_many+0x14c/0x174
[<ffff200008aaf9b4>] __dev_close+0xc8/0x144
[<ffff200008ac2100>] __dev_change_flags+0xd8/0x194
[<ffff200008ac221c>] dev_change_flags+0x60/0xb0
[<ffff200008ba2dec>] devinet_ioctl+0x484/0x9d4
[<ffff200008ba7b78>] inet_ioctl+0x190/0x194
[<ffff200008a78c44>] sock_do_ioctl+0x78/0xa8
[<ffff200008a7a128>] sock_ioctl+0x110/0x3c4
[<ffff200008365a70>] vfs_ioctl+0x90/0xa0
[<ffff200008365dbc>] do_vfs_ioctl+0x148/0xc38
[<ffff2000083668f0>] SyS_ioctl+0x44/0x74
[<ffff200008083770>] el0_svc_naked+0x24/0x28

The buggy address belongs to the page:
page:ffff7e001b6213c0 count:0 mapcount:0 mapping:          (null) index:0x0
flags: 0x4000000000000000()
raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff
raw: 0000000000000000 ffff7e001b6213e0 0000000000000000 0000000000000000
page dumped because: kasan: bad access detected

Memory state around the buggy address:
 ffff8006d884f680: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff8006d884f700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff8006d884f780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
                   ^
 ffff8006d884f800: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff8006d884f880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================
Disabling lock debugging due to kernel taint
root@salvator-x:~#

Fixes: a47b70ea86bd ("ravb: unmap descriptors when freeing rings")
Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
---
 drivers/net/ethernet/renesas/ravb_main.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 3cd7989c007d..784782da3a85 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -230,18 +230,6 @@  static void ravb_ring_free(struct net_device *ndev, int q)
 	int ring_size;
 	int i;
 
-	/* Free RX skb ringbuffer */
-	if (priv->rx_skb[q]) {
-		for (i = 0; i < priv->num_rx_ring[q]; i++)
-			dev_kfree_skb(priv->rx_skb[q][i]);
-	}
-	kfree(priv->rx_skb[q]);
-	priv->rx_skb[q] = NULL;
-
-	/* Free aligned TX buffers */
-	kfree(priv->tx_align[q]);
-	priv->tx_align[q] = NULL;
-
 	if (priv->rx_ring[q]) {
 		for (i = 0; i < priv->num_rx_ring[q]; i++) {
 			struct ravb_ex_rx_desc *desc = &priv->rx_ring[q][i];
@@ -270,6 +258,18 @@  static void ravb_ring_free(struct net_device *ndev, int q)
 		priv->tx_ring[q] = NULL;
 	}
 
+	/* Free RX skb ringbuffer */
+	if (priv->rx_skb[q]) {
+		for (i = 0; i < priv->num_rx_ring[q]; i++)
+			dev_kfree_skb(priv->rx_skb[q][i]);
+	}
+	kfree(priv->rx_skb[q]);
+	priv->rx_skb[q] = NULL;
+
+	/* Free aligned TX buffers */
+	kfree(priv->tx_align[q]);
+	priv->tx_align[q] = NULL;
+
 	/* Free TX skb ringbuffer.
 	 * SKBs are freed by ravb_tx_free() call above.
 	 */