File improve-pngchunk-bounds-checking.patch of Package exiv2-0_26.26888
This updates the implementation of PngChunk::readRawProfile()
to the version in 0.27.5
--- exiv2-0.26.orig/src/pngchunk.cpp
+++ exiv2-0.26/src/pngchunk.cpp
@@ -37,6 +37,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "iptc.hpp"
#include "image.hpp"
#include "error.hpp"
+#include "enforce.hpp"
// + standard includes
#include <sstream>
@@ -590,17 +591,12 @@ namespace Exiv2 {
DataBuf PngChunk::readRawProfile(const DataBuf& text,bool iTXt)
{
DataBuf info;
- register long i;
- register unsigned char *dp;
- const char *sp;
- unsigned int nibbles;
- long length;
unsigned char unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
- 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
- 13,14,15};
+ 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
+ 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
+ 13,14,15};
if (text.size_ == 0) {
return DataBuf();
}
@@ -611,39 +607,69 @@ namespace Exiv2 {
return info;
}
+ const char *sp = (char*) text.pData_+1; // current byte (space pointer)
+ const char *eot = (char*) text.pData_+text.size_; // end of text
- sp = (char*)text.pData_+1;
+ if (sp >= eot) {
+ return DataBuf();
+ }
// Look for newline
-
while (*sp != '\n')
+ {
sp++;
+ if ( sp == eot )
+ {
+ return DataBuf();
+ }
+ }
+ sp++ ; // step over '\n'
+ if (sp == eot) {
+ return DataBuf();
+ }
// Look for length
-
while (*sp == '\0' || *sp == ' ' || *sp == '\n')
+ {
sp++;
-
- length = (long) atol(sp);
- const char* eot = (char*)text.pData_ + text.size_;
- if (length < 0 || length > (eot - sp)/2) {
- throw Error(14);
+ if (sp == eot )
+ {
+ return DataBuf();
+ }
}
- while (*sp != ' ' && *sp != '\n')
+ // Parse the length.
+ long length = 0;
+ while ('0' <= *sp && *sp <= '9')
+ {
+ // Compute the new length using unsigned long, so that we can
+ // check for overflow.
+ const unsigned long newlength = (10 * static_cast<unsigned long>(length)) + (*sp - '0');
+ if (newlength > static_cast<unsigned long>(std::numeric_limits<long>::max())) {
+ return DataBuf(); // Integer overflow.
+ }
+ length = static_cast<long>(newlength);
sp++;
+ if (sp == eot )
+ {
+ return DataBuf();
+ }
+ }
+ sp++ ; // step over '\n'
+ if (sp == eot) {
+ return DataBuf();
+ }
- // Allocate space
+ enforce(length <= (eot - sp)/2, Exiv2::kerCorruptedMetadata);
+ // Allocate space
if (length == 0)
{
#ifdef DEBUG
std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: invalid profile length\n";
#endif
}
-
info.alloc(length);
-
if (info.size_ != length)
{
#ifdef DEBUG
@@ -654,11 +680,12 @@ namespace Exiv2 {
// Copy profile, skipping white space and column 1 "=" signs
- dp = (unsigned char*)info.pData_;
- nibbles = length * 2;
+ unsigned char *dp = (unsigned char*)info.pData_; // decode pointer
+ unsigned int nibbles = length * 2;
- for (i = 0; i < (long) nibbles; i++)
+ for (long i = 0; i < (long) nibbles; i++)
{
+ enforce(sp < eot, Exiv2::kerCorruptedMetadata);
while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
{
if (*sp == '\0')
@@ -670,6 +697,7 @@ namespace Exiv2 {
}
sp++;
+ enforce(sp < eot, Exiv2::kerCorruptedMetadata);
}
if (i%2 == 0)