[PATCH] fs/ntfs3: validate INDEX_ROOT size before reading its fields
From: Shirong Zhao
Date: Tue Oct 27 2026 - 22:45:17 EST
check_index_root() reads root->index_block_size and
root->index_block_clst before checking that the resident data is
large enough. check_attr() accepts a resident attribute with
data_size == 0 and data_off == asize, and mi->mrec is exactly
record_size bytes, so a crafted $LogFile record can make the
first read go past the end of the allocation.
Use resident_data_ex() so the attribute is validated before the
fields are read.
Signed-off-by: Shirong Zhao <shxzhaosr@xxxxxxx>
---
fs/ntfs3/fslog.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c
index 2460a4a..e208f4c 100644
--- a/fs/ntfs3/fslog.c
+++ b/fs/ntfs3/fslog.c
@@ -2721,15 +2721,21 @@ static inline bool check_index_root(const struct ATTRIB *attr,
struct ntfs_sb_info *sbi)
{
bool ret;
- const struct INDEX_ROOT *root = resident_data(attr);
- u8 index_bits = le32_to_cpu(root->index_block_size) >=
+ const struct INDEX_ROOT *root;
+ u8 index_bits;
+ u8 block_clst;
+
+ root = resident_data_ex(attr, sizeof(struct INDEX_ROOT));
+ if (!root)
+ return false;
+
+ index_bits = le32_to_cpu(root->index_block_size) >=
sbi->cluster_size ?
sbi->cluster_bits :
SECTOR_SHIFT;
- u8 block_clst = root->index_block_clst;
+ block_clst = root->index_block_clst;
- if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) ||
- (root->type != ATTR_NAME && root->type != ATTR_ZERO) ||
+ if ((root->type != ATTR_NAME && root->type != ATTR_ZERO) ||
(root->type == ATTR_NAME &&
root->rule != NTFS_COLLATION_TYPE_FILENAME) ||
(le32_to_cpu(root->index_block_size) !=
--
2.53.0