fs/ntfs3: Fix case when unmarked clusters intersect with zone
[ Upstream commit 5fc982fe7e ]
Reported-by: syzbot+7f3761b790fa41d0f3d5@syzkaller.appspotmail.com
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
c5f89458a2
commit
57f7979aef
+30
-10
@@ -1053,8 +1053,8 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
{
|
||||
int ret, err;
|
||||
CLST next_vcn, lcn, len;
|
||||
size_t index;
|
||||
bool ok;
|
||||
size_t index, done;
|
||||
bool ok, zone;
|
||||
struct wnd_bitmap *wnd;
|
||||
|
||||
ret = run_unpack(run, sbi, ino, svcn, evcn, vcn, run_buf, run_buf_size);
|
||||
@@ -1085,8 +1085,9 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
continue;
|
||||
|
||||
down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
|
||||
zone = max(wnd->zone_bit, lcn) < min(wnd->zone_end, lcn + len);
|
||||
/* Check for free blocks. */
|
||||
ok = wnd_is_used(wnd, lcn, len);
|
||||
ok = !zone && wnd_is_used(wnd, lcn, len);
|
||||
up_read(&wnd->rw_lock);
|
||||
if (ok)
|
||||
continue;
|
||||
@@ -1094,14 +1095,33 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
/* Looks like volume is corrupted. */
|
||||
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
|
||||
|
||||
if (down_write_trylock(&wnd->rw_lock)) {
|
||||
/* Mark all zero bits as used in range [lcn, lcn+len). */
|
||||
size_t done;
|
||||
err = wnd_set_used_safe(wnd, lcn, len, &done);
|
||||
up_write(&wnd->rw_lock);
|
||||
if (err)
|
||||
return err;
|
||||
if (!down_write_trylock(&wnd->rw_lock))
|
||||
continue;
|
||||
|
||||
if (zone) {
|
||||
/*
|
||||
* Range [lcn, lcn + len) intersects with zone.
|
||||
* To avoid complex with zone just turn it off.
|
||||
*/
|
||||
wnd_zone_set(wnd, 0, 0);
|
||||
}
|
||||
|
||||
/* Mark all zero bits as used in range [lcn, lcn+len). */
|
||||
err = wnd_set_used_safe(wnd, lcn, len, &done);
|
||||
if (zone) {
|
||||
/* Restore zone. Lock mft run. */
|
||||
struct rw_semaphore *lock;
|
||||
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);
|
||||
}
|
||||
up_write(&wnd->rw_lock);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user