Explorar el Código

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
implicitfield hace 2 años
padre
commit
c88d8a21cc

+ 5 - 1
Meta/Lagom/Fuzzers/FuzzTar.cpp

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

+ 7 - 5
Userland/Libraries/LibArchive/TarStream.cpp

@@ -71,7 +71,7 @@ TarInputStream::TarInputStream(InputStream& stream)
 {
     if (!m_stream.read_or_error(Bytes(&m_header, sizeof(m_header)))) {
         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;
     }
     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));
 }
 
-void TarInputStream::advance()
+ErrorOr<void> TarInputStream::advance()
 {
     if (m_finished)
-        return;
+        return Error::from_string_literal("Attempted to read a finished stream");
 
     m_generation++;
     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)))) {
         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()) {
         m_finished = true;
-        return;
+        return {};
     }
 
     VERIFY(m_stream.discard_or_error(block_size - sizeof(TarFileHeader)));
+    return {};
 }
 
 bool TarInputStream::valid() const

+ 1 - 1
Userland/Libraries/LibArchive/TarStream.h

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

+ 5 - 1
Userland/Utilities/tar.cpp

@@ -98,7 +98,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
             return {};
         };
 
-        for (; !tar_stream.finished(); tar_stream.advance()) {
+        while (!tar_stream.finished()) {
             Archive::TarFileHeader const& header = tar_stream.header();
 
             // 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.
             local_overrides.clear();
+
+            auto maybe_error = tar_stream.advance();
+            if (maybe_error.is_error())
+                return maybe_error.error();
         }
         file_stream.close();