Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fba2a1a1 authored by Elliott Hughes's avatar Elliott Hughes
Browse files

Fix SEGV in libziparchive with malformed zip file.

d77c99eb changed MappedFile to return a
bogus zero-length mapping on failure rather than nullptr. None of the
calling code was changed, though, and it seems like doing so would be a
bad idea. Revert that part of the change.

Add missing tests, and tidy up some of the logging. Also remove
single-use or obfuscatory constants from the tests.

The new "empty.zip" was created by using zip(1) to create a zip file
with one entry, then using `zip -d` to remove it.

The new "zero-size-cd.zip" was created by using zip(1) to create a zip
file containing a single empty file, and then hex editing the two byte
"size of the central directory" field in the "end of central directory
record" structure at the end of the file. (This is equivalent to, but
much smaller than, the example zip file provided by the bug reporter.)

Bug: http://b/145925341
Test: treehugger
Change-Id: Iff64673bce7dae886ccbc9dd6c2bbe18de19f9d2
parent 5a07ae14
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ struct FileRegion {
    FileRegion(borrowed_fd fd, off64_t offset, size_t length)
        : mapped_(android::base::MappedFile::FromOsHandle(adb_get_os_handle(fd), offset, length,
                                                          PROT_READ)) {
        if (mapped_.data() != nullptr) {
        if (mapped_ != nullptr) {
            return;
        }

@@ -50,14 +50,14 @@ struct FileRegion {
        }
    }

    const char* data() const { return mapped_.data() ? mapped_.data() : buffer_.data(); }
    size_t size() const { return mapped_.data() ? mapped_.size() : buffer_.size(); }
    const char* data() const { return mapped_ ? mapped_->data() : buffer_.data(); }
    size_t size() const { return mapped_ ? mapped_->size() : buffer_.size(); }

  private:
    FileRegion() = default;
    DISALLOW_COPY_AND_ASSIGN(FileRegion);

    android::base::MappedFile mapped_;
    std::unique_ptr<android::base::MappedFile> mapped_;
    std::string buffer_;
};
}  // namespace
+2 −5
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ class MappedFile {
  /**
   * Same thing, but using the raw OS file handle instead of a CRT wrapper.
   */
  static MappedFile FromOsHandle(os_handle h, off64_t offset, size_t length, int prot);
  static std::unique_ptr<MappedFile> FromOsHandle(os_handle h, off64_t offset, size_t length,
                                                  int prot);

  /**
   * Removes the mapping.
@@ -69,10 +70,6 @@ class MappedFile {
  char* data() const { return base_ + offset_; }
  size_t size() const { return size_; }

  bool isValid() const { return base_ != nullptr; }

  explicit operator bool() const { return isValid(); }

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile);

+13 −12
Original line number Diff line number Diff line
@@ -38,15 +38,14 @@ static off64_t InitPageSize() {
std::unique_ptr<MappedFile> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
                                               int prot) {
#if defined(_WIN32)
  auto file =
      FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
  return FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
#else
  auto file = FromOsHandle(fd.get(), offset, length, prot);
  return FromOsHandle(fd.get(), offset, length, prot);
#endif
  return file ? std::make_unique<MappedFile>(std::move(file)) : std::unique_ptr<MappedFile>{};
}

MappedFile MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length, int prot) {
std::unique_ptr<MappedFile> MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length,
                                                     int prot) {
  static const off64_t page_size = InitPageSize();
  size_t slop = offset % page_size;
  off64_t file_offset = offset - slop;
@@ -59,28 +58,30 @@ MappedFile MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length,
    // http://b/119818070 "app crashes when reading asset of zero length".
    // Return a MappedFile that's only valid for reading the size.
    if (length == 0 && ::GetLastError() == ERROR_FILE_INVALID) {
      return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0, nullptr};
      return std::unique_ptr<MappedFile>(
          new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0, nullptr));
    }
    return MappedFile(nullptr, 0, 0, nullptr);
    return nullptr;
  }
  void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
                             file_offset, file_length);
  if (base == nullptr) {
    CloseHandle(handle);
    return MappedFile(nullptr, 0, 0, nullptr);
    return nullptr;
  }
  return MappedFile{static_cast<char*>(base), length, slop, handle};
  return std::unique_ptr<MappedFile>(
      new MappedFile(static_cast<char*>(base), length, slop, handle));
#else
  void* base = mmap(nullptr, file_length, prot, MAP_SHARED, h, file_offset);
  if (base == MAP_FAILED) {
    // http://b/119818070 "app crashes when reading asset of zero length".
    // mmap fails with EINVAL for a zero length region.
    if (errno == EINVAL && length == 0) {
      return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0};
      return std::unique_ptr<MappedFile>(new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0));
    }
    return MappedFile(nullptr, 0, 0);
    return nullptr;
  }
  return MappedFile{static_cast<char*>(base), length, slop};
  return std::unique_ptr<MappedFile>(new MappedFile(static_cast<char*>(base), length, slop));
#endif
}

+0 −2
Original line number Diff line number Diff line
@@ -44,8 +44,6 @@ TEST(mapped_file, zero_length_mapping) {
  ASSERT_TRUE(tf.fd != -1);

  auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
  ASSERT_NE(nullptr, m);
  EXPECT_TRUE((bool)*m);
  EXPECT_EQ(0u, m->size());
  EXPECT_NE(nullptr, m->data());
}
+22 B

File added.

No diff preview for this file type.

Loading