From: Patrice Fournier Date: Tue, 18 Sep 2018 03:00:53 +0000 (-0400) Subject: Address CVE-2018-17141 and fixes a few vulnerabilities in code supporting JPEG X-Git-Tag: HYLAFAX-6_0_7~1 X-Git-Url: http://git.hylafax.org/HylaFAX?a=commitdiff_plain;h=82fa7bdbffc253de4d3e80a87d47fdbf68eabe36;hp=5b95b384dd1b44b9d2c5c15cc10e50def7c1555d Address CVE-2018-17141 and fixes a few vulnerabilities in code supporting JPEG These changes are adapted from Lee's fix for this vulnerability. Luis Merino, Markus Vervier, and Eric Sesterhenn of X41 D-SEC GmbH (Security Advisory: X41-2018-008) discovered an uninitialized pointer write and also an out-of-bounds write in FaxModem::writeECMData() that could lead to remote code execution with a specially-crafted fax sender. These changes fix the coding errors and deliberately prevent malicious and malfunctioning senders from inadvertently or deliberately setting JPEG and MH/MR/MMR/JBIG formats in the same DCS signal. --- diff --git a/faxd/Class2.c++ b/faxd/Class2.c++ index 9bd312d..6439719 100644 --- a/faxd/Class2.c++ +++ b/faxd/Class2.c++ @@ -485,6 +485,15 @@ Class2Modem::parseClass2Capabilities(const char* cap, Class2Params& params, bool } else { if (jpscan == 0x1) params.jp = JP_GREY; else if (jpscan & 0x2) params.jp = JP_COLOR; + /* + * ITU T.30 does not specify that bits 16 (MR) or 31 (MMR) must be set to zero if color fax is used; + * and ITU T.32 Table 21 provides a data field, "JP", for JPEG support separate from "DF" for data + * format and does not specify that DF is meaningless in DCS when JP is used; but because T.4/T.6 + * (MH/MR/MMR), JBIG, and JPEG are distinct formats from each other, we must conclude that any + * indication of JPEG in DCS must, therefore, invalidate any indication in DCS of MH/MR/MMR/JBIG. + * Otherwise, having both df and jp be non-zero will be confusing and possibly cause problems. + */ + if (params.jp != JP_NONE) params.df = 0; // Yes, this is DF_1DMH, but there is no "DF_NONE". } return (true); } else { diff --git a/faxd/CopyQuality.c++ b/faxd/CopyQuality.c++ index 6ebc936..d1f2d0f 100644 --- a/faxd/CopyQuality.c++ +++ b/faxd/CopyQuality.c++ @@ -38,6 +38,7 @@ #include #define RCVBUFSIZ (32*1024) // XXX +#define COLORBUFSIZ (2000*1024) // 1MB is not big enough static void setupCompression(TIFF*, u_int, u_int, uint32); @@ -356,7 +357,7 @@ FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality, * rather fax-specific. */ recvEOLCount = 0; - recvRow = (u_char*) malloc(1024*1000); // 1M should do it? + recvRow = (u_char*) malloc(COLORBUFSIZ); fxAssert(recvRow != NULL, "page buffering error (JPEG page)."); recvPageStart = recvRow; } @@ -408,8 +409,12 @@ FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality, if (params.df == DF_JBIG) { flushRawData(tif, 0, (const u_char*) buf, cc); } else { - memcpy(recvRow, (const char*) buf, cc); - recvRow += cc; + /* We don't support reception of a JPEG page bigger than COLORBUFSIZ. */ + if (recvRow + cc - recvPageStart > COLORBUFSIZ) cc = recvPageStart + COLORBUFSIZ - recvRow; + if (cc > 0) { + memcpy(recvRow, (const char*) buf, cc); + recvRow += cc; + } } } while (!fin); if (params.df == DF_JBIG) clearSDNORMCount(); @@ -987,7 +992,7 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par case JP_GREY+4: case JP_COLOR+4: recvEOLCount = 0; - recvRow = (u_char*) malloc(1024*1000); // 1M should do it? + recvRow = (u_char*) malloc(COLORBUFSIZ); fxAssert(recvRow != NULL, "page buffering error (JPEG page)."); recvPageStart = recvRow; setupStartPage(tif, params); @@ -1039,14 +1044,20 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par } break; } - if (params.jp != JP_GREY && params.jp != JP_COLOR) { - flushRawData(tif, 0, (const u_char*) buf, cc); - } else { - memcpy(recvRow, (const char*) buf, cc); - recvRow += cc; - } - if (seq & 2 && (params.jp == JP_GREY || params.jp == JP_COLOR)) { - fixupJPEG(tif); + switch (dataform) { + case JP_GREY+4: + case JP_COLOR+4: + /* We don't support reception of a JPEG page bigger than COLORBUFSIZ. */ + if (recvRow + cc - recvPageStart > COLORBUFSIZ) cc = recvPageStart + COLORBUFSIZ - recvRow; + if (cc > 0) { + memcpy(recvRow, (const char*) buf, cc); + recvRow += cc; + } + if (seq & 2) fixupJPEG(tif); + break; + default: + flushRawData(tif, 0, (const u_char*) buf, cc); + break; } } diff --git a/libhylafax/Class2Params.c++ b/libhylafax/Class2Params.c++ index 0409cbd..81b9a22 100644 --- a/libhylafax/Class2Params.c++ +++ b/libhylafax/Class2Params.c++ @@ -303,6 +303,15 @@ Class2Params::setFromDCS(FaxParams& dcs_caps) if (dcs_caps.isBitEnabled(FaxParams::BITNUM_FULLCOLOR)) { if (jp == JP_GREY) jp = JP_COLOR; } + /* + * ITU T.30 does not specify that bits 16 (MR) or 31 (MMR) must be set to zero if color fax is used; + * and ITU T.32 Table 21 provides a data field, "JP", for JPEG support separate from "DF" for data + * format and does not specify that DF is meaningless in DCS when JP is used; but because T.4/T.6 + * (MH/MR/MMR), JBIG, and JPEG are distinct formats from each other, we must conclude that any + * indication of JPEG in DCS must, therefore, invalidate any indication in DCS of MH/MR/MMR/JBIG. + * Otherwise, having both df and jp be non-zero will be confusing and possibly cause problems. + */ + if (jp != JP_NONE) df = 0; // Yes, this is DF_1DMH, but there is no "DF_NONE". if (ec == EC_DISABLE && (df == DF_2DMMR || df == DF_JBIG || jp == JP_GREY || jp == JP_COLOR)) { // MMR, JBIG, and JPEG require ECM... we've seen cases where fax