Fix buffer overflow in XBM parser.

Avoid parsing over the buffer limit, or interpreting non-hex as hex.
This still leaves parsing of lines longer than 300 chars unreliable.

Based on Qt5 patch for CVE-2020-17507.

Signed-off-by: Slávek Banko <slavek.banko@axis.cz>
(cherry picked from commit 9d7d238e9e)
r14.0.x
Slávek Banko 4 years ago
parent d18dfa7dad
commit 02ae5beea3
No known key found for this signature in database
GPG Key ID: 608F5293A04BE668

@ -5512,18 +5512,32 @@ static inline int hex2byte( char *p )
static void read_xbm_image( QImageIO *iio ) static void read_xbm_image( QImageIO *iio )
{ {
const int buflen = 300; const int buflen = 300;
const int maxlen = 4096;
char buf[buflen]; char buf[buflen];
QRegExp r1, r2; QRegExp r1, r2;
QIODevice *d = iio->ioDevice(); QIODevice *d = iio->ioDevice();
int w=-1, h=-1; int w=-1, h=-1;
QImage image; QImage image;
Q_INT64 readBytes = 0;
Q_INT64 totalReadBytes = 0;
r1 = QString::fromLatin1("^#define[ \t]+[a-zA-Z0-9._]+[ \t]+"); r1 = QString::fromLatin1("^#define[ \t]+[a-zA-Z0-9._]+[ \t]+");
r2 = QString::fromLatin1("[0-9]+"); r2 = QString::fromLatin1("[0-9]+");
d->readLine( buf, buflen ); // "#define .._width <num>"
while (!d->atEnd() && buf[0] != '#') //skip leading comment, if any buf[0] = '\0';
d->readLine( buf, buflen ); while (buf[0] != '#') { //skip leading comment, if any
readBytes = d->readLine(buf, buflen);
// if readBytes >= buflen, it's very probably not a C file
if ((readBytes <= 0) || (readBytes >= (buflen-1)))
return;
// limit xbm headers to the first 4k in the file to prevent
// excessive reads on non-xbm files
totalReadBytes += readBytes;
if (totalReadBytes >= maxlen)
return;
}
QString sbuf; QString sbuf;
sbuf = QString::fromLatin1(buf); sbuf = QString::fromLatin1(buf);
@ -5532,7 +5546,10 @@ static void read_xbm_image( QImageIO *iio )
r2.search(sbuf, r1.matchedLength()) == r1.matchedLength() ) r2.search(sbuf, r1.matchedLength()) == r1.matchedLength() )
w = atoi( &buf[r1.matchedLength()] ); w = atoi( &buf[r1.matchedLength()] );
d->readLine( buf, buflen ); // "#define .._height <num>" readBytes = d->readLine(buf, buflen ); // "#define .._height <num>"
if (readBytes <= 0) {
return;
}
sbuf = QString::fromLatin1(buf); sbuf = QString::fromLatin1(buf);
if ( r1.search(sbuf) == 0 && if ( r1.search(sbuf) == 0 &&
@ -5543,8 +5560,11 @@ static void read_xbm_image( QImageIO *iio )
return; // format error return; // format error
for ( ;; ) { // scan for data for ( ;; ) { // scan for data
if ( d->readLine(buf, buflen) <= 0 ) // end of file readBytes = d->readLine(buf, buflen);
if (readBytes <= 0) { // end of file
return; return;
}
buf[readBytes] = '\0';
if ( strstr(buf,"0x") != 0 ) // does line contain data? if ( strstr(buf,"0x") != 0 ) // does line contain data?
break; break;
} }
@ -5562,7 +5582,10 @@ static void read_xbm_image( QImageIO *iio )
w = (w+7)/8; // byte width w = (w+7)/8; // byte width
while ( y < h ) { // for all encoded bytes... while ( y < h ) { // for all encoded bytes...
if ( p ) { // p = "0x.." if (p && (p < (buf + readBytes - 3))) { // p = "0x.."
if (!isxdigit(p[2]) || !isxdigit(p[3])) {
return;
}
*b++ = hex2byte(p+2); *b++ = hex2byte(p+2);
p += 2; p += 2;
if ( ++x == w && ++y < h ) { if ( ++x == w && ++y < h ) {
@ -5571,8 +5594,10 @@ static void read_xbm_image( QImageIO *iio )
} }
p = strstr( p, "0x" ); p = strstr( p, "0x" );
} else { // read another line } else { // read another line
if ( d->readLine(buf,buflen) <= 0 ) // EOF ==> truncated image readBytes = d->readLine(buf, buflen);
if (readBytes <= 0) // EOF ==> truncated image
break; break;
buf[readBytes] = '\0';
p = strstr( buf, "0x" ); p = strstr( buf, "0x" );
} }
} }

Loading…
Cancel
Save