From 2bf50778043dfebd8c1cb45859446069d99c6d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Mon, 19 Jul 2021 09:23:23 +0200 Subject: [PATCH] Checked consistency of index blocks Improved existing consistency checks of index blocks and grouped them into a specific function. --- include/ntfs-3g/index.h | 2 + libntfs-3g/dir.c | 52 ++--------------- libntfs-3g/index.c | 125 +++++++++++++++++++++++++--------------- 3 files changed, 87 insertions(+), 92 deletions(-) diff --git a/include/ntfs-3g/index.h b/include/ntfs-3g/index.h index 4e3f73f7..22dcbb80 100644 --- a/include/ntfs-3g/index.h +++ b/include/ntfs-3g/index.h @@ -139,6 +139,8 @@ extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, extern void ntfs_index_ctx_put(ntfs_index_context *ictx); extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx); +extern int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size, + u64 inum, VCN vcn); extern int ntfs_index_entry_consistent(const INDEX_ENTRY *ie, COLLATION_RULES collation_rule, u64 inum); extern int ntfs_index_lookup(const void *key, const int key_len, diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index d4c8204e..142c6826 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -407,33 +407,12 @@ descend_into_child_node: goto close_err_out; } - if (sle64_to_cpu(ia->index_block_vcn) != vcn) { - ntfs_log_error("Actual VCN (0x%llx) of index buffer is different " - "from expected VCN (0x%llx).\n", - (long long)sle64_to_cpu(ia->index_block_vcn), - (long long)vcn); - errno = EIO; - goto close_err_out; - } - if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { - ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode 0x%llx " - "has a size (%u) differing from the directory " - "specified size (%u).\n", (long long)vcn, - (unsigned long long)dir_ni->mft_no, - (unsigned) le32_to_cpu(ia->index.allocated_size) + 0x18, - (unsigned)index_block_size); + if (ntfs_index_block_inconsistent((INDEX_BLOCK*)ia, index_block_size, + ia_na->ni->mft_no, vcn)) { errno = EIO; goto close_err_out; } index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); - if (((s32)le32_to_cpu(ia->index.index_length) < 0) - || (index_end > (u8*)ia + index_block_size)) { - ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode " - "0x%llx exceeds maximum size.\n", - (long long)vcn, (unsigned long long)dir_ni->mft_no); - errno = EIO; - goto close_err_out; - } /* The first index entry. */ ie = (INDEX_ENTRY*)((u8*)&ia->index + @@ -1372,33 +1351,12 @@ find_next_index_buffer: } ia_start = ia_pos & ~(s64)(index_block_size - 1); - if (sle64_to_cpu(ia->index_block_vcn) != ia_start >> - index_vcn_size_bits) { - ntfs_log_error("Actual VCN (0x%llx) of index buffer is different " - "from expected VCN (0x%llx) in inode 0x%llx.\n", - (long long)sle64_to_cpu(ia->index_block_vcn), - (long long)ia_start >> index_vcn_size_bits, - (unsigned long long)dir_ni->mft_no); - goto dir_err_out; - } - if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { - ntfs_log_error("Index buffer (VCN 0x%llx) of directory inode %lld " - "has a size (%u) differing from the directory " - "specified size (%u).\n", (long long)ia_start >> - index_vcn_size_bits, - (unsigned long long)dir_ni->mft_no, - (unsigned) le32_to_cpu(ia->index.allocated_size) - + 0x18, (unsigned)index_block_size); + if (ntfs_index_block_inconsistent((INDEX_BLOCK*)ia, index_block_size, + ia_na->ni->mft_no, ia_start >> index_vcn_size_bits)) { goto dir_err_out; } index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); - if (index_end > (u8*)ia + index_block_size) { - ntfs_log_error("Size of index buffer (VCN 0x%llx) of directory inode " - "%lld exceeds maximum size.\n", - (long long)ia_start >> index_vcn_size_bits, - (unsigned long long)dir_ni->mft_no); - goto dir_err_out; - } + /* The first index entry. */ ie = (INDEX_ENTRY*)((u8*)&ia->index + le32_to_cpu(ia->index.entries_offset)); diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c index c8c03481..943450e2 100644 --- a/libntfs-3g/index.c +++ b/libntfs-3g/index.c @@ -388,50 +388,6 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) return dup; } -static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) -{ - u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18; - - ntfs_log_trace("Entering\n"); - - if (!ntfs_is_indx_record(ib->magic)) { - - ntfs_log_error("Corrupt index block signature: vcn %lld inode " - "%llu\n", (long long)vcn, - (unsigned long long)icx->ni->mft_no); - return -1; - } - - if (sle64_to_cpu(ib->index_block_vcn) != vcn) { - - ntfs_log_error("Corrupt index block: VCN (%lld) is different " - "from expected VCN (%lld) in inode %llu\n", - (long long)sle64_to_cpu(ib->index_block_vcn), - (long long)vcn, - (unsigned long long)icx->ni->mft_no); - return -1; - } - - if (ib_size != icx->block_size) { - - ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " - "has a size (%u) differing from the index " - "specified size (%u)\n", (long long)vcn, - (unsigned long long)icx->ni->mft_no, ib_size, - icx->block_size); - return -1; - } - if (((s32)le32_to_cpu(ib->index.index_length) < 0) - || ((u8*)&ib->index + le32_to_cpu(ib->index.index_length) > - (u8*)ib + icx->block_size)) { - ntfs_log_error("Size of index buffer (%lld) of inode %llu " - "exceeds maximum size.\n", (long long)vcn, - (unsigned long long)icx->ni->mft_no); - return -1; - } - return 0; -} - static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name, u32 name_len, ntfs_attr_search_ctx **ctx) { @@ -477,6 +433,82 @@ static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len) return ir; } +/* + * Check the consistency of an index block + * + * Make sure the index block does not overflow from the index record. + * The size of block is assumed to have been checked to be what is + * defined in the index root. + * + * Returns 0 if no error was found + * -1 otherwise (with errno unchanged) + * + * |<--->| offsetof(INDEX_BLOCK, index) + * | |<--->| sizeof(INDEX_HEADER) + * | | | + * | | | seq index entries unused + * |=====|=====|=====|===========================|==============| + * | | | | | + * | |<--------->| entries_offset | | + * | |<---------------- index_length ------->| | + * | |<--------------------- allocated_size --------------->| + * |<--------------------------- block_size ------------------->| + * + * size(INDEX_HEADER) <= ent_offset < ind_length <= alloc_size < bk_size + */ + +int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size, + u64 inum, VCN vcn) +{ + u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + + offsetof(INDEX_BLOCK, index); + + if (!ntfs_is_indx_record(ib->magic)) { + ntfs_log_error("Corrupt index block signature: vcn %lld inode " + "%llu\n", (long long)vcn, + (unsigned long long)inum); + return -1; + } + + if (sle64_to_cpu(ib->index_block_vcn) != vcn) { + ntfs_log_error("Corrupt index block: VCN (%lld) is different " + "from expected VCN (%lld) in inode %llu\n", + (long long)sle64_to_cpu(ib->index_block_vcn), + (long long)vcn, + (unsigned long long)inum); + return -1; + } + + if (ib_size != block_size) { + ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " + "has a size (%u) differing from the index " + "specified size (%u)\n", (long long)vcn, + (unsigned long long)inum, ib_size, + (unsigned int)block_size); + return -1; + } + if (le32_to_cpu(ib->index.entries_offset) < sizeof(INDEX_HEADER)) { + ntfs_log_error("Invalid index entry offset in inode %lld\n", + (unsigned long long)inum); + return -1; + } + if (le32_to_cpu(ib->index.index_length) + <= le32_to_cpu(ib->index.entries_offset)) { + ntfs_log_error("No space for index entries in inode %lld\n", + (unsigned long long)inum); + return -1; + } + if (le32_to_cpu(ib->index.allocated_size) + < le32_to_cpu(ib->index.index_length)) { + ntfs_log_error("Index entries overflow in inode %lld\n", + (unsigned long long)inum); + return -1; + } + + return (0); +} + + /* * Check the consistency of an index entry * @@ -671,8 +703,11 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) return -1; } - if (ntfs_ia_check(icx, dst, vcn)) + if (ntfs_index_block_inconsistent((INDEX_BLOCK*)dst, icx->block_size, + icx->ia_na->ni->mft_no, vcn)) { + errno = EIO; return -1; + } return 0; }