diff --git a/include/ntfs-3g/index.h b/include/ntfs-3g/index.h index 036b742f..4e3f73f7 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_entry_consistent(const INDEX_ENTRY *ie, + COLLATION_RULES collation_rule, u64 inum); extern int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ictx) __attribute_warn_unused_result__; diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index f3c14d8f..b2afbc34 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -328,9 +328,10 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, if (ie->ie_flags & INDEX_ENTRY_END) break; - if (!le16_to_cpu(ie->length)) { - ntfs_log_error("Zero length index entry in inode %lld" - "\n", (unsigned long long)dir_ni->mft_no); + /* The file name must not overflow from the entry */ + if (ntfs_index_entry_consistent(ie, COLLATION_FILE_NAME, + dir_ni->mft_no)) { + errno = EIO; goto put_err_out; } /* @@ -467,10 +468,10 @@ descend_into_child_node: if (ie->ie_flags & INDEX_ENTRY_END) break; - if (!le16_to_cpu(ie->length)) { + /* The file name must not overflow from the entry */ + if (ntfs_index_entry_consistent(ie, COLLATION_FILE_NAME, + dir_ni->mft_no)) { errno = EIO; - ntfs_log_error("Zero length index entry in inode %lld" - "\n", (unsigned long long)dir_ni->mft_no); goto close_err_out; } /* @@ -1273,6 +1274,13 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, /* Skip index root entry if continuing previous readdir. */ if (ir_pos > (u8*)ie - (u8*)ir) continue; + + /* The file name must not overflow from the entry */ + if (ntfs_index_entry_consistent(ie, COLLATION_FILE_NAME, + dir_ni->mft_no)) { + errno = EIO; + goto dir_err_out; + } /* * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. @@ -1429,6 +1437,13 @@ find_next_index_buffer: /* Skip index entry if continuing previous readdir. */ if (ia_pos - ia_start > (u8*)ie - (u8*)ia) continue; + + /* The file name must not overflow from the entry */ + if (ntfs_index_entry_consistent(ie, COLLATION_FILE_NAME, + dir_ni->mft_no)) { + errno = EIO; + goto dir_err_out; + } /* * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c index e12cbafd..1bd0acd5 100644 --- a/libntfs-3g/index.c +++ b/libntfs-3g/index.c @@ -469,6 +469,57 @@ static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len) return ir; } +/* + * Check the consistency of an index entry + * + * Make sure data and key do not overflow from entry. + * As a side effect, an entry with zero length is rejected. + * This entry must be a full one (no INDEX_ENTRY_END flag), and its + * length must have been checked beforehand to not overflow from the + * index record. + * + * Returns 0 if no error was found + * -1 otherwise (with errno unchanged) + */ + +int ntfs_index_entry_consistent(const INDEX_ENTRY *ie, + COLLATION_RULES collation_rule, u64 inum) +{ + int ret; + + ret = 0; + if (ie->key_length + && ((le16_to_cpu(ie->key_length) + offsetof(INDEX_ENTRY, key)) + > le16_to_cpu(ie->length))) { + ntfs_log_error("Overflow from index entry in inode %lld\n", + (long long)inum); + ret = -1; + + } else + if (collation_rule == COLLATION_FILE_NAME) { + if ((offsetof(INDEX_ENTRY, key.file_name.file_name) + + ie->key.file_name.file_name_length + * sizeof(ntfschar)) + > le16_to_cpu(ie->length)) { + ntfs_log_error("File name overflow from index" + " entry in inode %lld\n", + (long long)inum); + ret = -1; + } + } else { + if (ie->data_length + && ((le16_to_cpu(ie->data_offset) + + le16_to_cpu(ie->data_length)) + > le16_to_cpu(ie->length))) { + ntfs_log_error("Data overflow from index" + " entry in inode %lld\n", + (long long)inum); + ret = -1; + } + } + return (ret); +} + /** * Find a key in the index block. * @@ -521,6 +572,12 @@ static int ntfs_ie_lookup(const void *key, const int key_len, ntfs_log_error("Collation function not defined\n"); errno = EOPNOTSUPP; return STATUS_ERROR; + } + /* Make sure key and data do not overflow from entry */ + if (ntfs_index_entry_consistent(ie, icx->ir->collation_rule, + icx->ni->mft_no)) { + errno = EIO; + return STATUS_ERROR; } rc = icx->collate(icx->ni->vol, key, key_len, &ie->key, le16_to_cpu(ie->key_length)); @@ -704,6 +761,7 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic else icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS; /* get the appropriate collation function */ + icx->ir = ir; icx->collate = ntfs_get_collate_function(ir->collation_rule); if (!icx->collate) { err = errno = EOPNOTSUPP; @@ -790,6 +848,10 @@ descend_into_child_node: err_out: icx->bad_index = TRUE; /* Force icx->* to be freed */ err_lookup: + if (icx->actx) { + ntfs_attr_put_search_ctx(icx->actx); + icx->actx = NULL; + } free(ib); if (!err) err = EIO;