plug-ins: validate fcTL frame dimensions...

...against IHDR bounds in APNG loader

The pixel buffer is allocated using base image dimensions from the IHDR
chunk, but row write offsets were computed using the per-frame dimensions
from the fcTL chunk with no bounds check. A crafted APNG file with
fcTL.width > IHDR.width or fcTL.height > IHDR.height would cause
out-of-bounds writes into the heap on every row after row 0.

Reject fcTL frames whose dimensions or offsets extend beyond the base
image dimensions before proceeding with decoding.
This commit is contained in:
Gabriele Barbero 2026-04-03 19:32:16 +02:00
parent 6c04ce939f
commit 691785113a

View file

@ -1448,6 +1448,9 @@ load_apng_image (GFile *file,
{
while (! feof (fp))
{
guint region_width;
guint region_height;
png_id = read_apng_chunk (fp, &chunk);
if (! png_id)
{
@ -1509,6 +1512,23 @@ load_apng_image (GFile *file,
apng_frame.delay_num = png_get_uint_16 (chunk.data + 28);
apng_frame.delay_den = png_get_uint_16 (chunk.data + 30);
region_width = apng_frame.offset_x + apng_frame.width;
region_height = apng_frame.offset_y + apng_frame.height;
if (region_width > (guint) gimp_image_get_width (image) ||
region_height > (guint) gimp_image_get_height (image))
{
fclose (fp);
g_free (apng_frame.pixels);
g_free (prior_pixels);
g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
_("Invalid APNG: fcTL frame dimensions "
"exceed IHDR allocation"));
return FALSE;
}
dispose_op = chunk.data[32];
blend_op = chunk.data[33];