| From b4ce5a5b2972d12f3c2878f3ba26bb271a463283 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 18 Aug 2025 14:12:45 -0700 |
| Subject: gve: prevent ethtool ops after shutdown |
| |
| From: Jordan Rhee <jordanrhee@google.com> |
| |
| [ Upstream commit 75a9a46d67f46d608205888f9b34e315c1786345 ] |
| |
| A crash can occur if an ethtool operation is invoked |
| after shutdown() is called. |
| |
| shutdown() is invoked during system shutdown to stop DMA operations |
| without performing expensive deallocations. It is discouraged to |
| unregister the netdev in this path, so the device may still be visible |
| to userspace and kernel helpers. |
| |
| In gve, shutdown() tears down most internal data structures. If an |
| ethtool operation is dispatched after shutdown(), it will dereference |
| freed or NULL pointers, leading to a kernel panic. While graceful |
| shutdown normally quiesces userspace before invoking the reboot |
| syscall, forced shutdowns (as observed on GCP VMs) can still trigger |
| this path. |
| |
| Fix by calling netif_device_detach() in shutdown(). |
| This marks the device as detached so the ethtool ioctl handler |
| will skip dispatching operations to the driver. |
| |
| Fixes: 974365e51861 ("gve: Implement suspend/resume/shutdown") |
| Signed-off-by: Jordan Rhee <jordanrhee@google.com> |
| Signed-off-by: Jeroen de Borst <jeroendb@google.com> |
| Link: https://patch.msgid.link/20250818211245.1156919-1-jeroendb@google.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/google/gve/gve_main.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c |
| index ec189f0703f9..241a541b8edd 100644 |
| --- a/drivers/net/ethernet/google/gve/gve_main.c |
| +++ b/drivers/net/ethernet/google/gve/gve_main.c |
| @@ -2373,6 +2373,8 @@ static void gve_shutdown(struct pci_dev *pdev) |
| struct gve_priv *priv = netdev_priv(netdev); |
| bool was_up = netif_carrier_ok(priv->dev); |
| |
| + netif_device_detach(netdev); |
| + |
| rtnl_lock(); |
| if (was_up && gve_close(priv->dev)) { |
| /* If the dev was up, attempt to close, if close fails, reset */ |
| -- |
| 2.50.1 |
| |