Skip to content

Commit 2519a03

Browse files
jbowlerctruta
authored andcommitted
refactor: Clean up the checking of chunk lengths and allocation limits
Internal changes only. Move chunk length checks to fewer places: Change `png_struct::user_chunk_malloc_max` to always have a non-zero value, in order to avoid the need to check for zero in multiple places. Add `png_chunk_max(png_ptr)`, a function-like macro defined in pngpriv.h which expresses all the previous checks on the various USER_LIMITS and system limitations. Replace the code which implemented such checks with `png_chunk_max`. Move the malloc limit length check in `png_read_chunk_header` to `png_handle_chunk` and make it conditional on the chunk type. Progressive reader: call `png_read_chunk_header`. Correct the handling of pHYs. Reviewed-by: Cosmin Truta <ctruta@gmail.com> Signed-off-by: John Bowler <jbowler@acm.org> Signed-off-by: Cosmin Truta <ctruta@gmail.com>
1 parent c4b20d0 commit 2519a03

File tree

6 files changed

+221
-235
lines changed

6 files changed

+221
-235
lines changed

png.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,18 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
278278
create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
279279
# endif
280280

281-
# ifdef PNG_USER_CHUNK_MALLOC_MAX
282281
/* Added at libpng-1.2.43 and 1.4.1, required only for read but exists
283282
* in png_struct regardless.
284283
*/
284+
# if PNG_USER_CHUNK_MALLOC_MAX > 0 /* default to compile-time limit */
285285
create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
286+
287+
/* No compile time limit so initialize to the system limit: */
288+
# elif (defined PNG_MAX_MALLOC_64K/* legacy system limit */
289+
create_struct.user_chunk_malloc_max = 65536U;
290+
291+
# else /* modern system limit SIZE_MAX (C99) */
292+
create_struct.user_chunk_malloc_max = PNG_SIZE_MAX;
286293
# endif
287294
# endif
288295

pngmem.c

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,30 +72,29 @@ png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size),
7272
* to implement a user memory handler. This checks to be sure it isn't
7373
* called with big numbers.
7474
*/
75-
#ifndef PNG_USER_MEM_SUPPORTED
76-
PNG_UNUSED(png_ptr)
77-
#endif
75+
# ifdef PNG_MAX_MALLOC_64K
76+
/* This is support for legacy systems which had segmented addressing
77+
* limiting the maximum allocation size to 65536. It takes precedence
78+
* over PNG_SIZE_MAX which is set to 65535 on true 16-bit systems.
79+
*
80+
* TODO: libpng-1.8: finally remove both cases.
81+
*/
82+
if (size > 65536U) return NULL;
83+
# endif
7884

79-
/* Some compilers complain that this is always true. However, it
80-
* can be false when integer overflow happens.
85+
/* This is checked too because the system malloc call below takes a (size_t).
8186
*/
82-
if (size > 0 && size <= PNG_SIZE_MAX
83-
# ifdef PNG_MAX_MALLOC_64K
84-
&& size <= 65536U
85-
# endif
86-
)
87-
{
88-
#ifdef PNG_USER_MEM_SUPPORTED
87+
if (size > PNG_SIZE_MAX) return NULL;
88+
89+
# ifdef PNG_USER_MEM_SUPPORTED
8990
if (png_ptr != NULL && png_ptr->malloc_fn != NULL)
9091
return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size);
92+
# else
93+
PNG_UNUSED(png_ptr)
94+
# endif
9195

92-
else
93-
#endif
94-
return malloc((size_t)size); /* checked for truncation above */
95-
}
96-
97-
else
98-
return NULL;
96+
/* Use the system malloc */
97+
return malloc((size_t)/*SAFE*/size); /* checked for truncation above */
9998
}
10099

101100
#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\

pngpread.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,8 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
193193
*/
194194
if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0)
195195
{
196-
png_byte chunk_length[4];
197-
png_byte chunk_tag[4];
198-
199196
PNG_PUSH_SAVE_BUFFER_IF_LT(8)
200-
png_push_fill_buffer(png_ptr, chunk_length, 4);
201-
png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
202-
png_reset_crc(png_ptr);
203-
png_crc_read(png_ptr, chunk_tag, 4);
204-
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
205-
png_check_chunk_name(png_ptr, png_ptr->chunk_name);
206-
png_check_chunk_length(png_ptr, png_ptr->push_length);
197+
png_ptr->push_length = png_read_chunk_header(png_ptr);
207198
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
208199
}
209200

pngpriv.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,25 @@ PNG_INTERNAL_FUNCTION(png_uint_32,png_fixed_ITU,(png_const_structrp png_ptr,
10811081
PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr,
10821082
png_const_charp user_png_ver),PNG_EMPTY);
10831083

1084+
#ifdef PNG_READ_SUPPORTED /* should only be used on read */
1085+
/* Security: read limits on the largest allocations while reading a PNG. This
1086+
* avoids very large allocations caused by PNG files with damaged or altered
1087+
* chunk 'length' fields.
1088+
*/
1089+
#ifdef PNG_SET_USER_LIMITS_SUPPORTED /* run-time limit */
1090+
# define png_chunk_max(png_ptr) ((png_ptr)->user_chunk_malloc_max)
1091+
1092+
#elif PNG_USER_CHUNK_MALLOC_MAX > 0 /* compile-time limit */
1093+
# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_USER_CHUNK_MALLOC_MAX)
1094+
1095+
#elif (defined PNG_MAX_MALLOC_64K) /* legacy system limit */
1096+
# define png_chunk_max(png_ptr) ((void)png_ptr, 65536U)
1097+
1098+
#else /* modern system limit SIZE_MAX (C99) */
1099+
# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_SIZE_MAX)
1100+
#endif
1101+
#endif /* READ */
1102+
10841103
/* Internal base allocator - no messages, NULL on failure to allocate. This
10851104
* does, however, call the application provided allocator and that could call
10861105
* png_error (although that would be a bug in the application implementation.)
@@ -1584,12 +1603,6 @@ typedef enum
15841603
handled_ok /* known, supported and handled without error */
15851604
} png_handle_result_code;
15861605

1587-
PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_const_structrp png_ptr,
1588-
png_uint_32 chunk_name),PNG_EMPTY);
1589-
1590-
PNG_INTERNAL_FUNCTION(void,png_check_chunk_length,(png_const_structrp png_ptr,
1591-
png_uint_32 chunk_length),PNG_EMPTY);
1592-
15931606
PNG_INTERNAL_FUNCTION(png_handle_result_code,png_handle_unknown,
15941607
(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep),
15951608
PNG_EMPTY);

0 commit comments

Comments
 (0)