Skip to content

Commit a82fbf4

Browse files
fs/ntfs3: reject SEEK_DATA and SEEK_HOLE past EOF early
Handle non-data/hole seeks through generic_file_llseek_size() and return -ENXIO immediately when SEEK_DATA or SEEK_HOLE is requested at or past EOF. Handle compressed files in such cases properly as well. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
1 parent ecbb433 commit a82fbf4

2 files changed

Lines changed: 21 additions & 10 deletions

File tree

fs/ntfs3/file.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
10081008
CLST lcn, clen;
10091009

10101010
frame = valid >> frame_bits;
1011-
frame_vbo = valid & ~(frame_size - 1);
1011+
frame_vbo = valid & ~(u64)(frame_size - 1);
10121012
off = valid & (frame_size - 1);
10131013

10141014
err = attr_data_get_block(ni, frame << NTFS_LZNT_CUNIT, 1, &lcn,
@@ -1077,7 +1077,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
10771077
if (bytes > count)
10781078
bytes = count;
10791079

1080-
frame_vbo = pos & ~(frame_size - 1);
1080+
frame_vbo = pos & ~(u64)(frame_size - 1);
10811081
index = frame_vbo >> PAGE_SHIFT;
10821082

10831083
if (unlikely(fault_in_iov_iter_readable(from, bytes))) {
@@ -1530,17 +1530,19 @@ static loff_t ntfs_llseek(struct file *file, loff_t offset, int whence)
15301530
loff_t maxbytes = ntfs_get_maxbytes(ni);
15311531
loff_t ret;
15321532

1533-
if (whence == SEEK_DATA || whence == SEEK_HOLE) {
1533+
if (whence != SEEK_DATA && whence != SEEK_HOLE) {
1534+
ret = generic_file_llseek_size(file, offset, whence, maxbytes,
1535+
i_size_read(inode));
1536+
} else if ((unsigned long long)offset >= i_size_read(inode)) {
1537+
ret = -ENXIO;
1538+
} else {
15341539
inode_lock_shared(inode);
15351540
/* Scan file for hole or data. */
15361541
ret = ni_seek_data_or_hole(ni, offset, whence == SEEK_DATA);
15371542
inode_unlock_shared(inode);
15381543

15391544
if (ret >= 0)
15401545
ret = vfs_setpos(file, ret, maxbytes);
1541-
} else {
1542-
ret = generic_file_llseek_size(file, offset, whence, maxbytes,
1543-
i_size_read(inode));
15441546
}
15451547
return ret;
15461548
}

fs/ntfs3/frecord.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,8 +2889,14 @@ loff_t ni_seek_data_or_hole(struct ntfs_inode *ni, loff_t offset, bool data)
28892889
* the file offset is set to offset.
28902890
*/
28912891
if (lcn != SPARSE_LCN) {
2892-
vbo = (u64)vcn << cluster_bits;
2893-
return max(vbo, offset);
2892+
/* Normal cluster. */
2893+
break;
2894+
}
2895+
2896+
if ((ni->std_fa & FILE_ATTRIBUTE_COMPRESSED) &&
2897+
(vcn & (NTFS_LZNT_CLUSTERS - 1))) {
2898+
/* Compressed cluster in compressed frame. */
2899+
break;
28942900
}
28952901
} else {
28962902
/*
@@ -2904,8 +2910,8 @@ loff_t ni_seek_data_or_hole(struct ntfs_inode *ni, loff_t offset, bool data)
29042910
/* native compression hole begins at aligned vcn. */
29052911
(!(ni->std_fa & FILE_ATTRIBUTE_COMPRESSED) ||
29062912
!(vcn & (NTFS_LZNT_CLUSTERS - 1)))) {
2907-
vbo = (u64)vcn << cluster_bits;
2908-
return max(vbo, offset);
2913+
/* Hole in sparsed or compressed file frame. */
2914+
break;
29092915
}
29102916
}
29112917

@@ -2914,6 +2920,9 @@ loff_t ni_seek_data_or_hole(struct ntfs_inode *ni, loff_t offset, bool data)
29142920
return -EINVAL;
29152921
}
29162922
}
2923+
2924+
vbo = (u64)vcn << cluster_bits;
2925+
return max(vbo, offset);
29172926
}
29182927

29192928
/*

0 commit comments

Comments
 (0)