diff options
| author | Matthias Goergens <matthias.goergens@gmail.com> | 2026-09-30 11:48:35 +0800 |
|---|---|---|
| committer | Namjae Jeon <linkinjeon@kernel.org> | 2026-10-20 18:41:51 +0900 |
| commit | 8e91379152204a9cc18fa7e16724646ad3aec759 (patch) | |
| tree | b5047d1e895d17bd689e3624e0a24e3955f5f32d /scripts/Makefile.thinlto | |
| parent | 82a5e003ef09113c10b791d687297ef455bb1552 (diff) | |
| download | linux-8e91379152204a9cc18fa7e16724646ad3aec759.tar.gz linux-8e91379152204a9cc18fa7e16724646ad3aec759.zip | |
ntfs: reject non-resident attributes whose sizes exceed their allocation
ntfs_read_locked_inode(), ntfs_read_locked_attr_inode() and
ntfs_read_locked_index_inode() take a non-resident attribute's data_size
and initialized_size from disk without checking them against its
allocated_size. The runlist ends at allocated_size and the read path
maps what lies beyond it as a hole, so a data_size larger than the
allocation makes reads return zeros that are not on disk, with no error.
On a crafted volume with 4 KiB clusters where a 6144000-byte file claims
a data_size and initialized_size 64 KiB beyond its allocation, reading
the file returns 16 clusters of such zeros. A sparse file behaves the
same. A compressed file instead fails with -EIO after a burst of "Still
have pages left!" errors from ntfs_read_compressed_block().
Require 0 <= initialized_size <= data_size <= allocated_size, with
allocated_size a multiple of the cluster size, when the inode is read,
as fs/ntfs3 does in mi_enum_attr(), and fail with -EIO otherwise, which
marks the inode bad and the volume as having errors. initialized_size
above data_size is rejected too because an extending write zeroes the
gap it opens only from initialized_size onwards. An unaligned
allocated_size ends inside a cluster that the read path treats as past
the end: a crafted 66440-byte file with 4 KiB clusters reads its last
904 bytes as zeros.
Sparse and compressed attributes need no exception. Every non-resident
attribute has a cluster-aligned allocated_size >= data_size, holes
included, on eight public test volumes (seven written by Windows, with
LZNT1-compressed files, a sparse $UsnJrnl:$J and a OneDrive placeholder
whose unnamed $DATA is one hole, and one by mkntfs), on a volume written
by ntfs-3g and on one written by this driver, and the patched driver
reads every file on them as before. fs/ntfs3 has enforced the same
checks since v6.6, also without exceptions. The layout.h comment saying
that data_size can exceed allocated_size for compressed and sparse
attributes is corrected.
This also covers a non-resident attribute list, which
load_attribute_list() reads through ntfs_attr_iget(), and $MFT, whose
inode goes through ntfs_read_locked_inode() after the previous patch's
check. $MFT's own non-resident attribute list goes through neither:
ntfs_read_inode_mount() loads it with load_attribute_list_mount() and
ntfs_read_locked_inode() skips it for $MFT, so the check is added there
too. The check was already missing in the classic driver; the Fixes
tag names the commit that brought that code back.
Fixes: 1e9ea7e04472 ("Revert "fs: Remove NTFS classic"")
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Diffstat (limited to 'scripts/Makefile.thinlto')
0 files changed, 0 insertions, 0 deletions
