Merge branch 'PHP-7.4'

* PHP-7.4:
  Make MAX_IFD_NESTING_LEVEL an actual nesting level
This commit is contained in:
Nikita Popov 2020-08-31 09:36:48 +02:00
commit 5f4b169be8
3 changed files with 50 additions and 16 deletions

View File

@ -62,7 +62,8 @@ typedef unsigned char uchar;
#define EFREE_IF(ptr) if (ptr) efree(ptr)
#define MAX_IFD_NESTING_LEVEL 200
#define MAX_IFD_NESTING_LEVEL 10
#define MAX_IFD_TAGS 1000
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(exif)
@ -1975,6 +1976,7 @@ typedef struct {
int read_thumbnail;
int read_all;
int ifd_nesting_level;
int ifd_count;
int num_errors;
/* internal */
file_section_list file;
@ -2696,6 +2698,7 @@ static void exif_process_SOFn (uchar *Data, int marker, jpeg_sof_info *result)
/* forward declarations */
static bool exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, const exif_offset_info *info, size_t displacement, int section_index, int tag);
static bool exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, const exif_offset_info *info, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table);
static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offset, int section_index);
/* {{{ exif_get_markername
Get name of marker */
@ -3238,7 +3241,7 @@ static bool exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * val
/* {{{ exif_process_IFD_TAG
* Process one of the nested IFDs directories. */
static bool exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, const exif_offset_info *info, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table)
static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entry, const exif_offset_info *info, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table)
{
size_t length;
unsigned int tag, format, components;
@ -3251,13 +3254,6 @@ static bool exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, co
int dump_free;
#endif /* EXIF_DEBUG */
/* Protect against corrupt headers */
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum directory nesting level reached");
return false;
}
ImageInfo->ifd_nesting_level++;
tag = php_ifd_get16u(dir_entry, ImageInfo->motorola_intel);
format = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);
components = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel);
@ -3568,6 +3564,24 @@ static bool exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, co
}
/* }}} */
static bool exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, const exif_offset_info *info, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table)
{
bool result;
/* Protect against corrupt headers */
if (ImageInfo->ifd_count++ > MAX_IFD_TAGS) {
exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum IFD tag count reached");
return false;
}
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum directory nesting level reached");
return false;
}
ImageInfo->ifd_nesting_level++;
result = exif_process_IFD_TAG_impl(ImageInfo, dir_entry, info, displacement, section_index, ReadNextIFD, tag_table);
ImageInfo->ifd_nesting_level--;
return result;
}
/* {{{ exif_process_IFD_in_JPEG
* Process one of the nested IFDs directories. */
static bool exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, const exif_offset_info *info, size_t displacement, int section_index, int tag)
@ -4008,7 +4022,7 @@ static bool exif_scan_thumbnail(image_info_type *ImageInfo)
/* {{{ exif_process_IFD_in_TIFF
* Parse the TIFF header; */
static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offset, int section_index)
static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir_offset, int section_index)
{
int i, sn, num_entries, sub_section_index = 0;
unsigned char *dir_entry;
@ -4016,10 +4030,6 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
int entry_tag , entry_type;
tag_table_type tag_table = exif_get_tag_table(section_index);
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
return false;
}
if (ImageInfo->FileSize >= 2 && ImageInfo->FileSize - 2 >= dir_offset) {
sn = exif_file_sections_add(ImageInfo, M_PSEUDO, 2, NULL);
#ifdef EXIF_DEBUG
@ -4162,7 +4172,6 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
#ifdef EXIF_DEBUG
exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s @x%04X", exif_get_sectionname(sub_section_index), entry_offset);
#endif
ImageInfo->ifd_nesting_level++;
exif_process_IFD_in_TIFF(ImageInfo, entry_offset, sub_section_index);
if (section_index!=SECTION_THUMBNAIL && entry_tag==TAG_SUB_IFD) {
if (ImageInfo->Thumbnail.filetype != IMAGE_FILETYPE_UNKNOWN
@ -4209,7 +4218,6 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
#ifdef EXIF_DEBUG
exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read next IFD (THUMBNAIL) at x%04X", next_offset);
#endif
ImageInfo->ifd_nesting_level++;
exif_process_IFD_in_TIFF(ImageInfo, next_offset, SECTION_THUMBNAIL);
#ifdef EXIF_DEBUG
exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "%s THUMBNAIL @0x%04X + 0x%04X", ImageInfo->Thumbnail.data ? "Ignore" : "Read", ImageInfo->Thumbnail.offset, ImageInfo->Thumbnail.size);
@ -4246,6 +4254,21 @@ static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offs
}
/* }}} */
static bool exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offset, int section_index)
{
bool result;
if (ImageInfo->ifd_count++ > MAX_IFD_TAGS) {
return false;
}
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
return false;
}
ImageInfo->ifd_nesting_level++;
result = exif_process_IFD_in_TIFF_impl(ImageInfo, dir_offset, section_index);
ImageInfo->ifd_nesting_level--;
return result;
}
/* {{{ exif_scan_FILE_header
* Parse the marker stream until SOS or EOI is seen; */
static bool exif_scan_FILE_header(image_info_type *ImageInfo)
@ -4399,6 +4422,7 @@ static bool exif_read_from_impl(image_info_type *ImageInfo, php_stream *stream,
ImageInfo->ifd_nesting_level = 0;
ImageInfo->ifd_count = 0;
ImageInfo->num_errors = 0;
/* Scan the headers */

View File

@ -0,0 +1,10 @@
--TEST--
Should not cause OOM
--FILE--
<?php
var_dump(@exif_read_data(__DIR__ . '/nesting_level_oom.tiff'));
?>
--EXPECT--
bool(false)

Binary file not shown.