File CVE-2019-13111.patch of Package exiv2-0_26.26888
From caa4e6745a76a23bb80127cf54c0d65096ae684c Mon Sep 17 00:00:00 2001
From: Kevin Backhouse <kev@semmle.com>
Date: Tue, 30 Apr 2019 09:26:18 +0100
Subject: [PATCH] Avoid negative integer overflow when `filesize <
io_->tell()`.
This fixes #791.
---
include/exiv2/webpimage.hpp | 2 +-
src/webpimage.cpp | 35 ++++++++++++++++--------
test/data/issue_791_poc1.webp | Bin 0 -> 28 bytes
tests/bugfixes/github/test_issue_791.py | 27 ++++++++++++++++++
4 files changed, 52 insertions(+), 12 deletions(-)
create mode 100644 test/data/issue_791_poc1.webp
create mode 100644 tests/bugfixes/github/test_issue_791.py
Index: exiv2-0.26/include/exiv2/webpimage.hpp
===================================================================
--- exiv2-0.26.orig/include/exiv2/webpimage.hpp
+++ exiv2-0.26/include/exiv2/webpimage.hpp
@@ -95,7 +95,7 @@ namespace Exiv2 {
byte *header, long header_size);
bool equalsWebPTag(Exiv2::DataBuf& buf ,const char* str);
void debugPrintHex(byte *data, long size);
- void decodeChunks(uint64_t filesize);
+ void decodeChunks(uint32_t filesize);
void inject_VP8X(BasicIo& iIo, bool has_xmp, bool has_exif,
bool has_alpha, bool has_icc, int width,
int height);
Index: exiv2-0.26/src/webpimage.cpp
===================================================================
--- exiv2-0.26.orig/src/webpimage.cpp
+++ exiv2-0.26/src/webpimage.cpp
@@ -66,6 +66,14 @@ namespace Exiv2 {
namespace Exiv2 {
using namespace Exiv2::Internal;
+ // This static function is a temporary fix in v0.27. In the next version,
+ // it will be added as a method of BasicIo.
+ static void readOrThrow(BasicIo& iIo, byte* buf, long rcount, ErrorCode err) {
+ const long nread = iIo.read(buf, rcount);
+ enforce(nread == rcount, err);
+ enforce(!iIo.error(), err);
+ }
+
WebPImage::WebPImage(BasicIo::AutoPtr io)
: Image(ImageType::webp, mdNone, io)
{
@@ -477,6 +485,7 @@ namespace Exiv2 {
/* =========================================== */
+
void WebPImage::readMetadata()
{
if (io_->open() != 0) throw Error(9, io_->path(), strError());
@@ -492,7 +501,7 @@ namespace Exiv2 {
DataBuf chunkId(5);
chunkId.pData_[4] = '\0' ;
- io_->read(data, WEBP_TAG_SIZE * 3);
+ readOrThrow(*io_, data, WEBP_TAG_SIZE * 3, Exiv2::kerCorruptedMetadata);
const uint32_t filesize = Exiv2::getULong(data + WEBP_TAG_SIZE, littleEndian) + 8;
enforce(filesize <= io_->size(), Exiv2::kerCorruptedMetadata);
@@ -500,7 +509,7 @@ namespace Exiv2 {
} // WebPImage::readMetadata
- void WebPImage::decodeChunks(uint64_t filesize)
+ void WebPImage::decodeChunks(uint32_t filesize)
{
DataBuf chunkId(5);
byte size_buff[WEBP_TAG_SIZE];
@@ -512,9 +521,10 @@ namespace Exiv2 {
chunkId.pData_[4] = '\0' ;
while ( !io_->eof() && (uint64_t) io_->tell() < filesize) {
- io_->read(chunkId.pData_, WEBP_TAG_SIZE);
- io_->read(size_buff, WEBP_TAG_SIZE);
+ readOrThrow(*io_, chunkId.pData_, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
+ readOrThrow(*io_, size_buff, WEBP_TAG_SIZE, Exiv2::kerCorruptedMetadata);
const uint32_t size = Exiv2::getULong(size_buff, littleEndian);
+ enforce(io_->tell() <= filesize, Exiv2::kerCorruptedMetadata);
enforce(size <= (filesize - io_->tell()), Exiv2::kerCorruptedMetadata);
DataBuf payload(size);
@@ -523,7 +533,7 @@ namespace Exiv2 {
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];
- io_->read(payload.pData_, payload.size_);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf, &payload.pData_[4], 3);
@@ -536,7 +546,7 @@ namespace Exiv2 {
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_VP8) && !has_canvas_data) {
has_canvas_data = true;
- io_->read(payload.pData_, payload.size_);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
byte size_buf[WEBP_TAG_SIZE];
// Fetch width""
@@ -555,7 +565,7 @@ namespace Exiv2 {
byte size_buf_w[2];
byte size_buf_h[3];
- io_->read(payload.pData_, payload.size_);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf_w, &payload.pData_[1], 2);
@@ -571,7 +581,7 @@ namespace Exiv2 {
has_canvas_data = true;
byte size_buf[WEBP_TAG_SIZE];
- io_->read(payload.pData_, payload.size_);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
// Fetch width
memcpy(&size_buf, &payload.pData_[6], 3);
@@ -583,10 +593,10 @@ namespace Exiv2 {
size_buf[3] = 0;
pixelHeight_ = Exiv2::getULong(size_buf, littleEndian) + 1;
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_ICCP)) {
- io_->read(payload.pData_, payload.size_);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
this->setIccProfile(payload);
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_EXIF)) {
- io_->read(payload.pData_, payload.size_);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
byte size_buff[2];
byte exifLongHeader[] = { 0xFF, 0x01, 0xFF, 0xE1 };
@@ -667,7 +677,7 @@ namespace Exiv2 {
if (rawExifData) free(rawExifData);
} else if (equalsWebPTag(chunkId, WEBP_CHUNK_HEADER_XMP)) {
- io_->read(payload.pData_, payload.size_);
+ readOrThrow(*io_, payload.pData_, payload.size_, Exiv2::kerCorruptedMetadata);
xmpPacket_.assign(reinterpret_cast<char*>(payload.pData_), payload.size_);
if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) {
#ifndef SUPPRESS_WARNINGS
@@ -700,6 +710,9 @@ namespace Exiv2 {
bool isWebPType(BasicIo& iIo, bool /*advance*/)
{
+ if (iIo.size() < 12) {
+ return false;
+ }
const int32_t len = 4;
const unsigned char RiffImageId[4] = { 'R', 'I', 'F' ,'F'};
const unsigned char WebPImageId[4] = { 'W', 'E', 'B' ,'P'};
Index: exiv2-0.26/tests/bugfixes/github/test_issue_791.py
===================================================================
--- /dev/null
+++ exiv2-0.26/tests/bugfixes/github/test_issue_791.py
@@ -0,0 +1,27 @@
+import system_tests
+
+
+class IntegerOverflowInWebpImageReadMetadata(
+ metaclass=system_tests.CaseMeta):
+ """
+ Regression test for the bug described in:
+ https://github.com/Exiv2/exiv2/issues/791
+
+ Due to an integer overflow bug (#791), this test triggers a 4GB
+ memory allocation. So the test will fail with a std::bad_alloc
+ exception if less than 4GB is available. On Linux, you can use
+ `ulimit -v 4000000` to reduce the available memory to slightly
+ less than 4GB.
+ """
+ url = "https://github.com/Exiv2/exiv2/issues/791"
+
+ filename = system_tests.path(
+ "$data_path/issue_791_poc1.webp"
+ )
+ commands = ["$exiv2 $filename"]
+ stdout = [""]
+ stderr = ["""Exiv2 exception in print action for file $filename:
+corrupted image metadata
+"""
+]
+ retval = [1]