[Devel] [PATCH hci-8.1 v4 09/11] dm-ploop: fix use-after-free on the last inflight_md decrement
no-reply at sashiko.virtuozzo.com
no-reply at sashiko.virtuozzo.com
Mon Oct 12 16:40:12 MSK 2026
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] dm-ploop: ploop_destroy() self-deadlocks using wait_event_lock_irq() on wq.lock
--
commit e7aad5678d9b3ec2b2234a7e4beccd4508f457af
Author: Alexander Ivanov <alexander.ivanov at virtuozzo.com>
dm-ploop: fix use-after-free on the last inflight_md decrement
This patch moves the inflight_md decrement and wakeup to the end of the
piwb completion path, so that it is the last access to the ploop. The
decrement and wakeup are done under inflight_md_wq.lock, the waiters check
the counter under the same lock, and ploop_destroy() now waits for
inflight_md to reach zero before freeing anything.
Link: https://virtuozzo.atlassian.net/browse/VSTOR-148171
> diff --git a/drivers/md/dm-ploop-target.c b/drivers/md/dm-ploop-target.c
> --- a/drivers/md/dm-ploop-target.c
> +++ b/drivers/md/dm-ploop-target.c
[ ... ]
> @@ -192,6 +192,13 @@ static void ploop_destroy(struct ploop *ploop)
> if (ploop->kt_allocator)
> kthread_stop(ploop->kt_allocator->task);
>
> + /* BAT writes may still be completing from aio context */
> + spin_lock_irq(&ploop->inflight_md_wq.lock);
> + wait_event_lock_irq(ploop->inflight_md_wq,
> + !atomic_read(&ploop->inflight_md),
> + ploop->inflight_md_wq.lock);
> + spin_unlock_irq(&ploop->inflight_md_wq.lock);
> +
[Severity: High]
Can this deadlock on the waitqueue lock when inflight_md is non-zero?
ploop_destroy() takes inflight_md_wq.lock and then passes that same lock
as the lock argument to wait_event_lock_irq(). If the condition is
already true, the macro exits through its fast path and nothing goes
wrong. If inflight_md is still non-zero, the call chain is:
ploop_destroy()
spin_lock_irq(&ploop->inflight_md_wq.lock)
wait_event_lock_irq()
__wait_event_lock_irq()
___wait_event()
prepare_to_wait_event()
spin_lock_irqsave(&wq_head->lock, flags)
prepare_to_wait_event() acquires wq_head->lock, which is the lock the
caller already holds. The spinlock is not recursive, so the task would
spin on itself with interrupts disabled. The spin_unlock_irq() inside the
macro, before schedule(), is never reached.
This is the case the patch is meant to handle, namely BAT writes still
completing from aio context when ploop_destroy() runs.
wait_event_lock_irq() looks only usable when the lock argument is a
different lock from the waitqueue's own lock. ploop_suspend_submitting_pios()
uses wait_event_interruptible_locked_irq() for this situation.
Would it work to drop the outer spin_lock_irq()/spin_unlock_irq() and use a
plain wait_event() here, since the waker already takes the waitqueue lock
in wake_up_locked()? Alternatively, a *_locked_irq style wait could be
used, as in ploop_suspend_submitting_pios().
> WARN_ON(!llist_empty(&ploop->pios[PLOOP_LIST_PREPARE]));
> WARN_ON(!llist_empty(&ploop->llresubmit_pios));
> WARN_ON(!llist_empty(&ploop->enospc_pios));
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261012132646.41494-1-alexander.ivanov@virtuozzo.com?part=9
More information about the Devel
mailing list