[PATCH v2 5/6] ntfs: fail the mount when $MFT's data size exceeds its allocation
From: Matthias Goergens
Date: Sun Sep 27 2026 - 01:10:05 EST
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@xxxxxxxxxxxxxxx
Signed-off-by: Matthias Goergens <matthias.goergens@xxxxxxxxx>
---
fs/ntfs/inode.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index a61f1519549cb..9c97fc3f9e5ff 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.55.0