net_dim_init_irq_moder() publishes the allocated struct via
dev->irq_moder before copying the moderation profiles. If a
kmemdup() fails, the error path frees the object but leaves
dev->irq_moder dangling. net_dim_free_irq_moder() treats a
non-NULL irq_moder as live: it dereferences
dev->irq_moder->rx_profile / tx_profile under RTNL and frees the
object a second time.
On current mainline the only in-tree caller of
net_dim_init_irq_moder() is virtnet_probe(), and its failure path
today does "goto free", which only reaches free_netdev(); nothing
calls net_dim_free_irq_moder() there, so the dangling pointer is
never dereferenced. The bug becomes reachable once the caller
unwinds through the existing free_irq_moder label, as virtio-net
starts doing in the follow-up fix:
virtnet_probe()
virtnet_init_irq_moder()
net_dim_init_irq_moder() /* kmemdup fails:
kfree(moder),
dev->irq_moder stale */
goto free_irq_moder
virtnet_free_irq_moder()
net_dim_free_irq_moder() /* non-NULL irq_moder =>
rtnl_dereference(
dev->irq_moder->rx_profile)
use-after-free,
kfree() a second time */
This patch is the prerequisite that makes such an unwind safe;
without it the follow-up would trade the virtqueue leak for a
use-after-free and a double kfree on this error path.
NULL the pointer after freeing it, so a later
net_dim_free_irq_moder() is a no-op and the device is left as if
initialization never happened.
Fixes: f750dfe825b90 ("ethtool: provide customized dim profile management")
Suggested-by: Jakub Kicinski <[email protected]>
Signed-off-by: Jianlin Shi <[email protected]>
---
lib/dim/net_dim.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/dim/net_dim.c b/lib/dim/net_dim.c
index d8d4f6553559..bf59deae6a29 100644
--- a/lib/dim/net_dim.c
+++ b/lib/dim/net_dim.c
@@ -141,6 +141,7 @@ int net_dim_init_irq_moder(struct net_device *dev, u8
profile_flags,
kfree(rxp);
free_moder:
kfree(moder);
+ dev->irq_moder = NULL;
return -ENOMEM;
}
EXPORT_SYMBOL(net_dim_init_irq_moder);
--
2.43.0