Avoid negative integer overflow when filesize < io_->tell().

This fixes #791.
This commit is contained in:
Kevin Backhouse
2019-04-30 09:26:18 +01:00
committed by Luis Díaz Más
parent db870755b9
commit caa4e6745a
4 changed files with 52 additions and 12 deletions
+24 -11
View File
@@ -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'};