From 56ebadd03c066f8281f3b0c0e12b18120a9301bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E8=AF=9A?= Date: Tue, 25 Nov 2025 14:32:45 +0800 Subject: [PATCH] Add patch to fix CVE-2025-64505,CVE-2025-64506,CVE-2025-64720 and CVE-2025-65018 --- 0001-bugfix-for-CVE-2025-64505-1.patch | 160 +++++++++++++++++++++++++ 0001-bugfix-for-CVE-2025-64505-2.patch | 48 ++++++++ 0001-bugfix-for-CVE-2025-64505-3.patch | 31 +++++ 0002-bugfix-for-CVE-2025-64506.patch | 53 ++++++++ 0003-bugfix-for-CVE-2025-64720.patch | 102 ++++++++++++++++ 0004-bugfix-for-CVE-2025-65018-1.patch | 56 +++++++++ 0004-bugfix-for-CVE-2025-65018-2.patch | 159 ++++++++++++++++++++++++ libpng.spec | 23 +++- 8 files changed, 631 insertions(+), 1 deletion(-) create mode 100644 0001-bugfix-for-CVE-2025-64505-1.patch create mode 100644 0001-bugfix-for-CVE-2025-64505-2.patch create mode 100644 0001-bugfix-for-CVE-2025-64505-3.patch create mode 100644 0002-bugfix-for-CVE-2025-64506.patch create mode 100644 0003-bugfix-for-CVE-2025-64720.patch create mode 100644 0004-bugfix-for-CVE-2025-65018-1.patch create mode 100644 0004-bugfix-for-CVE-2025-65018-2.patch diff --git a/0001-bugfix-for-CVE-2025-64505-1.patch b/0001-bugfix-for-CVE-2025-64505-1.patch new file mode 100644 index 0000000..6301483 --- /dev/null +++ b/0001-bugfix-for-CVE-2025-64505-1.patch @@ -0,0 +1,160 @@ +From ea094764f3436e3c6524622724c2d342a3eff235 Mon Sep 17 00:00:00 2001 +From: Cosmin Truta +Date: Sat, 8 Nov 2025 17:16:59 +0200 +Subject: [PATCH] Fix a memory leak in function `png_set_quantize`; refactor + +Release the previously-allocated array `quantize_index` before +reallocating it. This avoids leaking memory when the function +`png_set_quantize` is called multiple times on the same `png_struct`. + +This function assumed single-call usage, but fuzzing revealed that +repeated calls would overwrite the pointers without freeing the +original allocations, leaking 256 bytes per call for `quantize_index` +and additional memory for `quantize_sort` when histogram-based +quantization is used. + +Also remove the array `quantize_sort` from the list of `png_struct` +members and make it a local variable. This array is initialized, +used and released exclusively inside the function `png_set_quantize`. + +Reported-by: Samsung-PENTEST +Analyzed-by: degrigis +Reviewed-by: John Bowler +--- + pngrtran.c | 43 +++++++++++++++++++++++-------------------- + pngstruct.h | 1 - + 2 files changed, 23 insertions(+), 21 deletions(-) + +diff --git a/pngrtran.c b/pngrtran.c +index 1809db7047..4632dd5215 100644 +--- a/pngrtran.c ++++ b/pngrtran.c +@@ -501,6 +501,12 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + { + int i; + ++ /* Initialize the array to index colors. ++ * ++ * Be careful to avoid leaking memory. Applications are allowed to call ++ * this function more than once per png_struct. ++ */ ++ png_free(png_ptr, png_ptr->quantize_index); + png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte)))); + for (i = 0; i < num_palette; i++) +@@ -515,15 +521,14 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + * Perhaps not the best solution, but good enough. + */ + +- int i; ++ png_bytep quantize_sort; ++ int i, j; + +- /* Initialize an array to sort colors */ +- png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, ++ /* Initialize the local array to sort colors. */ ++ quantize_sort = (png_bytep)png_malloc(png_ptr, + (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte)))); +- +- /* Initialize the quantize_sort array */ + for (i = 0; i < num_palette; i++) +- png_ptr->quantize_sort[i] = (png_byte)i; ++ quantize_sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + * bubble sort, and running it until we have sorted +@@ -535,19 +540,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* To stop early if the list is pre-sorted */ +- int j; + + done = 1; + for (j = 0; j < i; j++) + { +- if (histogram[png_ptr->quantize_sort[j]] +- < histogram[png_ptr->quantize_sort[j + 1]]) ++ if (histogram[quantize_sort[j]] ++ < histogram[quantize_sort[j + 1]]) + { + png_byte t; + +- t = png_ptr->quantize_sort[j]; +- png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; +- png_ptr->quantize_sort[j + 1] = t; ++ t = quantize_sort[j]; ++ quantize_sort[j] = quantize_sort[j + 1]; ++ quantize_sort[j + 1] = t; + done = 0; + } + } +@@ -559,18 +563,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + /* Swap the palette around, and set up a table, if necessary */ + if (full_quantize != 0) + { +- int j = num_palette; ++ j = num_palette; + + /* Put all the useful colors within the max, but don't + * move the others. + */ + for (i = 0; i < maximum_colors; i++) + { +- if ((int)png_ptr->quantize_sort[i] >= maximum_colors) ++ if ((int)quantize_sort[i] >= maximum_colors) + { + do + j--; +- while ((int)png_ptr->quantize_sort[j] >= maximum_colors); ++ while ((int)quantize_sort[j] >= maximum_colors); + + palette[i] = palette[j]; + } +@@ -578,7 +582,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + } + else + { +- int j = num_palette; ++ j = num_palette; + + /* Move all the used colors inside the max limit, and + * develop a translation table. +@@ -586,13 +590,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + for (i = 0; i < maximum_colors; i++) + { + /* Only move the colors we need to */ +- if ((int)png_ptr->quantize_sort[i] >= maximum_colors) ++ if ((int)quantize_sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; +- while ((int)png_ptr->quantize_sort[j] >= maximum_colors); ++ while ((int)quantize_sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; +@@ -630,8 +634,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + } + } + } +- png_free(png_ptr, png_ptr->quantize_sort); +- png_ptr->quantize_sort = NULL; ++ png_free(png_ptr, quantize_sort); + } + else + { +diff --git a/pngstruct.h b/pngstruct.h +index 084422bc1e..fe5fa04155 100644 +--- a/pngstruct.h ++++ b/pngstruct.h +@@ -405,7 +405,6 @@ struct png_struct_def + + #ifdef PNG_READ_QUANTIZE_SUPPORTED + /* The following three members were added at version 1.0.14 and 1.2.4 */ +- png_bytep quantize_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is + in the palette */ + png_bytep palette_to_index; /* which original index points to this + diff --git a/0001-bugfix-for-CVE-2025-64505-2.patch b/0001-bugfix-for-CVE-2025-64505-2.patch new file mode 100644 index 0000000..8aa4b51 --- /dev/null +++ b/0001-bugfix-for-CVE-2025-64505-2.patch @@ -0,0 +1,48 @@ +From 6a528eb5fd0dd7f6de1c39d30de0e41473431c37 Mon Sep 17 00:00:00 2001 +From: Cosmin Truta +Date: Sat, 8 Nov 2025 23:58:26 +0200 +Subject: [PATCH] Fix a buffer overflow in `png_do_quantize` + +Allocate the quantize_index array to PNG_MAX_PALETTE_LENGTH (256 bytes) +instead of num_palette bytes. This approach matches the allocation +pattern for `palette[]`, `trans_alpha[]` and `riffled_palette[]` which +were similarly oversized in libpng 1.2.1 to prevent buffer overflows +from malformed PNG files with out-of-range palette indices. + +Out-of-range palette indices `index >= num_palette` will now read +identity-mapped values from the `quantize_index` array (where index N +maps to palette entry N). This prevents undefined behavior while +avoiding runtime bounds checking overhead in the performance-critical +pixel processing loop. + +Reported-by: Samsung-PENTEST +Analyzed-by: degrigis +--- + pngrtran.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/pngrtran.c b/pngrtran.c +index 4632dd5215..9c2475fde2 100644 +--- a/pngrtran.c ++++ b/pngrtran.c +@@ -502,14 +502,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, + int i; + + /* Initialize the array to index colors. ++ * ++ * Ensure quantize_index can fit 256 elements (PNG_MAX_PALETTE_LENGTH) ++ * rather than num_palette elements. This is to prevent buffer overflows ++ * caused by malformed PNG files with out-of-range palette indices. + * + * Be careful to avoid leaking memory. Applications are allowed to call + * this function more than once per png_struct. + */ + png_free(png_ptr, png_ptr->quantize_index); + png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, +- (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte)))); +- for (i = 0; i < num_palette; i++) ++ PNG_MAX_PALETTE_LENGTH); ++ for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++) + png_ptr->quantize_index[i] = (png_byte)i; + } + diff --git a/0001-bugfix-for-CVE-2025-64505-3.patch b/0001-bugfix-for-CVE-2025-64505-3.patch new file mode 100644 index 0000000..fa32386 --- /dev/null +++ b/0001-bugfix-for-CVE-2025-64505-3.patch @@ -0,0 +1,31 @@ +From 83b23a888b4395c3ae0af3f6d484fce3e4a81155 Mon Sep 17 00:00:00 2001 +From: Cosmin Truta +Date: Mon, 10 Nov 2025 11:11:42 +0200 +Subject: [PATCH] refactor: Delete unreachable code from + `png_do_read_transformations` + +After calling `png_do_quantize` from `png_do_read_transformations`, +`rowbytes` (i.e. the length in bytes of a non-empty row) is always +non-zero. The subsequent call to `png_error` was therefore unreachable. +--- + pngrtran.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/pngrtran.c b/pngrtran.c +index 9c2475fde2..548780030a 100644 +--- a/pngrtran.c ++++ b/pngrtran.c +@@ -5016,13 +5016,8 @@ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) + + #ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) +- { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); +- +- if (row_info->rowbytes == 0) +- png_error(png_ptr, "png_do_quantize returned rowbytes=0"); +- } + #endif /* READ_QUANTIZE */ + + #ifdef PNG_READ_EXPAND_16_SUPPORTED diff --git a/0002-bugfix-for-CVE-2025-64506.patch b/0002-bugfix-for-CVE-2025-64506.patch new file mode 100644 index 0000000..5dba6d0 --- /dev/null +++ b/0002-bugfix-for-CVE-2025-64506.patch @@ -0,0 +1,53 @@ +From 2bd84c019c300b78e811743fbcddb67c9d9bf821 Mon Sep 17 00:00:00 2001 +From: Cosmin Truta +Date: Fri, 7 Nov 2025 22:40:05 +0200 +Subject: [PATCH] Fix a heap buffer overflow in `png_write_image_8bit` + +The condition guarding the pre-transform path incorrectly allowed 8-bit +input data to enter `png_write_image_8bit` which expects 16-bit input. +This caused out-of-bounds reads when processing 8-bit grayscale+alpha +images (GitHub #688), or 8-bit RGB or RGB+alpha images (GitHub #746), +with the `convert_to_8bit` flag set (an invalid combination that should +bypass the pre-transform path). + +The second part of the condition, i.e. + + colormap == 0 && convert_to_8bit != 0 + +failed to verify that input was 16-bit, i.e. + + linear != 0 + +contradicting the comment "This only applies when the input is 16-bit". + +The fix consists in restructuring the condition to ensure both the +`alpha` path and the `convert_to_8bit` path require linear (16-bit) +input. The corrected condition, i.e. + + linear != 0 && (alpha != 0 || display->convert_to_8bit != 0) + +matches the expectation of the `png_write_image_8bit` function and +prevents treating 8-bit buffers as 16-bit data. + +Reported-by: Samsung-PENTEST +Reported-by: weijinjinnihao +Analyzed-by: degrigis +Reviewed-by: John Bowler +--- + pngwrite.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/pngwrite.c b/pngwrite.c +index 35a5d17b60..83148960ef 100644 +--- a/pngwrite.c ++++ b/pngwrite.c +@@ -2173,8 +2173,7 @@ png_image_write_main(png_voidp argument) + * before it is written. This only applies when the input is 16-bit and + * either there is an alpha channel or it is converted to 8-bit. + */ +- if ((linear != 0 && alpha != 0 ) || +- (colormap == 0 && display->convert_to_8bit != 0)) ++ if (linear != 0 && (alpha != 0 || display->convert_to_8bit != 0)) + { + png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr))); diff --git a/0003-bugfix-for-CVE-2025-64720.patch b/0003-bugfix-for-CVE-2025-64720.patch new file mode 100644 index 0000000..eb709c2 --- /dev/null +++ b/0003-bugfix-for-CVE-2025-64720.patch @@ -0,0 +1,102 @@ +From 08da33b4c88cfcd36e5a706558a8d7e0e4773643 Mon Sep 17 00:00:00 2001 +From: Cosmin Truta +Date: Wed, 12 Nov 2025 13:46:23 +0200 +Subject: [PATCH] Fix a buffer overflow in `png_init_read_transformations` + +The palette compositing code in `png_init_read_transformations` was +incorrectly applying background compositing when PNG_FLAG_OPTIMIZE_ALPHA +was set. This violated the premultiplied alpha invariant +`component <= alpha` expected by `png_image_read_composite`, causing +values that exceeded the valid range for the PNG_sRGB_FROM_LINEAR lookup +tables. + +When PNG_ALPHA_OPTIMIZED is active, palette entries should contain pure +premultiplied RGB values without background compositing. The background +compositing must happen later in `png_image_read_composite` where the +actual background color from the PNG file is available. + +The fix consists in introducing conditional behavior based on +PNG_FLAG_OPTIMIZE_ALPHA: when set, the code performs only +premultiplication using the formula `component * alpha + 127) / 255` +with proper gamma correction. When not set, the original background +compositing calculation based on the `png_composite` macro is preserved. + +This prevents buffer overflows in `png_image_read_composite` where +out-of-range premultiplied values would cause out-of-bounds array access +in `png_sRGB_base[]` and `png_sRGB_delta[]`. + +Reported-by: Samsung-PENTEST +Analyzed-by: John Bowler +--- + pngrtran.c | 58 ++++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 45 insertions(+), 13 deletions(-) + +diff --git a/pngrtran.c b/pngrtran.c +index 548780030a..2f52022551 100644 +--- a/pngrtran.c ++++ b/pngrtran.c +@@ -1781,19 +1781,51 @@ png_init_read_transformations(png_structrp png_ptr) + } + else /* if (png_ptr->trans_alpha[i] != 0xff) */ + { +- png_byte v, w; +- +- v = png_ptr->gamma_to_1[palette[i].red]; +- png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); +- palette[i].red = png_ptr->gamma_from_1[w]; +- +- v = png_ptr->gamma_to_1[palette[i].green]; +- png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); +- palette[i].green = png_ptr->gamma_from_1[w]; +- +- v = png_ptr->gamma_to_1[palette[i].blue]; +- png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); +- palette[i].blue = png_ptr->gamma_from_1[w]; ++ if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0) ++ { ++ /* Premultiply only: ++ * component = round((component * alpha) / 255) ++ */ ++ png_uint_32 component; ++ ++ component = png_ptr->gamma_to_1[palette[i].red]; ++ component = ++ (component * png_ptr->trans_alpha[i] + 128) / 255; ++ palette[i].red = png_ptr->gamma_from_1[component]; ++ ++ component = png_ptr->gamma_to_1[palette[i].green]; ++ component = ++ (component * png_ptr->trans_alpha[i] + 128) / 255; ++ palette[i].green = png_ptr->gamma_from_1[component]; ++ ++ component = png_ptr->gamma_to_1[palette[i].blue]; ++ component = ++ (component * png_ptr->trans_alpha[i] + 128) / 255; ++ palette[i].blue = png_ptr->gamma_from_1[component]; ++ } ++ else ++ { ++ /* Composite with background color: ++ * component = ++ * alpha * component + (1 - alpha) * background ++ */ ++ png_byte v, w; ++ ++ v = png_ptr->gamma_to_1[palette[i].red]; ++ png_composite(w, v, ++ png_ptr->trans_alpha[i], back_1.red); ++ palette[i].red = png_ptr->gamma_from_1[w]; ++ ++ v = png_ptr->gamma_to_1[palette[i].green]; ++ png_composite(w, v, ++ png_ptr->trans_alpha[i], back_1.green); ++ palette[i].green = png_ptr->gamma_from_1[w]; ++ ++ v = png_ptr->gamma_to_1[palette[i].blue]; ++ png_composite(w, v, ++ png_ptr->trans_alpha[i], back_1.blue); ++ palette[i].blue = png_ptr->gamma_from_1[w]; ++ } + } + } + else diff --git a/0004-bugfix-for-CVE-2025-65018-1.patch b/0004-bugfix-for-CVE-2025-65018-1.patch new file mode 100644 index 0000000..ea898f9 --- /dev/null +++ b/0004-bugfix-for-CVE-2025-65018-1.patch @@ -0,0 +1,56 @@ +From 16b5e3823918840aae65c0a6da57c78a5a496a4d Mon Sep 17 00:00:00 2001 +From: Cosmin Truta +Date: Mon, 17 Nov 2025 20:38:47 +0200 +Subject: [PATCH] Fix a buffer overflow in `png_image_finish_read` +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reject bit-depth mismatches between IHDR and the requested output +format. When a 16-bit PNG is processed with an 8-bit output format +request, `png_combine_row` writes using the IHDR depth before +transformation, causing writes beyond the buffer allocated via +`PNG_IMAGE_SIZE(image)`. + +The validation establishes a safe API contract where +`PNG_IMAGE_SIZE(image)` is guaranteed to be sufficient across the +transformation pipeline. + +Example overflow (32×32 pixels, 16-bit RGB to 8-bit RGBA): +- Input format: 16 bits/channel × 3 channels = 6144 bytes +- Output buffer: 8 bits/channel × 4 channels = 4096 bytes +- Overflow: 6144 bytes - 4096 bytes = 2048 bytes + +Larger images produce proportionally larger overflows. For example, +for 256×256 pixels, the overflow is 131072 bytes. + +Reported-by: yosiimich +--- + pngread.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/pngread.c b/pngread.c +index 212afb7d21..92571ec335 100644 +--- a/pngread.c ++++ b/pngread.c +@@ -4040,6 +4040,20 @@ png_image_finish_read(png_imagep image, png_const_colorp background, + int result; + png_image_read_control display; + ++ /* Reject bit depth mismatches to avoid buffer overflows. */ ++ png_uint_32 ihdr_bit_depth = ++ image->opaque->png_ptr->bit_depth; ++ int requested_linear = ++ (image->format & PNG_FORMAT_FLAG_LINEAR) != 0; ++ if (ihdr_bit_depth == 16 && !requested_linear) ++ return png_image_error(image, ++ "png_image_finish_read: " ++ "16-bit PNG must use 16-bit output format"); ++ if (ihdr_bit_depth < 16 && requested_linear) ++ return png_image_error(image, ++ "png_image_finish_read: " ++ "8-bit PNG must not use 16-bit output format"); ++ + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; diff --git a/0004-bugfix-for-CVE-2025-65018-2.patch b/0004-bugfix-for-CVE-2025-65018-2.patch new file mode 100644 index 0000000..fad703d --- /dev/null +++ b/0004-bugfix-for-CVE-2025-65018-2.patch @@ -0,0 +1,159 @@ +From 218612ddd6b17944e21eda56caf8b4bf7779d1ea Mon Sep 17 00:00:00 2001 +From: Cosmin Truta +Date: Wed, 19 Nov 2025 21:45:13 +0200 +Subject: [PATCH] Rearchitect the fix to the buffer overflow in + `png_image_finish_read` + +Undo the fix from commit 16b5e3823918840aae65c0a6da57c78a5a496a4d. +That fix turned out to be unnecessarily limiting. It rejected all +16-to-8 bit transformations, although the vulnerability only affects +interlaced PNGs where `png_combine_row` writes using IHDR bit-depth +before the transformation completes. + +The proper solution is to add an intermediate `local_row` buffer, +specifically for the slow but necessary step of 16-to-8 bit conversion +of interlaced images. (The processing of non-interlaced images remains +intact, using the fast path.) We added the flag `do_local_scale` and +the function `png_image_read_direct_scaled`, following the pattern that +involves `do_local_compose`. + +In conclusion: +- The 16-to-8 bit transformations of interlaced images are now safe, + as they use an intermediate buffer. +- The 16-to-8 bit transformations of non-interlaced images remain safe, + as the fast path remains unchanged. +- All our regression tests are now passing. +--- + pngread.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 75 insertions(+), 14 deletions(-) + +diff --git a/pngread.c b/pngread.c +index 92571ec335..79917daaaf 100644 +--- a/pngread.c ++++ b/pngread.c +@@ -3129,6 +3129,54 @@ png_image_read_colormapped(png_voidp argument) + } + } + ++/* Row reading for interlaced 16-to-8 bit depth conversion with local buffer. */ ++static int ++png_image_read_direct_scaled(png_voidp argument) ++{ ++ png_image_read_control *display = png_voidcast(png_image_read_control*, ++ argument); ++ png_imagep image = display->image; ++ png_structrp png_ptr = image->opaque->png_ptr; ++ png_bytep local_row = png_voidcast(png_bytep, display->local_row); ++ png_bytep first_row = png_voidcast(png_bytep, display->first_row); ++ ptrdiff_t row_bytes = display->row_bytes; ++ int passes; ++ ++ /* Handle interlacing. */ ++ switch (png_ptr->interlaced) ++ { ++ case PNG_INTERLACE_NONE: ++ passes = 1; ++ break; ++ ++ case PNG_INTERLACE_ADAM7: ++ passes = PNG_INTERLACE_ADAM7_PASSES; ++ break; ++ ++ default: ++ png_error(png_ptr, "unknown interlace type"); ++ } ++ ++ /* Read each pass using local_row as intermediate buffer. */ ++ while (--passes >= 0) ++ { ++ png_uint_32 y = image->height; ++ png_bytep output_row = first_row; ++ ++ for (; y > 0; --y) ++ { ++ /* Read into local_row (gets transformed 8-bit data). */ ++ png_read_row(png_ptr, local_row, NULL); ++ ++ /* Copy from local_row to user buffer. */ ++ memcpy(output_row, local_row, (size_t)row_bytes); ++ output_row += row_bytes; ++ } ++ } ++ ++ return 1; ++} ++ + /* Just the row reading part of png_image_read. */ + static int + png_image_read_composite(png_voidp argument) +@@ -3547,6 +3595,7 @@ png_image_read_direct(png_voidp argument) + int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; + int do_local_compose = 0; + int do_local_background = 0; /* to avoid double gamma correction bug */ ++ int do_local_scale = 0; /* for interlaced 16-to-8 bit conversion */ + int passes = 0; + + /* Add transforms to ensure the correct output format is produced then check +@@ -3680,8 +3729,16 @@ png_image_read_direct(png_voidp argument) + png_set_expand_16(png_ptr); + + else /* 8-bit output */ ++ { + png_set_scale_16(png_ptr); + ++ /* For interlaced images, use local_row buffer to avoid overflow ++ * in png_combine_row() which writes using IHDR bit-depth. ++ */ ++ if (png_ptr->interlaced != 0) ++ do_local_scale = 1; ++ } ++ + change &= ~PNG_FORMAT_FLAG_LINEAR; + } + +@@ -3957,6 +4014,24 @@ png_image_read_direct(png_voidp argument) + return result; + } + ++ else if (do_local_scale != 0) ++ { ++ /* For interlaced 16-to-8 conversion, use an intermediate row buffer ++ * to avoid buffer overflows in png_combine_row. The local_row is sized ++ * for the transformed (8-bit) output, preventing the overflow that would ++ * occur if png_combine_row wrote 16-bit data directly to the user buffer. ++ */ ++ int result; ++ png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); ++ ++ display->local_row = row; ++ result = png_safe_execute(image, png_image_read_direct_scaled, display); ++ display->local_row = NULL; ++ png_free(png_ptr, row); ++ ++ return result; ++ } ++ + else + { + png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes; +@@ -4040,20 +4115,6 @@ png_image_finish_read(png_imagep image, png_const_colorp background, + int result; + png_image_read_control display; + +- /* Reject bit depth mismatches to avoid buffer overflows. */ +- png_uint_32 ihdr_bit_depth = +- image->opaque->png_ptr->bit_depth; +- int requested_linear = +- (image->format & PNG_FORMAT_FLAG_LINEAR) != 0; +- if (ihdr_bit_depth == 16 && !requested_linear) +- return png_image_error(image, +- "png_image_finish_read: " +- "16-bit PNG must use 16-bit output format"); +- if (ihdr_bit_depth < 16 && requested_linear) +- return png_image_error(image, +- "png_image_finish_read: " +- "8-bit PNG must not use 16-bit output format"); +- + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; diff --git a/libpng.spec b/libpng.spec index dffec4f..03ad980 100644 --- a/libpng.spec +++ b/libpng.spec @@ -1,4 +1,4 @@ -%define anolis_release 1 +%define anolis_release 2 %bcond_without check Summary: A library of functions for manipulating PNG image format files @@ -15,6 +15,24 @@ Source1: pngusr.dfa # https://github.com/pnggroup/libpng/commit/9e538750d99c8f1accf7e93878e4fde47c069908 # https://github.com/pnggroup/libpng/commit/e4a31f024b6158aaaf55a43502f574d5f5d1c894 Patch0: libpng-1.6.40-nomore_neon_asm.patch +# https://github.com/pnggroup/libpng/pull/748 +# https://github.com/pnggroup/libpng/commit/ea094764f3436e3c6524622724c2d342a3eff235 +Patch1: 0001-bugfix-for-CVE-2025-64505-1.patch +# https://github.com/pnggroup/libpng/commit/6a528eb5fd0dd7f6de1c39d30de0e41473431c37 +Patch2: 0001-bugfix-for-CVE-2025-64505-2.patch +# https://github.com/pnggroup/libpng/commit/83b23a888b4395c3ae0af3f6d484fce3e4a81155 +Patch3: 0001-bugfix-for-CVE-2025-64505-3.patch +# https://github.com/pnggroup/libpng/pull/749 +# https://github.com/pnggroup/libpng/commit/2bd84c019c300b78e811743fbcddb67c9d9bf821 +Patch4: 0002-bugfix-for-CVE-2025-64506.patch +# https://github.com/pnggroup/libpng/pull/751 +# https://github.com/pnggroup/libpng/commit/08da33b4c88cfcd36e5a706558a8d7e0e4773643 +Patch5: 0003-bugfix-for-CVE-2025-64720.patch +# https://github.com/pnggroup/libpng/pull/757 +# https://github.com/pnggroup/libpng/commit/16b5e3823918840aae65c0a6da57c78a5a496a4d +Patch6: 0004-bugfix-for-CVE-2025-65018-1.patch +# https://github.com/pnggroup/libpng/commit/218612ddd6b17944e21eda56caf8b4bf7779d1ea +Patch7: 0004-bugfix-for-CVE-2025-65018-2.patch BuildRequires: gcc BuildRequires: make @@ -114,6 +132,9 @@ make check %{_bindir}/pngfix %changelog +* Tue Nov 25 2025 YangCheng - 1:1.6.40-2 +- Add patch to fix CVE-2025-64505,CVE-2025-64506,CVE-2025-64720 and CVE-2025-65018 + * Tue Feb 18 2025 mgb01105731 - 1:1.6.40-1 - Update to 1.6.40 from 1.6.39 - Add patches to fixes annoncheck on aarch64 as noeon asm prevents -- Gitee