Re: [BUG] WARNING: refcount bug in sync_timeline_signal
From: Christian König
Date: Wed Aug 26 2026 - 04:41:15 EST
Hi Jaeyoung,
the SW_SYNC component is pretty much deprecated, only kept for user space unit testing and not maintained any more.
Background is that even if you fix all those known bugs you can still hard crash the Linux kernel with it. See the big warning in th KConfig and the kernel tainting when that component is enabled as well.
So if you have patches which fixes things I'm happy to take them, but nobody will investigate in bug reports on that component any more.
Regards,
Christian.
On 8/24/26 17:56, Jaeyoung Chung wrote:
> Hello,
>
> We found a "WARNING: refcount bug in sync_timeline_signal" on Linux v7.2.
> The issue was found by our own race fuzzer. We have not analyzed the root cause,
> so we do not have a proposed fix to offer.
>
> To reproduce the race reliably, we applied the delay patch below to the
> kernel and ran the C reproducer as root inside an x86_64 QEMU guest. The
> crash log we observed, the delay patch and the reproducer are all included
> below.
>
> The following kernel config options are required to reproduce the issue:
> CONFIG_SW_SYNC=y
> CONFIG_SYNC_FILE=y
> CONFIG_DMA_SHARED_BUFFER=y
> CONFIG_DEBUG_FS=y
> CONFIG_KASAN=y
>
> We hope this report is useful. Please let us know if any further
> information would help.
>
> Reported-by: Eulgyu Kim <eulgyukim@xxxxxxxxx>
> Reported-by: Jaeyoung Chung <jjy600901@xxxxxxxxx>
>
> Kernel delay patch:
> ==================================================================
> diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
> index 8df20b0218a9..d30ce9d915ba 100644
> --- a/drivers/dma-buf/sw_sync.c
> +++ b/drivers/dma-buf/sw_sync.c
> @@ -8,6 +8,7 @@
> #include <linux/file.h>
> #include <linux/fs.h>
> #include <linux/uaccess.h>
> +#include <linux/delay.h>
> #include <linux/panic.h>
> #include <linux/slab.h>
> #include <linux/sync_file.h>
> @@ -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);
> + }
> +
> obj->value += inc;
>
> list_for_each_entry_safe(pt, next, &obj->pt_list, link) {
> ==================================================================
>
> C reproducer:
> ==================================================================
> #define _GNU_SOURCE
> #include <errno.h>
> #include <fcntl.h>
> #include <pthread.h>
> #include <sched.h>
> #include <stdint.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <sys/ioctl.h>
> #include <sys/mount.h>
> #include <sys/prctl.h>
> #include <sys/stat.h>
> #include <time.h>
> #include <unistd.h>
>
> #define SYSCHK(x) ({ long __r = (long)(x); if (__r == -1L) { perror(#x); exit(1); } __r; })
>
> #define SW_SYNC_IOC_CREATE_FENCE 0xc0285700u
> #define SW_SYNC_IOC_INC 0x40045701u
> #define SWSYNC "/sys/kernel/debug/sync/sw_sync"
> #define BIAS_US 2000
>
> struct fence_data {
> uint32_t value;
> char name[32];
> int32_t fence;
> };
>
> static volatile int g_round, g_stop, g_tl_fd = -1, g_fence_fd = -1;
> static volatile int g_armed, g_done0, g_done1;
>
> static void spin_us(long us)
> {
> struct timespec a, b;
>
> clock_gettime(CLOCK_MONOTONIC, &a);
> do {
> clock_gettime(CLOCK_MONOTONIC, &b);
> __asm__ __volatile__("pause" ::: "memory");
> } while ((b.tv_sec - a.tv_sec) * 1000000L + (b.tv_nsec - a.tv_nsec) / 1000L < us);
> }
>
> static void pin_cpu(int cpu)
> {
> cpu_set_t set;
>
> CPU_ZERO(&set);
> CPU_SET(cpu, &set);
> sched_setaffinity(0, sizeof(set), &set);
> }
>
> static int wait_round(int *last)
> {
> while (g_round == *last && !g_stop)
> sched_yield();
> if (g_stop)
> return 0;
> *last = g_round;
> return 1;
> }
>
> /* T1: advances the timeline, signalling the pt */
> static void *thr_inc(void *a)
> {
> unsigned int v = 1;
> int last = 0;
>
> (void)a;
> prctl(PR_SET_NAME, "syzrepro1", 0, 0, 0);
> pin_cpu(0);
> while (wait_round(&last)) {
> g_armed = 1;
> __sync_synchronize();
> ioctl(g_tl_fd, SW_SYNC_IOC_INC, &v);
> __sync_synchronize();
> g_done1 = 1;
> }
> return NULL;
> }
>
> /* T0: closes the fence mid-signal, dropping the pt's last reference */
> static void *thr_close(void *a)
> {
> int last = 0;
>
> (void)a;
> prctl(PR_SET_NAME, "syzrepro0", 0, 0, 0);
> pin_cpu(1);
> while (wait_round(&last)) {
> while (!g_armed && !g_stop)
> __asm__ __volatile__("pause" ::: "memory");
> if (g_stop)
> break;
> spin_us(BIAS_US);
> close(g_fence_fd);
> __sync_synchronize();
> g_done0 = 1;
> }
> return NULL;
> }
>
> static int open_sw_sync(void)
> {
> int fd = open(SWSYNC, O_RDWR);
>
> if (fd >= 0 || errno != ENOENT)
> return fd;
> mkdir("/sys/kernel/debug", 0755);
> mount("debugfs", "/sys/kernel/debug", "debugfs", 0, NULL);
> return open(SWSYNC, O_RDWR);
> }
>
> int main(void)
> {
> pthread_t t0, t1;
> long i;
>
> close(SYSCHK(open_sw_sync()));
> pthread_create(&t1, NULL, thr_inc, NULL);
> pthread_create(&t0, NULL, thr_close, NULL);
>
> for (i = 0; i < 200 && !g_stop; i++) {
> struct fence_data d = { .value = 1, .name = "syzrepro_pt", .fence = -1 };
> int tl = SYSCHK(open_sw_sync()), w;
>
> SYSCHK(ioctl(tl, SW_SYNC_IOC_CREATE_FENCE, &d));
> g_tl_fd = tl;
> g_fence_fd = d.fence;
> g_armed = g_done0 = g_done1 = 0;
> __sync_synchronize();
> g_round = i + 1;
>
> for (w = 0; w < 5000 && !(g_done0 && g_done1); w++) {
> struct timespec ts = { 0, 1000000 };
>
> nanosleep(&ts, NULL);
> }
> close(tl);
> }
>
> g_stop = 1;
> __sync_synchronize();
> g_round++;
> pthread_join(t1, NULL);
> pthread_join(t0, NULL);
> return 0;
> }
> ==================================================================
>
> Crash log:
> ==================================================================
> refcount_t: addition on 0; use-after-free.
> WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x76/0xd0 lib/refcount.c:25, CPU#0: syzrepro1/402
> Modules linked in:
> CPU: 0 UID: 0 PID: 402 Comm: syzrepro1 Tainted: G L 7.2.0-dirty #2 PREEMPT
> Tainted: [L]=SOFTLOCKUP
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014
> RIP: 0010:refcount_warn_saturate+0x76/0xd0 lib/refcount.c:25
> Code: 3d ff e4 bb 04 67 48 0f b9 3a eb 4d 85 db 74 2f 83 fb 01 75 38 48 8d 3d f8 e4 bb 04 67 48 0f b9 3a eb 36 48 8d 3d fa e4 bb 04 <67> 48 0f b9 3a eb 28 48 8d 3d fc e4 bb 04 67 48 0f b9 3a eb 1a 48
> RSP: 0018:ffff88810cd47d68 EFLAGS: 00010046
> RAX: 0000000000000000 RBX: 0000000000000002 RCX: dffffc0000000000
> RDX: 0000000000000001 RSI: 0000000000000004 RDI: ffffffff9be2c840
> RBP: ffff888102a5dc40 R08: ffff888102a5d73b R09: 1ffff1102054bae7
> R10: dffffc0000000000 R11: ffffed102054bae8 R12: dffffc0000000000
> R13: ffff888102a5d740 R14: ffff888102a5d738 R15: ffff888102a5d738
> FS: 00007ae687b8f6c0(0000) GS:ffff88817d75f000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000578dd65f7e58 CR3: 000000010b72c000 CR4: 00000000000006f0
> Call Trace:
> <TASK>
> __refcount_add include/linux/refcount.h:-1 [inline]
> __refcount_inc include/linux/refcount.h:366 [inline]
> refcount_inc include/linux/refcount.h:383 [inline]
> kref_get include/linux/kref.h:45 [inline]
> dma_fence_get include/linux/dma-fence.h:317 [inline]
> sync_timeline_signal+0x383/0x550 drivers/dma-buf/sw_sync.c:229
> sw_sync_ioctl_inc drivers/dma-buf/sw_sync.c:410 [inline]
> sw_sync_ioctl+0x140/0x980 drivers/dma-buf/sw_sync.c:475
> vfs_ioctl fs/ioctl.c:51 [inline]
> __do_sys_ioctl fs/ioctl.c:597 [inline]
> __se_sys_ioctl+0xb6/0x100 fs/ioctl.c:583
> do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> do_syscall_64+0xf7/0x370 arch/x86/entry/syscall_64.c:94
> entry_SYSCALL_64_after_hwframe+0x76/0x7e
> RIP: 0033:0x7ae687c90d6b
> Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
> RSP: 002b:00007ae687b8edd0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
> RAX: ffffffffffffffda RBX: 00007ae687b8ee3c RCX: 00007ae687c90d6b
> RDX: 00007ae687b8ee38 RSI: 0000000040045701 RDI: 0000000000000003
> RBP: 0000000000000000 R08: 0000000000000000 R09: 00007ffcdb19abc7
> R10: 0000000000000000 R11: 0000000000000246 R12: ffffffffffffff80
> R13: 0000000000000000 R14: 00007ffcdb19aad0 R15: 00007ae68738f000
> </TASK>
> ----------------
> Code disassembly (best guess):
> 0: 3d ff e4 bb 04 cmp $0x4bbe4ff,%eax
> 5: 67 48 0f b9 3a ud1 (%edx),%rdi
> a: eb 4d jmp 0x59
> c: 85 db test %ebx,%ebx
> e: 74 2f je 0x3f
> 10: 83 fb 01 cmp $0x1,%ebx
> 13: 75 38 jne 0x4d
> 15: 48 8d 3d f8 e4 bb 04 lea 0x4bbe4f8(%rip),%rdi # 0x4bbe514
> 1c: 67 48 0f b9 3a ud1 (%edx),%rdi
> 21: eb 36 jmp 0x59
> 23: 48 8d 3d fa e4 bb 04 lea 0x4bbe4fa(%rip),%rdi # 0x4bbe524
> * 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
> 2f: eb 28 jmp 0x59
> 31: 48 8d 3d fc e4 bb 04 lea 0x4bbe4fc(%rip),%rdi # 0x4bbe534
> 38: 67 48 0f b9 3a ud1 (%edx),%rdi
> 3d: eb 1a jmp 0x59
> 3f: 48 rex.W
> ==================================================================
>
>