diff options
author | Slávek Banko <slavek.banko@axis.cz> | 2020-09-28 15:21:41 +0200 |
---|---|---|
committer | Slávek Banko <slavek.banko@axis.cz> | 2021-02-02 02:02:32 +0100 |
commit | 89a7df23e244c395ad08d5f9cc79d3264e94df46 (patch) | |
tree | 0bf10063eb16e56c4b2e4b26603f43718bc14a9e | |
parent | 91813556308d3137b639eeb1fc054813d78ade03 (diff) | |
download | qt3-89a7df23e244c395ad08d5f9cc79d3264e94df46.tar.gz qt3-89a7df23e244c395ad08d5f9cc79d3264e94df46.zip |
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 9d7d238e9efc673a0dbda1140e2eaa740fe00d6b)
-rw-r--r-- | src/kernel/qimage.cpp | 39 |
1 files changed, 32 insertions, 7 deletions
diff --git a/src/kernel/qimage.cpp b/src/kernel/qimage.cpp index 10b040b..878b38e 100644 --- a/src/kernel/qimage.cpp +++ b/src/kernel/qimage.cpp @@ -5511,18 +5511,32 @@ static inline int hex2byte( char *p ) static void read_xbm_image( QImageIO *iio ) { const int buflen = 300; + const int maxlen = 4096; char buf[buflen]; QRegExp r1, r2; QIODevice *d = iio->ioDevice(); int w=-1, h=-1; QImage image; + Q_INT64 readBytes = 0; + Q_INT64 totalReadBytes = 0; r1 = QString::fromLatin1("^#define[ \t]+[a-zA-Z0-9._]+[ \t]+"); r2 = QString::fromLatin1("[0-9]+"); - d->readLine( buf, buflen ); // "#define .._width <num>" - while (!d->atEnd() && buf[0] != '#') //skip leading comment, if any - d->readLine( buf, buflen ); + buf[0] = '\0'; + 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; sbuf = QString::fromLatin1(buf); @@ -5531,7 +5545,10 @@ static void read_xbm_image( QImageIO *iio ) r2.search(sbuf, r1.matchedLength()) == 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); if ( r1.search(sbuf) == 0 && @@ -5542,8 +5559,11 @@ static void read_xbm_image( QImageIO *iio ) return; // format error 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; + } + buf[readBytes] = '\0'; if ( strstr(buf,"0x") != 0 ) // does line contain data? break; } @@ -5561,7 +5581,10 @@ static void read_xbm_image( QImageIO *iio ) w = (w+7)/8; // byte width 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); p += 2; if ( ++x == w && ++y < h ) { @@ -5570,8 +5593,10 @@ static void read_xbm_image( QImageIO *iio ) } p = strstr( p, "0x" ); } 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; + buf[readBytes] = '\0'; p = strstr( buf, "0x" ); } } |