7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Matthias Goergens [ Upstream commit 82a5e003ef09113c10b791d687297ef455bb1552 ] ntfs_read_inode_mount() takes $MFT's i_size from data_size without checking it against allocated_size, unlike the resident case in ntfs_read_locked_inode(). mft records between the two are not on disk. On a crafted volume with 512-byte clusters whose $MFT is cut to 4 clusters while data_size still says 27 records, reading the folio holding records 0-3 finds the end of the runlist at vcn 4. An unpatched kernel hangs there on the folio lock, as in "ntfs: fail the mount when $MFT needs its own extent records". With the previous patch vcn 4-7 are past the allocation and so read as a hole: records 2 and 3 come back as zeros and the mount carries on until check_mft_mirror() finds the zeroed record 2. Refuse such a $MFT before anything is read through it. The mount now fails with: ntfs: (device vda): ntfs_read_inode_mount(): $MFT data size 27648 exceeds its allocated size 2048. $MFT is corrupt. Run chkdsk. fs/ntfs3 rejects any non-resident attribute whose data_size exceeds its allocated size. This patch checks only $MFT; the next one covers the other non-resident attributes. Fixes: b041ca562526 ("ntfs: update iomap and address space operations") Cc: stable@vger.kernel.org Signed-off-by: Matthias Goergens Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon Signed-off-by: Sasha Levin --- fs/ntfs/inode.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index ca7e2299a8a48..213c4a12b33aa 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -2136,6 +2136,16 @@ int ntfs_read_inode_mount(struct inode *vi) vi->i_size = le64_to_cpu(a->data.non_resident.data_size); ni->initialized_size = le64_to_cpu(a->data.non_resident.initialized_size); ni->allocated_size = le64_to_cpu(a->data.non_resident.allocated_size); + /* + * Records between allocated_size and data_size are not + * on disk, and would be read as zeros. + */ + if (vi->i_size > ni->allocated_size) { + ntfs_error(sb, + "$MFT data size %lld exceeds its allocated size %lld. $MFT is corrupt. Run chkdsk.", + vi->i_size, ni->allocated_size); + goto put_err_out; + } /* * Verify the number of mft records does not exceed * 2^32 - 1. -- 2.53.0