]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ntfs3: fix circular locking dependency in run_unpack_ex
authorSzymon Wilczek <swilczek.lx@gmail.com>
Sat, 27 Dec 2025 14:43:07 +0000 (15:43 +0100)
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Thu, 15 Jan 2026 04:57:48 +0000 (05:57 +0100)
Syzbot reported a circular locking dependency between wnd->rw_lock
(sbi->used.bitmap) and ni->file.run_lock.

The deadlock scenario:
1. ntfs_extend_mft() takes ni->file.run_lock then wnd->rw_lock.
2. run_unpack_ex() takes wnd->rw_lock then tries to acquire
   ni->file.run_lock inside ntfs_refresh_zone().

This creates an AB-BA deadlock.

Fix this by using down_read_trylock() instead of down_read() when
acquiring run_lock in run_unpack_ex(). If the lock is contended,
skip ntfs_refresh_zone() - the MFT zone will be refreshed on the
next MFT operation. This breaks the circular dependency since we
never block waiting for run_lock while holding wnd->rw_lock.

Reported-by: syzbot+d27edf9f96ae85939222@syzkaller.appspotmail.com
Tested-by: syzbot+d27edf9f96ae85939222@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d27edf9f96ae85939222
Signed-off-by: Szymon Wilczek <swilczek.lx@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
fs/ntfs3/run.c

index 395b20492525833ec3105fb6dc4fd98457560d67..dc59cad4fa3764b32423e2d565ffca82ee25ecfd 100644 (file)
@@ -1131,11 +1131,14 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
                        struct rw_semaphore *lock =
                                is_mounted(sbi) ? &sbi->mft.ni->file.run_lock :
                                                  NULL;
-                       if (lock)
-                               down_read(lock);
-                       ntfs_refresh_zone(sbi);
-                       if (lock)
-                               up_read(lock);
+                       if (lock) {
+                               if (down_read_trylock(lock)) {
+                                       ntfs_refresh_zone(sbi);
+                                       up_read(lock);
+                               }
+                       } else {
+                               ntfs_refresh_zone(sbi);
+                       }
                }
                up_write(&wnd->rw_lock);
                if (err)