Multiple missing sanity checks for proper file form were found in php, when processing Exchangeable Image File Format (EXIF) image files. A remote attacker could provide a specially-crafted EXIF image file, leading to php application, using the EXIF extension, crash, once processed. References: ----------- http://www.php.net/ChangeLog-5.php Upstream patch: --------------- http://svn.php.net/viewvc?view=revision&revision=287371
Created attachment 361646 [details] Local copy of PHP-5.2.11 EXIF sanity patch.
This issue affects the versions of php package, as shipped with Red Hat Enterprise Linux 3, 4, and 5.
MITRE's CVE-2009-3292 record: ----------------------------- Unspecified vulnerability in PHP before 5.2.11 has unknown impact and attack vectors related to "missing sanity checks around exif processing." References: ----------- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3292 http://www.php.net/ChangeLog-5.php#5.2.11 http://www.php.net/releases/5_2_11.php http://www.osvdb.org/58186 http://secunia.com/advisories/36791
Upstream patch introduces 3 changes: - length check in exif_process_APP1() - if (memcmp(CharBuf+2, ExifHeader, 6)) { + if (length <= 8 || memcmp(CharBuf+2, ExifHeader, 6)) { This change is not very interesting for memcmp() call on the same line, as possible buffer over-read is rather short here. More interesting is a subsequent call to exif_process_TIFF_in_JPEG(): exif_process_TIFF_in_JPEG(ImageInfo, CharBuf + 8, length - 8, displacement+8 TSRMLS_CC); There, length - 8 can integer underflow, passing negative (or actually very large positive value, as unsigned size_t type is used for length parameters) is passed to the function. Later on, this length value is used as an upper bound when reading more data from CharBuf buffer, that contains EXIF info loaded from the file. It should be noted that when length <= 8, all data later read in exif_process_TIFF_in_JPEG() are not reliably controlled by an attacker, so EXIF parsing may fail on any of the checks done in the function (e.g. where EXIF data format is determined). Theoretically, memory may contain desired data from some previous calls, so the checks may pass and offset_of_ifd may get set to a large value, allow further buffer over-reads, that may cause interpreter crash or (quite unlikely) cause PHP exif functions to leak some data from interpreters memory. So impact and low severity rating identical to similar problem fixed in PHP 5.2.10 - see bug #506896. - EOF checking when reading lh / ll - lh = php_stream_getc(ImageInfo->infile); - ll = php_stream_getc(ImageInfo->infile); + if ((lh = php_stream_getc(ImageInfo->infile)) == EOF) { + EXIF_ERRLOG_CORRUPT(ImageInfo) + return FALSE; + } + if ((ll = php_stream_getc(ImageInfo->infile)) == EOF) { + EXIF_ERRLOG_CORRUPT(ImageInfo) + return FALSE; + } We can ignore lh case completely, as EOF in reading lh means EOF for ll. EOF is defined as (-1), so when assigned to unsigned lh / ll, those variables will hold UINT_MAX (0xFFFFFFFF on both 32 and 64 bit arches). lh and ll is used to calculate itemlen: itemlen = (lh << 8) | ll; Given the "| ll", if ll is 0xFFFFFFFF, we can ignore lh completely. itemlen is then used passed to exif_file_sections_add() as: sn = exif_file_sections_add(ImageInfo, marker, itemlen+1, NULL); size argument of exif_file_sections_add() is size_t, so it will be 0 on 32 bit arches, 2^32 on 64 bits. This size is used as data buffer size: if (!size) { data = NULL; } else if (data == NULL) { data = safe_emalloc(size, 1, 0); } On 32 bits, no buffer is allocated, which leads to a NULL pointer dereference back in exif_scan_JPEG_header(): Data = ImageInfo->file.list[sn].data; // data is NULL /* Store first two pre-read bytes. */ Data[0] = (uchar)lh; Data[1] = (uchar)ll; On 64 bits, there's an attempt to allocate large amount of memory (4G). This is likely to fail on PHP's memory_limit (values between 32M (default) and 128M are common) or system memory limit, or allocate large buffer if no limits are set (unlikely). - MAX_IFD_NESTING_LEVEL check for TIFF exif header It seems this may cause PHP to process EXIF data in loop until execution time limit is hit.
(In reply to comment #4) > - MAX_IFD_NESTING_LEVEL check for TIFF exif header > > It seems this may cause PHP to process EXIF data in loop until execution time > limit is hit. To correct myself... This problem causes exif_process_IFD_in_TIFF() to be called recursively without limiting the depth of recursion. Hence this exhausts all stack memory and results in php process crash in a fraction of the default execution time limit. Hence impact=low too.
This issue has been addressed in following products: Red Hat Enterprise Linux 5 Red Hat Enterprise Linux 4 Red Hat Enterprise Linux 3 Via RHSA-2010:0040 https://rhn.redhat.com/errata/RHSA-2010-0040.html