mirror of
https://github.com/mhx/dwarfs.git
synced 2025-09-17 08:18:07 -04:00
Even more metadata checks
This commit is contained in:
parent
9112f1f7ac
commit
dca93db1da
@ -114,6 +114,10 @@ struct section_header_v2 {
|
||||
void dump(std::ostream& os) const;
|
||||
};
|
||||
|
||||
bool is_valid_compression_type(compression_type type);
|
||||
|
||||
bool is_valid_section_type(section_type type);
|
||||
|
||||
std::string get_compression_name(compression_type type);
|
||||
|
||||
std::string get_section_name(section_type type);
|
||||
|
@ -30,6 +30,48 @@
|
||||
|
||||
namespace dwarfs {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void read_section_header_common(T& header, size_t& start, mmif& mm,
|
||||
size_t offset) {
|
||||
if (offset + sizeof(T) > mm.size()) {
|
||||
DWARFS_THROW(runtime_error, "truncated section header");
|
||||
}
|
||||
|
||||
::memcpy(&header, mm.as<void>(offset), sizeof(T));
|
||||
|
||||
offset += sizeof(T);
|
||||
|
||||
auto end = offset + header.length;
|
||||
|
||||
if (end < offset) {
|
||||
DWARFS_THROW(runtime_error, "offset/length overflow");
|
||||
}
|
||||
|
||||
if (end > mm.size()) {
|
||||
DWARFS_THROW(runtime_error, "truncated section data");
|
||||
}
|
||||
|
||||
start = offset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void check_section(T const& sec) {
|
||||
if (!is_valid_section_type(sec.type())) {
|
||||
DWARFS_THROW(runtime_error, fmt::format("invalid section type ({0})",
|
||||
static_cast<int>(sec.type())));
|
||||
}
|
||||
|
||||
if (!is_valid_compression_type(sec.compression())) {
|
||||
DWARFS_THROW(runtime_error,
|
||||
fmt::format("invalid compression type ({0})",
|
||||
static_cast<int>(sec.compression())));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class fs_section_v1 : public fs_section::impl {
|
||||
public:
|
||||
fs_section_v1(mmif& mm, size_t offset);
|
||||
@ -118,36 +160,14 @@ fs_section::fs_section(mmif& mm, size_t offset, int version) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void read_section_header_common(T& header, size_t& start, mmif& mm,
|
||||
size_t offset) {
|
||||
if (offset + sizeof(T) > mm.size()) {
|
||||
DWARFS_THROW(runtime_error, "truncated section header");
|
||||
}
|
||||
|
||||
::memcpy(&header, mm.as<void>(offset), sizeof(T));
|
||||
|
||||
offset += sizeof(T);
|
||||
|
||||
auto end = offset + header.length;
|
||||
|
||||
if (end < offset) {
|
||||
DWARFS_THROW(runtime_error, "offset/length overflow");
|
||||
}
|
||||
|
||||
if (end > mm.size()) {
|
||||
DWARFS_THROW(runtime_error, "truncated section data");
|
||||
}
|
||||
|
||||
start = offset;
|
||||
}
|
||||
|
||||
fs_section_v1::fs_section_v1(mmif& mm, size_t offset) {
|
||||
read_section_header_common(hdr_, start_, mm, offset);
|
||||
check_section(*this);
|
||||
}
|
||||
|
||||
fs_section_v2::fs_section_v2(mmif& mm, size_t offset) {
|
||||
read_section_header_common(hdr_, start_, mm, offset);
|
||||
check_section(*this);
|
||||
}
|
||||
|
||||
} // namespace dwarfs
|
||||
|
@ -59,6 +59,14 @@ std::string get_default(const HT& ht, const typename HT::key_type& key) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool is_valid_compression_type(compression_type type) {
|
||||
return compressions.count(type) > 0;
|
||||
}
|
||||
|
||||
bool is_valid_section_type(section_type type) {
|
||||
return sections.count(type) > 0;
|
||||
}
|
||||
|
||||
std::string get_compression_name(compression_type type) {
|
||||
return get_default(compressions, type);
|
||||
}
|
||||
|
@ -235,6 +235,12 @@ void check_packed_tables(global_metadata::Meta const* meta) {
|
||||
size_t num_entries = meta->dir_entries() ? meta->dir_entries()->size()
|
||||
: meta->inodes().size();
|
||||
|
||||
if (!std::is_sorted(
|
||||
meta->directories().begin(), meta->directories().end(),
|
||||
[](auto a, auto b) { return a.first_entry() < b.first_entry(); })) {
|
||||
DWARFS_THROW(runtime_error, "first_entry inconsistency");
|
||||
}
|
||||
|
||||
for (auto d : meta->directories()) {
|
||||
if (auto i = d.first_entry(); i > num_entries) {
|
||||
DWARFS_THROW(runtime_error, "first_entry out of range");
|
||||
@ -259,6 +265,114 @@ void check_packed_tables(global_metadata::Meta const* meta) {
|
||||
}
|
||||
}
|
||||
|
||||
void check_compact_strings(
|
||||
::apache::thrift::frozen::View<thrift::metadata::string_table> v,
|
||||
size_t expected_num, size_t max_item_len, std::string const& what) {
|
||||
size_t index_size = v.index().size();
|
||||
|
||||
if (!v.packed_index() && index_size > 0) {
|
||||
--index_size;
|
||||
}
|
||||
|
||||
if (index_size != expected_num) {
|
||||
DWARFS_THROW(runtime_error, "unexpected number of compact " + what);
|
||||
}
|
||||
|
||||
size_t expected_data_size = 0;
|
||||
size_t longest_item_len = 0;
|
||||
if (!v.index().empty()) {
|
||||
if (v.packed_index()) {
|
||||
expected_data_size =
|
||||
std::accumulate(v.index().begin(), v.index().end(), 0);
|
||||
longest_item_len = *std::max_element(v.index().begin(), v.index().end());
|
||||
} else {
|
||||
expected_data_size = v.index().back();
|
||||
if (!std::is_sorted(v.index().begin(), v.index().end())) {
|
||||
DWARFS_THROW(runtime_error, "inconsistent index for compact " + what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (v.buffer().size() != expected_data_size) {
|
||||
DWARFS_THROW(runtime_error, "data size mismatch for compact " + what);
|
||||
}
|
||||
|
||||
if (longest_item_len > max_item_len) {
|
||||
DWARFS_THROW(runtime_error, "invalid item length in compact " + what);
|
||||
}
|
||||
}
|
||||
|
||||
void check_plain_strings(
|
||||
::apache::thrift::frozen::View<std::vector<std::string>> v,
|
||||
size_t expected_num, size_t max_item_len, std::string const& what) {
|
||||
if (v.size() != expected_num) {
|
||||
DWARFS_THROW(runtime_error, "unexpected number of " + what);
|
||||
}
|
||||
|
||||
size_t total_size = 0;
|
||||
|
||||
for (auto s : v) {
|
||||
if (s.size() > max_item_len) {
|
||||
DWARFS_THROW(runtime_error, "unexpectedly long item in " + what);
|
||||
}
|
||||
total_size += s.size();
|
||||
}
|
||||
|
||||
if (!v.empty()) {
|
||||
if (total_size != static_cast<size_t>(v.back().end() - v.front().begin())) {
|
||||
DWARFS_THROW(runtime_error, "unexpectedly data size in " + what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_string_tables(global_metadata::Meta const* meta) {
|
||||
size_t num_names = 0;
|
||||
if (auto dep = meta->dir_entries()) {
|
||||
if (dep->size() > 1) {
|
||||
num_names = std::max_element(dep->begin(), dep->end(),
|
||||
[](auto const& a, auto const& b) {
|
||||
return a.name_index() < b.name_index();
|
||||
})
|
||||
->name_index() +
|
||||
1;
|
||||
}
|
||||
} else {
|
||||
if (meta->inodes().size() > 1) {
|
||||
num_names =
|
||||
std::max_element(meta->inodes().begin(), meta->inodes().end(),
|
||||
[](auto const& a, auto const& b) {
|
||||
return a.name_index_v2_2() < b.name_index_v2_2();
|
||||
})
|
||||
->name_index_v2_2() +
|
||||
1;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t max_name_len = 255;
|
||||
constexpr size_t max_symlink_len = 4096;
|
||||
|
||||
if (auto cn = meta->compact_names()) {
|
||||
check_compact_strings(*cn, num_names, max_name_len, "names");
|
||||
} else {
|
||||
check_plain_strings(meta->names(), num_names, max_name_len, "names");
|
||||
}
|
||||
|
||||
size_t num_symlink_strings = 0;
|
||||
if (!meta->symlink_table().empty()) {
|
||||
num_symlink_strings = *std::max_element(meta->symlink_table().begin(),
|
||||
meta->symlink_table().end()) +
|
||||
1;
|
||||
}
|
||||
|
||||
if (auto cs = meta->compact_symlinks()) {
|
||||
check_compact_strings(*cs, num_symlink_strings, max_symlink_len,
|
||||
"symlink strings");
|
||||
} else {
|
||||
check_plain_strings(meta->symlinks(), num_symlink_strings, max_symlink_len,
|
||||
"symlink strings");
|
||||
}
|
||||
}
|
||||
|
||||
void check_chunks(global_metadata::Meta const* meta) {
|
||||
auto block_size = meta->block_size();
|
||||
|
||||
@ -329,6 +443,7 @@ check_metadata(logger& lgr, global_metadata::Meta const* meta, bool check) {
|
||||
check_empty_tables(meta);
|
||||
check_index_range(meta);
|
||||
check_packed_tables(meta);
|
||||
check_string_tables(meta);
|
||||
check_chunks(meta);
|
||||
auto offsets = check_partitioning(meta);
|
||||
|
||||
|
@ -143,8 +143,10 @@ int dwarfsck(int argc, char** argv) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
filesystem_v2::identify(lgr, mm, std::cout, detail, num_workers,
|
||||
check_integrity, fsopts.image_offset);
|
||||
if (filesystem_v2::identify(lgr, mm, std::cout, detail, num_workers,
|
||||
check_integrity, fsopts.image_offset) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} catch (system_error const& e) {
|
||||
LOG_ERROR << folly::exceptionStr(e);
|
||||
|
Loading…
x
Reference in New Issue
Block a user