Re: [PATCH 4.19 023/191] gpio: gpio-grgpio: fix possible sleep-in-atomic-context bugs in grgpio_irq_map/unmap()

From: Pavel Machek
Date: Sun Feb 23 2020 - 05:43:12 EST


Hi!

> From: Jia-Ju Bai <baijiaju1990@xxxxxxxxx>
>
> [ Upstream commit e36eaf94be8f7bc4e686246eed3cf92d845e2ef8 ]
>
> The driver may sleep while holding a spinlock.

True.

But you can't fix the bug by simply removing the locking, as now
nothing prevents grgpio_irq_unmap() from running while
grgpio_irq_map() is proceeding.

grgpio_irq_map()
lirq->irq = irq;
(drops the lock)

grgpio_irq_unmap()
(gets the lock)
if (lirq->irq == irq) {
...
(proceeds to work with half-initialized structure)

Best regards,
Pavel


> index 60a1556c570a4..c1be299e5567b 100644
> --- a/drivers/gpio/gpio-grgpio.c
> +++ b/drivers/gpio/gpio-grgpio.c
> @@ -258,17 +258,16 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
> lirq->irq = irq;
> uirq = &priv->uirqs[lirq->index];
> if (uirq->refcnt == 0) {
> + spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
> ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
> dev_name(priv->dev), priv);
> if (ret) {
> dev_err(priv->dev,
> "Could not request underlying irq %d\n",
> uirq->uirq);
> -
> - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
> -
> return ret;
> }
> + spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
> }
> uirq->refcnt++;
>
> @@ -314,8 +313,11 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
> if (index >= 0) {
> uirq = &priv->uirqs[lirq->index];
> uirq->refcnt--;
> - if (uirq->refcnt == 0)
> + if (uirq->refcnt == 0) {
> + spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
> free_irq(uirq->uirq, priv);
> + return;
> + }
> }
>
> spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

Attachment: signature.asc
Description: Digital signature