RE: [PATCH net] ptp: netc: fix potential interrupt storm caused by incorrect unbind order
"Wei Fang (OSS)" <[email protected]>
| Newsgroups | dev.linux.lists.imx,dev.linux.lists.sashiko-reviews,org.kernel.vger.netdev |
|---|---|
| Message-ID | <GV2PR04MB11739D22B9ABBFA122A56BBAE88CC2@GV2PR04MB11739.eurprd04.prod.outlook.com> |
> > diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c
> > index 5e381c354d746..3bab86afe8e23 100644
> > --- a/drivers/ptp/ptp_netc.c
> > +++ b/drivers/ptp/ptp_netc.c
> > @@ -1019,9 +1019,9 @@ static void netc_timer_remove(struct pci_dev
> *pdev)
> > {
> > struct netc_timer *priv = pci_get_drvdata(pdev);
> >
> > + ptp_clock_unregister(priv->clock);
> > + netc_timer_wr(priv, NETC_TMR_TEMASK, 0);
>
> [Severity: High]
> Does moving ptp_clock_unregister() before masking hardware interrupts
> introduce a use-after-free regression in the interrupt handler?
That is indeed a problem, I will fix it in next version.
>
> If EXTTS events are configured, ptp_clock_unregister() drops the final
> device reference and frees priv->clock if no file descriptors are open.
>
> Because the hardware interrupt mask (NETC_TMR_TEMASK) is not cleared until
> the next instruction, and free_irq() has not yet been called, the hardware
> can still fire an EXTTS interrupt.
>
> If this occurs, the ISR netc_timer_isr() processes the event and
> unconditionally dereferences the freed clock object:
>
> netc_timer_isr() -> netc_timer_handle_etts_event() {
> ...
> ptp_clock_event(priv->clock, &event);
> ...
> }
>
> > netc_timer_wr(priv, NETC_TMR_CTRL, 0);
> > - ptp_clock_unregister(priv->clock);
> > netc_timer_free_msix_irq(priv);
> > netc_timer_pci_remove(pdev);
> > }
>
> [Severity: High]
> This isn't a bug introduced by this patch, but can the driver encounter a
> hard lockup during probe on kexec or an unclean shutdown?
>
> Because the NETC timer does not support PCIe FLR, hardware registers
> retain their state. In netc_timer_probe(), the driver requests the IRQ via
> netc_timer_init_msix_irq() before resetting the hardware state.
>
> If the hardware has a pending interrupt, it fires immediately upon
> request_irq(). At this point, priv->tmr_emask is 0.
>
> The ISR netc_timer_isr() masks the hardware status with priv->tmr_emask
> and writes 0 back to the Write-1-to-Clear (W1C) register, failing to clear
> the pending hardware interrupt:
>
> netc_timer_isr() {
> ...
> tmr_event = netc_timer_rd(priv, NETC_TMR_TEVENT);
> tmr_event &= priv->tmr_emask;
> /* Clear interrupts status */
> netc_timer_wr(priv, NETC_TMR_TEVENT, tmr_event);
> ...
> }
>
> The ISR then defeats the kernel's spurious interrupt detection by
> unconditionally returning IRQ_HANDLED, causing the interrupt controller to
> re-invoke the ISR in an infinite loop:
>
> netc_timer_isr() {
> ...
> return IRQ_HANDLED;
> }
>
> --
> Sashiko AI
> review · https://sashiko.dev/#/patchset/20260724065116.521893-1-wei.fang@
> oss.nxp.com?part=1