Re: [BUG] WARNING: refcount bug in sync_timeline_signal

[email protected]
Newsgroups org.freedesktop.lists.dri-devel
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] The commit improperly merges fuzzer reproducer code that intentionally stalls the kernel, introducing a severe 50ms delay inside a spinlock with local interrupts disabled.

Pre-existing issues:
- [Critical] Calling `dma_fence_get()` in `sync_timeline_signal()` on a fence whose refcount may have already dropped to 0 leads to a use-after-free, double-free, and rb-tree corruption.
--

--- Patch [1]: [BUG] WARNING: refcount bug in sync_timeline_signal ---
commit 6c2b9513def2f661abe36d3f3a4c129d8212ea60
Author: Jaeyoung Chung <[email protected]>

WARNING: refcount bug in sync_timeline_signal

This commit merges a fuzzer's reproducer delay patch directly into the
sw_sync subsystem. It does not provide a fix for the underlying race
condition, but instead introduces an intentional delay.

> diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
> index 8df20b0218a9e..d30ce9d915ba7 100644
> --- a/drivers/dma-buf/sw_sync.c
> +++ b/drivers/dma-buf/sw_sync.c

[ ... ]

> @@ -215,6 +216,10 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
>  
>  	spin_lock_irq(&obj->lock);
>  
> +	if (strncmp(current->comm, "syzrepro1", 9) == 0) {
> +		mdelay(50);
> +	}
> +

[Severity: High]
Is it intentional to merge reproducer delay code into the tree?

Adding a 50-millisecond busy loop (mdelay(50)) inside a critical section
protected by spin_lock_irq(&obj->lock) in sync_timeline_signal() can cause
severe latency spikes and missed hardware interrupts.

An unprivileged user could trigger this by naming their task 'syzrepro1' and
interacting with the sw_sync subsystem to create a local Denial of Service.

>  	obj->value += inc;
>  
>  	list_for_each_entry_safe(pt, next, &obj->pt_list, link) {

[Severity: Critical]
This is a pre-existing issue, but does sync_timeline_signal() unsafely
call dma_fence_get() on a fence whose refcount may have already dropped to 0?

When a userspace program closes a sync_file descriptor, it drops the
underlying sync_pt fence refcount to 0, which triggers
timeline_fence_release().

timeline_fence_release() blocks waiting for obj->lock. Concurrently, if
sync_timeline_signal() holds obj->lock and iterates over obj->pt_list, it
encounters the 0-refcount fence and unconditionally calls
dma_fence_get(&pt->base):

drivers/dma-buf/sw_sync.c:sync_timeline_signal() {
    ...
    dma_fence_get(&pt->base);
    list_move_tail(&pt->link, &signalled);
    rb_erase(&pt->node, &obj->pt_tree);
    ...
}

It then moves the fence to a local list, erases it from the tree, and
unlocks.

timeline_fence_release() then acquires the lock, illegally modifies the other
thread's local list, performs a double rb_erase() on the tree, and frees the
fence:

drivers/dma-buf/sw_sync.c:timeline_fence_release() {
    ...
    if (!list_empty(&pt->link)) {
        list_del(&pt->link);
        rb_erase(&pt->node, &parent->pt_tree);
    }
    ...
}

Finally, sync_timeline_signal() iterates its local list, accessing and
putting the freed fence, leading to a use-after-free and double free.

Would using dma_fence_get_rcu() in sync_timeline_signal() safely increment
the refcount only if it is non-zero?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.