Avoid negative integer overflow when filesize < io_->tell().
This fixes #791.
This commit is contained in:
parent
db870755b9
commit
caa4e6745a
@ -93,7 +93,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);
|
||||
|
||||
@ -62,6 +62,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)
|
||||
{
|
||||
@ -474,6 +482,7 @@ namespace Exiv2 {
|
||||
|
||||
/* =========================================== */
|
||||
|
||||
|
||||
void WebPImage::readMetadata()
|
||||
{
|
||||
if (io_->open() != 0) throw Error(kerDataSourceOpenFailed, io_->path(), strError());
|
||||
@ -489,7 +498,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);
|
||||
@ -497,7 +506,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];
|
||||
@ -509,9 +518,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);
|
||||
@ -522,7 +532,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);
|
||||
@ -537,7 +547,7 @@ namespace Exiv2 {
|
||||
enforce(size >= 10, Exiv2::kerCorruptedMetadata);
|
||||
|
||||
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""
|
||||
@ -558,7 +568,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);
|
||||
@ -576,7 +586,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);
|
||||
@ -588,10 +598,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];
|
||||
// 4 meaningful bytes + 2 padding bytes
|
||||
@ -672,7 +682,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
|
||||
@ -705,6 +715,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'};
|
||||
|
||||
BIN
test/data/issue_791_poc1.webp
Normal file
BIN
test/data/issue_791_poc1.webp
Normal file
Binary file not shown.
27
tests/bugfixes/github/test_issue_791.py
Normal file
27
tests/bugfixes/github/test_issue_791.py
Normal file
@ -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]
|
||||
Loading…
Reference in New Issue
Block a user