LibArchive: Make TarInputStream::advance report errors

Fixes this bug that was reported by OSS-Fuzz:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=52862
This commit is contained in:
implicitfield 2022-11-11 18:44:12 +02:00 committed by Andrew Kaster
parent 26a4327b06
commit c88d8a21cc
Notes: sideshowbarker 2024-07-17 04:30:53 +09:00
4 changed files with 18 additions and 8 deletions

View file

@ -16,7 +16,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
if (!tar_stream.valid()) if (!tar_stream.valid())
return 0; return 0;
for (; !tar_stream.finished(); tar_stream.advance()) { while (!tar_stream.finished()) {
auto const& header = tar_stream.header(); auto const& header = tar_stream.header();
if (!header.content_is_like_extended_header()) if (!header.content_is_like_extended_header())
@ -33,6 +33,10 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
default: default:
return 0; return 0;
} }
auto maybe_error = tar_stream.advance();
if (maybe_error.is_error())
return 0;
} }
return 0; return 0;

View file

@ -71,7 +71,7 @@ TarInputStream::TarInputStream(InputStream& stream)
{ {
if (!m_stream.read_or_error(Bytes(&m_header, sizeof(m_header)))) { if (!m_stream.read_or_error(Bytes(&m_header, sizeof(m_header)))) {
m_finished = true; m_finished = true;
m_stream.handle_any_error(); // clear out errors so we dont assert m_stream.handle_any_error(); // clear out errors so we don't assert
return; return;
} }
VERIFY(m_stream.discard_or_error(block_size - sizeof(TarFileHeader))); VERIFY(m_stream.discard_or_error(block_size - sizeof(TarFileHeader)));
@ -82,10 +82,10 @@ static constexpr unsigned long block_ceiling(unsigned long offset)
return block_size * (1 + ((offset - 1) / block_size)); return block_size * (1 + ((offset - 1) / block_size));
} }
void TarInputStream::advance() ErrorOr<void> TarInputStream::advance()
{ {
if (m_finished) if (m_finished)
return; return Error::from_string_literal("Attempted to read a finished stream");
m_generation++; m_generation++;
VERIFY(m_stream.discard_or_error(block_ceiling(m_header.size()) - m_file_offset)); VERIFY(m_stream.discard_or_error(block_ceiling(m_header.size()) - m_file_offset));
@ -93,14 +93,16 @@ void TarInputStream::advance()
if (!m_stream.read_or_error(Bytes(&m_header, sizeof(m_header)))) { if (!m_stream.read_or_error(Bytes(&m_header, sizeof(m_header)))) {
m_finished = true; m_finished = true;
return; m_stream.handle_any_error(); // clear out errors so we don't assert
return Error::from_string_literal("Failed to read the header");
} }
if (!valid()) { if (!valid()) {
m_finished = true; m_finished = true;
return; return {};
} }
VERIFY(m_stream.discard_or_error(block_size - sizeof(TarFileHeader))); VERIFY(m_stream.discard_or_error(block_size - sizeof(TarFileHeader)));
return {};
} }
bool TarInputStream::valid() const bool TarInputStream::valid() const

View file

@ -34,7 +34,7 @@ private:
class TarInputStream { class TarInputStream {
public: public:
TarInputStream(InputStream&); TarInputStream(InputStream&);
void advance(); ErrorOr<void> advance();
bool finished() const { return m_finished; } bool finished() const { return m_finished; }
bool valid() const; bool valid() const;
TarFileHeader const& header() const { return m_header; } TarFileHeader const& header() const { return m_header; }

View file

@ -98,7 +98,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
return {}; return {};
}; };
for (; !tar_stream.finished(); tar_stream.advance()) { while (!tar_stream.finished()) {
Archive::TarFileHeader const& header = tar_stream.header(); Archive::TarFileHeader const& header = tar_stream.header();
// Handle meta-entries earlier to avoid consuming the file content stream. // Handle meta-entries earlier to avoid consuming the file content stream.
@ -198,6 +198,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
// Non-global headers should be cleared after every file. // Non-global headers should be cleared after every file.
local_overrides.clear(); local_overrides.clear();
auto maybe_error = tar_stream.advance();
if (maybe_error.is_error())
return maybe_error.error();
} }
file_stream.close(); file_stream.close();