mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] net: hinic3: unregister event callback on remove
@ 2026-09-16  3:24 Guangshuo Li
  2026-09-17 18:24 ` netdev-bot+sashiko
  0 siblings, 1 reply; 2+ messages in thread
From: Guangshuo Li @ 2026-09-16  3:24 UTC (permalink / raw)
  To: Fan Gong, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Gur Stavi, Xin Guo, netdev,
	linux-kernel
  Cc: Guangshuo Li, stable

hinic3_nic_probe() registers the NIC event callback with
hinic3_adev_event_register(). All probe failure paths unregister the
callback before returning.

The normal removal path, however, tears down and frees the NIC device
without calling hinic3_adev_event_unregister(), leaving the auxiliary
device event callback pointing to hinic3_nic_event().

If an event is delivered after the NIC private data has been released,
the callback may dereference the freed nic_dev and netdev objects.

Unregister the NIC event callback before starting the device teardown.

This issue was found by manual code inspection.

Fixes: 17fcb3dc12bb ("hinic3: module initialization and tx/rx logic")
Cc: stable@vger.kernel.org
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
 drivers/net/ethernet/huawei/hinic3/hinic3_main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index 0a888fe4c975..42e2ad179a9f 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
@@ -499,6 +499,8 @@ static void hinic3_nic_remove(struct auxiliary_device *adev)
 	if (!hinic3_support_nic(nic_dev->hwdev))
 		return;
 
+	hinic3_adev_event_unregister(adev);
+
 	netdev = nic_dev->netdev;
 	unregister_netdev(netdev);
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] net: hinic3: unregister event callback on remove
  2026-09-16  3:24 [PATCH] net: hinic3: unregister event callback on remove Guangshuo Li
@ 2026-09-17 18:24 ` netdev-bot+sashiko
  0 siblings, 0 replies; 2+ messages in thread
From: netdev-bot+sashiko @ 2026-09-17 18:24 UTC (permalink / raw)
  To: lgs201920130244
  Cc: gongfan1, andrew+netdev, davem, edumazet, kuba, pabeni,
	gur.stavi, guoxin09, netdev, linux-kernel, stable

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 (1) · Low: 0

- [Medium] The commit message asserts a live use-after-free ("If an event
  is delivered after the NIC private data has been released, the…

Pre-existing issues:
- [Medium] hinic3_del_one_adev()
  (drivers/net/ethernet/huawei/hinic3/hinic3_lld.c:94-113) implements…

--

net: hinic3: unregister event callback on remove

This adds a hinic3_adev_event_unregister() call at the start of
hinic3_nic_remove() so the auxiliary device event callback is cleared before
the NIC device is torn down, matching what the probe failure paths already
do.

> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> index 0a888fe4c975b..42e2ad179a9f5 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> @@ -499,6 +499,8 @@ static void hinic3_nic_remove(struct auxiliary_device *adev)
>  	if (!hinic3_support_nic(nic_dev->hwdev))
>  		return;
>  
> +	hinic3_adev_event_unregister(adev);
> +

[Severity: Medium]
Is there an event delivery path in this tree that can actually reach
hinic3_nic_event()?

The commit message says:

    If an event is delivered after the NIC private data has been released,
    the callback may dereference the freed nic_dev and netdev objects.

Grepping drivers/net/ethernet/huawei/hinic3/ shows the only accesses to
struct hinic3_adev::event are the two assignments:

  hinic3_lld.c:hinic3_adev_event_register() {
	hadev = container_of(adev, struct hinic3_adev, adev);
	hadev->event = event_handler;
  }

  hinic3_lld.c:hinic3_adev_event_unregister() {
	hadev = container_of(adev, struct hinic3_adev, adev);
	hadev->event = NULL;
  }

Nothing loads and calls hadev->event.  The hardware event paths that do
exist dispatch through aeqs->aeq_cb[] / ceqs->ceq_cb[] in hinic3_eqs.c, and
hinic3_nic_event() is referenced only as the argument to the
hinic3_adev_event_register() call in hinic3_nic_probe().

If that is correct, then this change restores register/unregister symmetry
but does not close a reachable failure.  Should the Fixes: tag for
17fcb3dc12bb and the Cc: stable@vger.kernel.org be dropped, and the message
reworded as a symmetry or cleanup change?  Alternatively, could the concrete
dispatch path that makes the dereference reachable be named in the message?

One further note for whenever a dispatcher is added: clearing a plain
function pointer gives no barrier against a call that is already in flight,
so the symmetry alone would not be sufficient there either.

[Severity: Medium]
This isn't a bug introduced by this patch, but the event-versus-teardown
exclusion that this ordering change leans on is a hand-rolled bit lock in
hinic3_del_one_adev():

  hinic3_lld.c:hinic3_del_one_adev() {
	timeout = read_poll_timeout(test_and_set_bit, state, !state,
				    HINIC3_EVENT_POLL_SLEEP_US,
				    HINIC3_EVENT_POLL_TIMEOUT_US,
				    false, svc_type, &pci_adapter->state);

	hadev = pci_adapter->hadev[svc_type];
	auxiliary_device_delete(&hadev->adev);
	auxiliary_device_uninit(&hadev->adev);
	pci_adapter->hadev[svc_type] = NULL;
	if (!timeout)
		clear_bit(svc_type, &pci_adapter->state);
  }

The bit svc_type of pci_adapter->state is set on entry and cleared on exit
to guard a code region, which is invisible to lockdep and provides no
ordering or fairness guarantees.

Does this loop also fail open?  On -ETIMEDOUT the bit was never acquired,
yet auxiliary_device_delete() / auxiliary_device_uninit() run anyway, which
drives hinic3_nic_remove() and free_netdev() while, by the code's own
assumption, another context still owns the bit.

On that same timeout path clear_bit() is skipped, so the bit stays set for
that service type.  Would every later add or delete of that service then
burn the full HINIC3_EVENT_POLL_TIMEOUT_US poll and fail open again?

Since the callers already hold pci_adapter->pdev_mutex, could that mutex
plus a synchronous flush or cancel of the event source replace the bit
entirely?

Today the only accesses to pci_adapter->state are the test_and_set_bit and
clear_bit above, so the first test_and_set_bit always observes the bit clear
and the timeout branch is not reachable, but that changes as soon as event
dispatch is added.

>  	netdev = nic_dev->netdev;
>  	unregister_netdev(netdev);
>

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260916032427.2899987-1-lgs201920130244%40gmail.com

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-17 18:24 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16  3:24 [PATCH] net: hinic3: unregister event callback on remove Guangshuo Li
2026-09-17 18:24 ` netdev-bot+sashiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®