diff --git a/lib/directory/directory_iterator.c b/lib/directory/directory_iterator.c index e80086f3f..53250fbfd 100644 --- a/lib/directory/directory_iterator.c +++ b/lib/directory/directory_iterator.c @@ -76,7 +76,7 @@ load_metablock( } static int -check_consistency(struct SqshDirectoryIterator *iterator) { +check_consistency(const struct SqshDirectoryIterator *iterator) { const char *name = sqsh_directory_iterator_name(iterator); const size_t name_len = sqsh_directory_iterator_name_size(iterator); @@ -269,13 +269,48 @@ sqsh_directory_iterator_file_type( return SQSH_FILE_TYPE_UNKNOWN; } +static int +check_file_consistency( + const struct SqshDirectoryIterator *iterator, + const struct SqshFile *file) { + const uint64_t file_inode = sqsh_file_inode(file); + const uint64_t iter_inode = sqsh_directory_iterator_inode_number(iterator); + if (iter_inode != file_inode) { + return -SQSH_ERROR_CORRUPTED_DIRECTORY_ENTRY; + } + + enum SqshFileType file_type = sqsh_file_type(file); + enum SqshFileType iter_type = sqsh_directory_iterator_file_type(iterator); + if (iter_type != file_type) { + return -SQSH_ERROR_CORRUPTED_DIRECTORY_ENTRY; + } + return 0; +} + struct SqshFile * sqsh_directory_iterator_open_file( const struct SqshDirectoryIterator *iterator, int *err) { + int rv = 0; + struct SqshFile *file = NULL; const uint64_t inode_ref = sqsh_directory_iterator_inode_ref(iterator); struct SqshArchive *archive = iterator->file->archive; - return sqsh_open_by_ref(archive, inode_ref, err); + file = sqsh_open_by_ref(archive, inode_ref, &rv); + if (file == NULL) { + goto out; + } + + rv = check_file_consistency(iterator, file); + +out: + if (rv < 0) { + sqsh_close(file); + file = NULL; + } + if (err != NULL) { + *err = rv; + } + return file; } static int diff --git a/test/directory/directory_iterator.c b/test/directory/directory_iterator.c index 237e0bbe5..c9a7996b4 100644 --- a/test/directory/directory_iterator.c +++ b/test/directory/directory_iterator.c @@ -207,9 +207,55 @@ iter_invalid_file_type(void) { sqsh__archive_cleanup(&archive); } +static void +iter_inconsistent_file_type(void) { + int rv; + struct SqshArchive archive = {0}; + uint8_t payload[] = { + /* clang-format off */ + SQSH_HEADER, + /* inode */ + [INODE_TABLE_OFFSET] = METABLOCK_HEADER(0, 1024), + INODE_HEADER(1, 0, 0, 0, 0, 1), + INODE_BASIC_DIR(0, 1024, 0, 0), + [INODE_TABLE_OFFSET+2+128] = + INODE_HEADER(3, 0, 0, 0, 0, 2), + INODE_BASIC_SYMLINK(3), + 't', 'g', 't', + [DIRECTORY_TABLE_OFFSET] = METABLOCK_HEADER(0, 128), + DIRECTORY_HEADER(2, 0, 0), + DIRECTORY_ENTRY(128, 2, 1, 1), + '1', + [FRAGMENT_TABLE_OFFSET] = 0, + /* clang-format on */ + }; + mk_stub(&archive, payload, sizeof(payload)); + + struct SqshFile file = {0}; + rv = sqsh__file_init(&file, &archive, 0); + assert(rv == 0); + + struct SqshDirectoryIterator *iter = + sqsh_directory_iterator_new(&file, &rv); + assert(rv == 0); + + bool has_next = sqsh_directory_iterator_next(iter, &rv); + assert(rv == 0); + assert(has_next == true); + + struct SqshFile *entry_file = sqsh_directory_iterator_open_file(iter, &rv); + assert(rv == -SQSH_ERROR_CORRUPTED_DIRECTORY_ENTRY); + assert(entry_file == NULL); + + sqsh_directory_iterator_free(iter); + sqsh__file_cleanup(&file); + sqsh__archive_cleanup(&archive); +} + DECLARE_TESTS TEST(iter_two_files) TEST(iter_invalid_file_name_with_slash) TEST(iter_invalid_file_name_with_0) TEST(iter_invalid_file_type) +TEST(iter_inconsistent_file_type) END_TESTS