diff --git a/src/dwarfs/metadata_types.cpp b/src/dwarfs/metadata_types.cpp index ef5b9bae..da2300bd 100644 --- a/src/dwarfs/metadata_types.cpp +++ b/src/dwarfs/metadata_types.cpp @@ -136,6 +136,26 @@ void check_index_range(global_metadata::Meta const* meta) { auto num_inodes = meta->inodes().size(); bool v2_2 = !static_cast(meta->dir_entries()); + if (num_modes >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of modes"); + } + + if (num_uids >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of uids"); + } + + if (num_gids >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of gids"); + } + + if (num_names >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of names"); + } + + if (num_inodes >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of inodes"); + } + for (auto ino : meta->inodes()) { if (ino.mode_index() >= num_modes) { DWARFS_THROW(runtime_error, "mode_index out of range"); @@ -154,6 +174,10 @@ void check_index_range(global_metadata::Meta const* meta) { } if (auto dep = meta->dir_entries()) { + if (dep->size() >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of dir_entries"); + } + if (auto cn = meta->compact_names()) { num_names = cn->index().size(); if (!cn->packed_index()) { @@ -173,6 +197,11 @@ void check_index_range(global_metadata::Meta const* meta) { } } } else { + if (meta->entry_table_v2_2().size() >= + std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of entries"); + } + for (auto ent : meta->entry_table_v2_2()) { if (ent >= num_inodes) { DWARFS_THROW(runtime_error, "entry_table_v2_2 value out of range"); @@ -182,6 +211,14 @@ void check_index_range(global_metadata::Meta const* meta) { } void check_packed_tables(global_metadata::Meta const* meta) { + if (meta->directories().size() >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of directories"); + } + + if (meta->chunk_table().size() >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of chunk_table entries"); + } + if (auto opt = meta->options(); opt and opt->packed_directories()) { if (std::any_of(meta->directories().begin(), meta->directories().end(), [](auto i) { return i.parent_entry() != 0; })) { @@ -229,6 +266,10 @@ void check_chunks(global_metadata::Meta const* meta) { DWARFS_THROW(runtime_error, "invalid block size"); } + if (meta->chunks().size() >= std::numeric_limits::max()) { + DWARFS_THROW(runtime_error, "invalid number of chunks"); + } + for (auto c : meta->chunks()) { if (c.offset() >= block_size || c.size() > block_size) { DWARFS_THROW(runtime_error, "chunk offset/size out of range"); diff --git a/src/dwarfs/metadata_v2.cpp b/src/dwarfs/metadata_v2.cpp index f44d763f..c1807c9d 100644 --- a/src/dwarfs/metadata_v2.cpp +++ b/src/dwarfs/metadata_v2.cpp @@ -57,6 +57,8 @@ #include "dwarfs/gen-cpp2/metadata_layouts.h" #include "dwarfs/gen-cpp2/metadata_types_custom_protocol.h" +#include "thrift/lib/thrift/gen-cpp2/frozen_types_custom_protocol.h" + namespace dwarfs { namespace { @@ -89,9 +91,41 @@ freeze_to_buffer(const T& x) { return {schema_buffer, data_buffer}; } +void check_schema(folly::ByteRange data) { + using namespace ::apache::thrift; + frozen::schema::Schema schema; + size_t schemaSize = CompactSerializer::deserialize(data, schema); + // std::cerr << debugString(schema) << '\n'; + if (schemaSize != data.size()) { + DWARFS_THROW(runtime_error, "invalid schema size"); + } + if (schema.layouts_ref()->count(*schema.rootLayout_ref()) == 0) { + DWARFS_THROW(runtime_error, "invalid rootLayout in schema"); + } + for (auto const& kvl : *schema.layouts_ref()) { + auto const& layout = kvl.second; + if (kvl.first >= static_cast(schema.layouts_ref()->size())) { + DWARFS_THROW(runtime_error, "invalid layout key in schema"); + } + if (*layout.size_ref() < 0) { + DWARFS_THROW(runtime_error, "negative size in schema"); + } + if (*layout.bits_ref() < 0) { + DWARFS_THROW(runtime_error, "negative bits in schema"); + } + for (auto const& kvf : *layout.fields_ref()) { + auto const& field = kvf.second; + if (schema.layouts_ref()->count(*field.layoutId_ref()) == 0) { + DWARFS_THROW(runtime_error, "invalid layoutId in field"); + } + } + } +} + template MappedFrozen map_frozen(folly::ByteRange schema, folly::ByteRange data) { using namespace ::apache::thrift::frozen; + check_schema(schema); auto layout = std::make_unique>(); deserializeRootLayout(schema, *layout); MappedFrozen ret(layout->view({data.begin(), 0}));