Checked consistency of index entries

Make sure the data and key in indexes do not overflow from index entries
edge.strict_endians^2
Jean-Pierre André 2021-07-12 08:31:18 +02:00
parent 32e858a87a
commit 436fe09f87
3 changed files with 85 additions and 6 deletions

View File

@ -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__;

View File

@ -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.

View File

@ -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;