Skip to content

Commit 07458ea

Browse files
committed
fix(filesystem_parser): make find_image_offset more reliable
1 parent 5fb5ebf commit 07458ea

File tree

2 files changed

+54
-22
lines changed

2 files changed

+54
-22
lines changed

src/reader/internal/filesystem_parser.cpp

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,34 +81,66 @@ filesystem_parser::find_image_offset(mmif& mm, file_off_t image_offset) {
8181
auto fh = mm.as<file_header>(pos);
8282

8383
if (fh->minor < 2) {
84-
// best we can do for older file systems
85-
return pos;
86-
}
87-
88-
// do a little more validation before we return
89-
if (pos + sizeof(section_header_v2) >= mm.size()) {
90-
break;
91-
}
92-
93-
auto sh = mm.as<section_header_v2>(pos);
94-
95-
if (sh->number == 0) {
96-
auto endpos = pos + sh->length + 2 * sizeof(section_header_v2);
97-
98-
if (endpos < sh->length) {
99-
// overflow
84+
// v1 section header, presumably
85+
if (pos + sizeof(file_header) + sizeof(section_header) >= mm.size()) {
10086
break;
10187
}
10288

103-
if (endpos >= mm.size()) {
89+
auto sh = mm.as<section_header>(pos + sizeof(file_header));
90+
91+
// The only compression types supported before v0.3.0
92+
auto is_valid_compression = [](compression_type_v1 c) {
93+
return c == compression_type_v1::NONE ||
94+
c == compression_type_v1::LZMA ||
95+
c == compression_type_v1::ZSTD ||
96+
c == compression_type_v1::LZ4 || c == compression_type_v1::LZ4HC;
97+
};
98+
99+
// First section must be either a block or the metadata schema,
100+
// using a valid compression type.
101+
if ((sh->type == section_type::BLOCK ||
102+
sh->type == section_type::METADATA_V2_SCHEMA) &&
103+
is_valid_compression(sh->compression) && sh->length > 0) {
104+
auto nextshpos =
105+
pos + sizeof(file_header) + sizeof(section_header) + sh->length;
106+
if (nextshpos + sizeof(section_header) < mm.size()) {
107+
auto nsh = mm.as<section_header>(nextshpos);
108+
// the next section must be a block or a metadata schema if the first
109+
// section was a block *or* a metadata block if the first section was
110+
// a metadata schema
111+
if ((sh->type == section_type::BLOCK
112+
? nsh->type == section_type::BLOCK ||
113+
nsh->type == section_type::METADATA_V2_SCHEMA
114+
: nsh->type == section_type::METADATA_V2) &&
115+
is_valid_compression(nsh->compression) && nsh->length > 0) {
116+
// we can be somewhat sure that this is where the filesystem starts
117+
return pos;
118+
}
119+
}
120+
}
121+
} else {
122+
// do a little more validation before we return
123+
if (pos + sizeof(section_header_v2) >= mm.size()) {
104124
break;
105125
}
106126

107-
auto ps = mm.as<void>(pos + sh->length + sizeof(section_header_v2));
127+
auto sh = mm.as<section_header_v2>(pos);
128+
129+
if (sh->number == 0) {
130+
auto endpos = pos + sh->length + 2 * sizeof(section_header_v2);
131+
132+
if (endpos >= sh->length) {
133+
if (endpos >= mm.size()) {
134+
break;
135+
}
136+
137+
auto ps = mm.as<void>(pos + sh->length + sizeof(section_header_v2));
108138

109-
if (::memcmp(ps, magic.data(), magic.size()) == 0 and
110-
reinterpret_cast<section_header_v2 const*>(ps)->number == 1) {
111-
return pos;
139+
if (::memcmp(ps, magic.data(), magic.size()) == 0 and
140+
reinterpret_cast<section_header_v2 const*>(ps)->number == 1) {
141+
return pos;
142+
}
143+
}
112144
}
113145
}
114146

test/filesystem_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ TEST(filesystem, find_image_offset) {
260260
EXPECT_NO_THROW(make_fs(prefix + valid_fs));
261261

262262
EXPECT_THAT([&] { make_fs("dwarfs"); }, throws_no_fs_found);
263-
EXPECT_THAT([&] { make_fs(v1_header + "X"); }, throws_no_schema);
263+
EXPECT_THAT([&] { make_fs(v1_header + "X"); }, throws_no_fs_found);
264264
EXPECT_THAT([&] { make_fs(v2_header + "X"); }, throws_no_fs_found);
265265
EXPECT_THAT([&] { make_fs(v2_header + "X" + valid_v2_header(1) + "X"); },
266266
throws_no_schema);

0 commit comments

Comments
 (0)