From 20e14268ef410cbabff54a79405813a8b9ce8e89 Mon Sep 17 00:00:00 2001 From: Hang Nan <2122295973@qq.com> Date: Tue, 20 Oct 2026 16:53:53 +0800 Subject: [PATCH] ntfs: reject index blocks with a too small entries offset Index blocks read from the volume are checked for a plausible header, but nothing keeps a block from placing its entries closer to the header than ntfs_ib_alloc() does when it creates one. The allocation adds the update sequence array, one entry per 512-byte sector plus the terminator, to the index header and aligns the result to 8 bytes, so the first entry of a 4096-byte block starts at offset 40, while a corrupt block may declare 16. ntfs_ib_copy_tail() then copies the entries that follow the median entry from the source block into a freshly allocated destination. The tail is sized as index_length minus entries_offset and the median entry, both from the source, while the destination only has allocated_size minus the canonical offset of room. With the values above the tail is 4040 bytes and the destination holds 4032, so the last 8 bytes are written past the end of the new allocation, with contents taken from the mounted image. Reject such a block when it is read: entries_offset must not be smaller than the canonical offset for the block size. Derive it from block_size rather than from the block's own usa_count, which post_read_mst_fixup() treats as "not protected" when it does not match the block size, and use the same helper in ntfs_ib_alloc() so both stay in sync. Fixes: 0a8ac0c1fa0b ("ntfs: update directory operations") Signed-off-by: Hang Nan <2122295973@qq.com> Reviewed-by: Baolin Liu Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/index.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index ac22d8407a77..66411a712b14 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -489,6 +489,14 @@ static struct index_entry *ntfs_ie_dup_novcn(struct index_entry *ie) return dup; } +/* Offset of the first entry in an index block created by ntfs_ib_alloc(). */ +static u32 ntfs_ib_canonical_entries_offset(u32 block_size) +{ + u32 usa_count = block_size / NTFS_BLOCK_SIZE + 1; + + return (sizeof(struct index_header) + usa_count * 2 + 7) & ~7; +} + /* * Check the consistency of an index block * @@ -548,6 +556,16 @@ int ntfs_index_block_inconsistent(struct ntfs_volume *vol, offsetof(struct index_block, index), inum)) return -EIO; + + if (le32_to_cpu(ib->index.entries_offset) < + ntfs_ib_canonical_entries_offset(block_size)) { + ntfs_error(sb, + "Index block: entries offset %u is below the minimum for a %u-byte block: vcn %lld inode %llu\n", + le32_to_cpu(ib->index.entries_offset), block_size, + vcn, inum); + return -EIO; + } + if (ntfs_index_entries_inconsistent(vol, &ib->index, cr, inum)) return -EIO; return 0; @@ -960,8 +978,8 @@ static struct index_block *ntfs_ib_alloc(s64 ib_vcn, u32 ib_size, *(__le16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); ib->lsn = 0; ib->index_block_vcn = cpu_to_le64(ib_vcn); - ib->index.entries_offset = cpu_to_le32((ih_size + - le16_to_cpu(ib->usa_count) * 2 + 7) & ~7); + ib->index.entries_offset = + cpu_to_le32(ntfs_ib_canonical_entries_offset(ib_size)); ib->index.index_length = 0; ib->index.allocated_size = cpu_to_le32(ib_size - (sizeof(struct index_block) - ih_size));