Re: [PATCH v6] serial: 8250: fix use-after-free in IRQ chain handling

From: Wang Zhaolong

Date: Wed Jul 08 2026 - 03:38:51 EST



> From: "Jiri Slaby"<jirislaby@xxxxxxxxxx>
> Date:  Wed, Jul 8, 2026, 2:04 PM
> Subject:  Re: [PATCH v6] serial: 8250: fix use-after-free in IRQ chain handling
> To: "Qiliang Yuan"<realwujing@xxxxxxxxx>, "Greg Kroah-Hartman"<gregkh@xxxxxxxxxxxxxxxxxxx>, "Anton Vorontsov"<avorontsov@xxxxxxxxxxxxx>, "Alan Cox"<alan@xxxxxxxxxx>
> Cc: <linux-kernel@xxxxxxxxxxxxxxx>, <linux-serial@xxxxxxxxxxxxxxx>, "Wang Zhaolong"<wangzhaolong@xxxxxxxxx>
> Ah, now I see you are fixing the same thing as:
> https://lore.kernel.org/all/20260708031115.3757150-1-wangzhaolong@xxxxxxxxx/
> 
> I did not look up who of you was first.
> 
> But:
> Reported-by: Wang Zhaolong <wangzhaolong@xxxxxxxxx>
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221579
> 
> Looks like he reported and apparently tries to fix that too ;). You were 
> obviously CCed, talk to them and don't send two patches for the same issue.
> 
> On 07. 07. 26, 16:06, Qiliang Yuan wrote:
> ...
> > --- a/drivers/tty/serial/8250/8250_core.c
> > +++ b/drivers/tty/serial/8250/8250_core.c
> > @@ -131,10 +131,11 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
> >    * - allocate a new one, add it to the hashtable and return it.
> >    */
> >   static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_port *up)
> > +        __must_hold(&hash_mutex)
> >   {
> >           struct irq_info *i;
> >   
> > -        guard(mutex)(&hash_mutex);
> > +        lockdep_assert_held(&hash_mutex);
> >   
> >           hash_for_each_possible(irq_lists, i, node, up->port.irq)
> >                   if (i->irq == up->port.irq)
> > @@ -151,19 +152,37 @@ static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_por
> >           return i;
> >   }
> >   
> > +/*
> > + * serial_link_irq_chain() hooks the given 8250 port into the IRQ chain.
> > + *
> > + * hash_mutex must be held from the hash lookup through the first
> > + * request_irq() completion.  Dropping it earlier allows a concurrent
> > + * serial_unlink_irq_chain() to race in after i->head is published but
> > + * before the IRQ is fully set up — another port sharing the IRQ can then
> > + * join the chain and run the shared-IRQ THRE test while IRQ startup is
> > + * still in progress, triggering an "Unbalanced enable for IRQ" warning
> > + * in kernel/irq/manage.c.
> > + */
> >   static int serial_link_irq_chain(struct uart_8250_port *up)
> >   {
> >           struct irq_info *i;
> >           int ret;
> >   
> > +        guard(mutex)(&hash_mutex);
> 
> hash_mutex is no longer an appropriate name for this lock.
> 
> > +
> >           i = serial_get_or_create_irq_info(up);
> >           if (IS_ERR(i))
> >                   return PTR_ERR(i);
> >   
> > +        /*
> > +         * Serialise against the list manipulation in the interrupt handler
> > +         * and in serial_unlink_irq_chain().  hash_mutex is still held which
> > +         * prevents serial_unlink_irq_chain() from entering and freeing the
> > +         * irq_info until the first request_irq() completes.
> > +         */
> >           scoped_guard(spinlock_irq, &i->lock) {
> >                   if (i->head) {
> >                           list_add(&up->list, i->head);
> > -
> 
> Unrelated change.
> 
> >                           return 0;
> >                   }
> >   
> > @@ -171,11 +190,14 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
> >                   i->head = &up->list;
> >           }
> >   
> > -        ret = request_irq(up->port.irq, serial8250_interrupt, up->port.irqflags, up->port.name, i);
> > -        if (ret < 0)
> > +        ret = request_irq(up->port.irq, serial8250_interrupt,
> > +                          up->port.irqflags, up->port.name, i);
> > +        if (ret < 0) {
> >                   serial_do_unlink(i, up);
> > +                return ret;
> > +        }
> >   
> > -        return ret;
> > +        return 0;
> 
> Unrelated and mainly unneeded change.
> 
> thanks,
> -- 
> js
> suse labs
> 

Hi Jiri, Qiliang,

Thanks for looking at this.

>From my side, I do not want to make this a patch ownership discussion.  I have
sent my v3 here:

  https://lore.kernel.org/all/20260708072306.3921604-1-wangzhaolong@xxxxxxxxx/

It addresses the lock rename comment, keeps the change focused on the required
locking, and has been verified again with the QEMU ttyS1/ttyS3 shared IRQ
reproducer.

My main goal is simply to get this reproducible mainline regression fixed
soon, because with panic_on_warn=1 it breaks my regular build/regression
testing.  I do not have any promotion or credit pressure around which patch is
taken.

So I think the choice should be left to the maintainers.  Please take whichever
version you think is the better basis for mainline.

Thanks,
Wang Zhaolong