diff options
| author | Szymon Wilczek <swilczek.lx@gmail.com> | 2025-12-27 15:43:07 +0100 |
|---|---|---|
| committer | Konstantin Komarov <almaz.alexandrovich@paragon-software.com> | 2026-01-15 05:57:48 +0100 |
| commit | 08ce2fee1b869ecbfbd94e0eb2630e52203a2e03 (patch) | |
| tree | 9dbb6de88001b1745c7b0615a74bb282d9340335 | |
| parent | 099ef9ab9203dff327f2d61e44773f9acbc01f13 (diff) | |
ntfs3: fix circular locking dependency in run_unpack_ex
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>
| -rw-r--r-- | fs/ntfs3/run.c | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c index 395b20492525..dc59cad4fa37 100644 --- a/fs/ntfs3/run.c +++ b/fs/ntfs3/run.c @@ -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) |
