[BUG REPORT] ntfs: possible circular locking dependency in ntfs_mft_writepages

From: yangguikun19

Date: Mon Jun 22 2026 - 02:24:39 EST


Hello,

syzkaller found a reproducible lockdep warning in the NTFS filesystem on a vanilla Linux 7.1.1 kernel. This is a possible circular locking dependency in ntfs_mft_writepages()/ntfs_write_mft_block() when writing back $MFT records from a crafted NTFS image.

I have not confirmed an exact public syzbot duplicate for this title/function. The closest known public family I found is a different classic-NTFS deadlock report in ntfs_read_folio, so I am reporting this as a separate issue.

Kernel:
  Linux 7.1.1
  target: linux/amd64
  config highlights: CONFIG_NTFS_FS=y, CONFIG_NTFS3_FS=m, CONFIG_LOCKDEP=y, CONFIG_PROVE_LOCKING=y, KASAN enabled

Reproducer status:
  syzkaller generated both syz and C reproducers.
  An isolated same-kernel replay with syz-repro -count 1 confirmed the issue from the original execution log.
  The isolated replay printed:
    2026/06/22 05:13:52 reproducing crash 'possible deadlock in ntfs_mft_writepages': program crashed: possible deadlock in ntfs_mft_writepages
    2026/06/22 05:13:52 reproducing crash 'possible deadlock in ntfs_mft_writepages': single: successfully extracted reproducer
    2026/06/22 05:13:52 reproducing crash 'possible deadlock in ntfs_mft_writepages': found reproducer with 2 syscalls

High-level trigger:
  syz_mount_image$ntfs(... crafted NTFS image ...)
  setxattr$security_ima("./file0", ...)

Lockdep report excerpt:

wlan1: Creating new IBSS network, BSSID 50:50:50:50:50:50
======================================================
WARNING: possible circular locking dependency detected
7.1.1 #1 Tainted: G        W          
------------------------------------------------------
kworker/u9:5/4025 is trying to acquire lock:
ff11000023a05630 (&mft_ni_runlist_lock_key){++++}-{4:4}, at: ntfs_write_mft_block fs/ntfs/mft.c:2825 [inline]
ff11000023a05630 (&mft_ni_runlist_lock_key){++++}-{4:4}, at: ntfs_mft_writepages+0x1113/0x2410 fs/ntfs/mft.c:2955

but task is already holding lock:
ff110000239f1bf8 (&extent_inode_mrec_lock_key){+.+.}-{4:4}, at: ntfs_may_write_mft_record fs/ntfs/mft.c:931 [inline]
ff110000239f1bf8 (&extent_inode_mrec_lock_key){+.+.}-{4:4}, at: ntfs_write_mft_block fs/ntfs/mft.c:2788 [inline]
ff110000239f1bf8 (&extent_inode_mrec_lock_key){+.+.}-{4:4}, at: ntfs_mft_writepages+0x1c6d/0x2410 fs/ntfs/mft.c:2955

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #2 (&extent_inode_mrec_lock_key){+.+.}-{4:4}:
       __mutex_lock_common kernel/locking/mutex.c:646 [inline]
       __mutex_lock+0x178/0x1d20 kernel/locking/mutex.c:820
       __ntfs_write_inode+0xc73/0x1530 fs/ntfs/inode.c:2813
       write_inode fs/fs-writeback.c:1584 [inline]
       __writeback_single_inode+0xcbf/0x1380 fs/fs-writeback.c:1827
       writeback_sb_inodes+0x71c/0x1b60 fs/fs-writeback.c:2056
       wb_writeback+0x404/0xbc0 fs/fs-writeback.c:2241
       wb_do_writeback fs/fs-writeback.c:2388 [inline]
       wb_workfn+0x158/0xbc0 fs/fs-writeback.c:2428
       process_one_work+0x9dc/0x1c20 kernel/workqueue.c:3314
       process_scheduled_works kernel/workqueue.c:3397 [inline]
       worker_thread+0x693/0xea0 kernel/workqueue.c:3478
       kthread+0x403/0x530 kernel/kthread.c:436
       ret_from_fork+0xafe/0xda0 arch/x86/kernel/process.c:158
       ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

-> #1 (&ni->extent_lock){+.+.}-{4:4}:
       __mutex_lock_common kernel/locking/mutex.c:646 [inline]
       __mutex_lock+0x178/0x1d20 kernel/locking/mutex.c:820
       __ntfs_write_inode+0xa12/0x1530 fs/ntfs/inode.c:2781
       write_inode fs/fs-writeback.c:1584 [inline]
       __writeback_single_inode+0xcbf/0x1380 fs/fs-writeback.c:1827
       writeback_sb_inodes+0x71c/0x1b60 fs/fs-writeback.c:2056
       wb_writeback+0x404/0xbc0 fs/fs-writeback.c:2241
       wb_do_writeback fs/fs-writeback.c:2388 [inline]
       wb_workfn+0x158/0xbc0 fs/fs-writeback.c:2428
       process_one_work+0x9dc/0x1c20 kernel/workqueue.c:3314
       process_scheduled_works kernel/workqueue.c:3397 [inline]
       worker_thread+0x693/0xea0 kernel/workqueue.c:3478
       kthread+0x403/0x530 kernel/kthread.c:436
       ret_from_fork+0xafe/0xda0 arch/x86/kernel/process.c:158
       ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

-> #0 (&mft_ni_runlist_lock_key){++++}-{4:4}:
       check_prev_add kernel/locking/lockdep.c:3165 [inline]
       check_prevs_add kernel/locking/lockdep.c:3284 [inline]
       validate_chain kernel/locking/lockdep.c:3908 [inline]
       __lock_acquire+0x1616/0x26b0 kernel/locking/lockdep.c:5237
       lock_acquire kernel/locking/lockdep.c:5868 [inline]
       lock_acquire+0x1b0/0x350 kernel/locking/lockdep.c:5825
       down_write+0x91/0x200 kernel/locking/rwsem.c:1625
       ntfs_write_mft_block fs/ntfs/mft.c:2825 [inline]
       ntfs_mft_writepages+0x1113/0x2410 fs/ntfs/mft.c:2955
       do_writepages+0x242/0x5b0 mm/page-writeback.c:2571
       __writeback_single_inode+0x127/0x1380 fs/fs-writeback.c:1764
       writeback_sb_inodes+0x71c/0x1b60 fs/fs-writeback.c:2056
       wb_writeback+0x404/0xbc0 fs/fs-writeback.c:2241
       wb_do_writeback fs/fs-writeback.c:2388 [inline]
       wb_workfn+0x158/0xbc0 fs/fs-writeback.c:2428
       process_one_work+0x9dc/0x1c20 kernel/workqueue.c:3314
       process_scheduled_works kernel/workqueue.c:3397 [inline]
       worker_thread+0x693/0xea0 kernel/workqueue.c:3478
       kthread+0x403/0x530 kernel/kthread.c:436
       ret_from_fork+0xafe/0xda0 arch/x86/kernel/process.c:158
       ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

other info that might help us debug this:

Chain exists of:
  &mft_ni_runlist_lock_key --> &ni->extent_lock --> &extent_inode_mrec_lock_key

 Possible unsafe locking scenario:

       CPU0                    CPU1
       ----                    ----
  lock(&extent_inode_mrec_lock_key);
                               lock(&ni->extent_lock);
                               lock(&extent_inode_mrec_lock_key);
  lock(&mft_ni_runlist_lock_key);

 *** DEADLOCK ***

3 locks held by kworker/u9:5/4025:
 #0: ff11000041ea0940 ((wq_completion)writeback){+.+.}-{0:0}, at: process_one_work+0x136f/0x1c20 kernel/workqueue.c:3289
 #1: ffa00000110dfd08 ((work_completion)(&(&wb->dwork)->work)){+.+.}-{0:0}, at: process_one_work+0x936/0x1c20 kernel/workqueue.c:3290
 #2: ff110000239f1bf8 (&extent_inode_mrec_lock_key){+.+.}-{4:4}, at: ntfs_may_write_mft_record fs/ntfs/mft.c:931 [inline]
 #2: ff110000239f1bf8 (&extent_inode_mrec_lock_key){+.+.}-{4:4}, at: ntfs_write_mft_block fs/ntfs/mft.c:2788 [inline]
 #2: ff110000239f1bf8 (&extent_inode_mrec_lock_key){+.+.}-{4:4}, at: ntfs_mft_writepages+0x1c6d/0x2410 fs/ntfs/mft.c:2955

stack backtrace:
CPU: 0 UID: 0 PID: 4025 Comm: kworker/u9:5 Tainted: G        W           7.1.1 #1 PREEMPT(full)
Tainted: [W]=WARN
Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Workqueue: writeback wb_workfn (flush-7:0)
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:94 [inline]
 dump_stack_lvl+0x116/0x1b0 lib/dump_stack.c:120
 print_circular_bug+0x274/0x340 kernel/locking/lockdep.c:2043
 check_noncircular+0x12d/0x150 kernel/locking/lockdep.c:2175
 check_prev_add kernel/locking/lockdep.c:3165 [inline]
 check_prevs_add kernel/locking/lockdep.c:3284 [inline]
 validate_chain kernel/locking/lockdep.c:3908 [inline]
 __lock_acquire+0x1616/0x26b0 kernel/locking/lockdep.c:5237
 lock_acquire kernel/locking/lockdep.c:5868 [inline]
 lock_acquire+0x1b0/0x350 kernel/locking/lockdep.c:5825
 down_write+0x91/0x200 kernel/locking/rwsem.c:1625
 ntfs_write_mft_block fs/ntfs/mft.c:2825 [inline]
 ntfs_mft_writepages+0x1113/0x2410 fs/ntfs/mft.c:2955
 do_writepages+0x242/0x5b0 mm/page-writeback.c:2571

Submission note:
  This draft is for the public subsystem bug-report route. If you want to treat it as a security issue, do not send it to public lists; send it privately to the affected maintainers and Cc security@xxxxxxxxxx instead.

Artifacts available locally:
  repro.prog
  repro.cprog
  repro.report
  isolated_repro_status.safe.txt

Please let me know if you want the full syz repro, C repro, full dmesg/report, or kernel .config posted inline or sent as attachments.

Thanks,
Guikun Yang

Attachment: repro.prog
Description: Binary data

Attachment: repro.report
Description: Binary data

Attachment: repro.cprog
Description: Binary data