Skip to content

Commit c45985d

Browse files
committed
Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3: Make MAX_IFD_NESTING_LEVEL an actual nesting level
2 parents 45ed9b4 + 376bbbd commit c45985d

File tree

3 files changed

+50
-16
lines changed

3 files changed

+50
-16
lines changed

ext/exif/exif.c

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ typedef unsigned char uchar;
6464

6565
#define EFREE_IF(ptr) if (ptr) efree(ptr)
6666

67-
#define MAX_IFD_NESTING_LEVEL 200
67+
#define MAX_IFD_NESTING_LEVEL 10
68+
#define MAX_IFD_TAGS 1000
6869

6970
/* {{{ arginfo */
7071
ZEND_BEGIN_ARG_INFO(arginfo_exif_tagname, 0)
@@ -2022,6 +2023,7 @@ typedef struct {
20222023
int read_thumbnail;
20232024
int read_all;
20242025
int ifd_nesting_level;
2026+
int ifd_count;
20252027
int num_errors;
20262028
/* internal */
20272029
file_section_list file;
@@ -2712,6 +2714,7 @@ static void exif_process_SOFn (uchar *Data, int marker, jpeg_sof_info *result)
27122714
/* forward declarations */
27132715
static int exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int tag);
27142716
static int exif_process_IFD_TAG( image_info_type *ImageInfo, char *dir_entry, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table);
2717+
static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offset, int section_index);
27152718

27162719
/* {{{ exif_get_markername
27172720
Get name of marker */
@@ -3283,7 +3286,7 @@ static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo, char * valu
32833286

32843287
/* {{{ exif_process_IFD_TAG
32853288
* Process one of the nested IFDs directories. */
3286-
static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table)
3289+
static int exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entry, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table)
32873290
{
32883291
size_t length;
32893292
unsigned int tag, format, components;
@@ -3296,13 +3299,6 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
32963299
int dump_free;
32973300
#endif /* EXIF_DEBUG */
32983301

3299-
/* Protect against corrupt headers */
3300-
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
3301-
exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum directory nesting level reached");
3302-
return FALSE;
3303-
}
3304-
ImageInfo->ifd_nesting_level++;
3305-
33063302
tag = php_ifd_get16u(dir_entry, ImageInfo->motorola_intel);
33073303
format = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel);
33083304
components = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel);
@@ -3622,6 +3618,24 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
36223618
}
36233619
/* }}} */
36243620

3621+
static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int ReadNextIFD, tag_table_type tag_table)
3622+
{
3623+
int result;
3624+
/* Protect against corrupt headers */
3625+
if (ImageInfo->ifd_count++ > MAX_IFD_TAGS) {
3626+
exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum IFD tag count reached");
3627+
return FALSE;
3628+
}
3629+
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
3630+
exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum directory nesting level reached");
3631+
return FALSE;
3632+
}
3633+
ImageInfo->ifd_nesting_level++;
3634+
result = exif_process_IFD_TAG_impl(ImageInfo, dir_entry, offset_base, IFDlength, displacement, section_index, ReadNextIFD, tag_table);
3635+
ImageInfo->ifd_nesting_level--;
3636+
return result;
3637+
}
3638+
36253639
/* {{{ exif_process_IFD_in_JPEG
36263640
* Process one of the nested IFDs directories. */
36273641
static int exif_process_IFD_in_JPEG(image_info_type *ImageInfo, char *dir_start, char *offset_base, size_t IFDlength, size_t displacement, int section_index, int tag)
@@ -4055,18 +4069,14 @@ static int exif_scan_thumbnail(image_info_type *ImageInfo)
40554069

40564070
/* {{{ exif_process_IFD_in_TIFF
40574071
* Parse the TIFF header; */
4058-
static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offset, int section_index)
4072+
static int exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir_offset, int section_index)
40594073
{
40604074
int i, sn, num_entries, sub_section_index = 0;
40614075
unsigned char *dir_entry;
40624076
size_t ifd_size, dir_size, entry_offset, next_offset, entry_length, entry_value=0, fgot;
40634077
int entry_tag , entry_type;
40644078
tag_table_type tag_table = exif_get_tag_table(section_index);
40654079

4066-
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
4067-
return FALSE;
4068-
}
4069-
40704080
if (ImageInfo->FileSize >= 2 && ImageInfo->FileSize - 2 >= dir_offset) {
40714081
sn = exif_file_sections_add(ImageInfo, M_PSEUDO, 2, NULL);
40724082
#ifdef EXIF_DEBUG
@@ -4210,7 +4220,6 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offse
42104220
#ifdef EXIF_DEBUG
42114221
exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s @x%04X", exif_get_sectionname(sub_section_index), entry_offset);
42124222
#endif
4213-
ImageInfo->ifd_nesting_level++;
42144223
exif_process_IFD_in_TIFF(ImageInfo, entry_offset, sub_section_index);
42154224
if (section_index!=SECTION_THUMBNAIL && entry_tag==TAG_SUB_IFD) {
42164225
if (ImageInfo->Thumbnail.filetype != IMAGE_FILETYPE_UNKNOWN
@@ -4254,7 +4263,6 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offse
42544263
#ifdef EXIF_DEBUG
42554264
exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read next IFD (THUMBNAIL) at x%04X", next_offset);
42564265
#endif
4257-
ImageInfo->ifd_nesting_level++;
42584266
exif_process_IFD_in_TIFF(ImageInfo, next_offset, SECTION_THUMBNAIL);
42594267
#ifdef EXIF_DEBUG
42604268
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);
@@ -4291,6 +4299,21 @@ static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offse
42914299
}
42924300
/* }}} */
42934301

4302+
static int exif_process_IFD_in_TIFF(image_info_type *ImageInfo, size_t dir_offset, int section_index)
4303+
{
4304+
int result;
4305+
if (ImageInfo->ifd_count++ > MAX_IFD_TAGS) {
4306+
return FALSE;
4307+
}
4308+
if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) {
4309+
return FALSE;
4310+
}
4311+
ImageInfo->ifd_nesting_level++;
4312+
result = exif_process_IFD_in_TIFF_impl(ImageInfo, dir_offset, section_index);
4313+
ImageInfo->ifd_nesting_level--;
4314+
return result;
4315+
}
4316+
42944317
/* {{{ exif_scan_FILE_header
42954318
* Parse the marker stream until SOS or EOI is seen; */
42964319
static int exif_scan_FILE_header(image_info_type *ImageInfo)
@@ -4446,6 +4469,7 @@ static int exif_read_from_impl(image_info_type *ImageInfo, php_stream *stream, i
44464469

44474470

44484471
ImageInfo->ifd_nesting_level = 0;
4472+
ImageInfo->ifd_count = 0;
44494473
ImageInfo->num_errors = 0;
44504474

44514475
/* Scan the headers */

ext/exif/tests/nesting_level_oom.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Should not cause OOM
3+
--FILE--
4+
<?php
5+
6+
var_dump(@exif_read_data(__DIR__ . '/nesting_level_oom.tiff'));
7+
8+
?>
9+
--EXPECT--
10+
bool(false)

ext/exif/tests/nesting_level_oom.tiff

438 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)