mirror of
https://git.yoctoproject.org/poky
synced 2026-08-31 02:23:22 +00:00
libpng: Fix CVE-2026-34757
These patches apply the upstream fixes [1][2], which address getter-to-setter aliasing issues in libpng chunk setters that could cause stale-pointer reads, as described in [3]. [1] https://github.com/pnggroup/libpng/commit/398cbe3df03f4e11bb031e07f416dfdde3684e8a [2] https://github.com/pnggroup/libpng/commit/55d20aaa322c9274491cda82c5cd4f99b48c6bcc [3] https://github.com/pnggroup/libpng/issues/836 Reference: https://security-tracker.debian.org/tracker/CVE-2026-34757 https://nvd.nist.gov/vuln/detail/CVE-2026-34757 Test results on qemux86-64 using ptest-runner: START: ptest-runner 2026-06-04T11:29 BEGIN: /usr/lib/libpng/ptest PASS: tests/pnggetset Testsuite summary # TOTAL: 33 # PASS: 33 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 DURATION: 80 END: /usr/lib/libpng/ptest 2026-06-04T11:31 STOP: ptest-runner TOTAL: 1 FAIL: 0 (From OE-Core rev: 392fb4216357fd4eefb6abe3788414f2e60b0889) Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
committed by
Paul Barker
parent
75764cf5d7
commit
d0d68df4c3
@@ -0,0 +1,521 @@
|
||||
From 1fb509cdff1f9d83e2bf160259529a742de9285f Mon Sep 17 00:00:00 2001
|
||||
From: Cosmin Truta <ctruta@gmail.com>
|
||||
Date: Mon, 30 Mar 2026 17:35:30 +0300
|
||||
Subject: [PATCH] fix: Handle self-referencing pointers in getter-to-setter
|
||||
aliasing
|
||||
|
||||
Apply a robustness fix for a caller-side API usage pattern involving
|
||||
the getters and the setters for PLTE, tRNS, and hIST.
|
||||
|
||||
Passing a pointer returned by the PLTE, tRNS, or hIST getters back
|
||||
into the corresponding setters used to cause the setters to read from
|
||||
a stale pointer. The fix consists in snapshotting the caller's data
|
||||
into a stack-local buffer before freeing the old internal storage.
|
||||
|
||||
Fixes pnggroup/libpng#836
|
||||
|
||||
CVE: CVE-2026-34757
|
||||
Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/398cbe3df03f4e11bb031e07f416dfdde3684e8a]
|
||||
|
||||
Reported-by: Iv4n <Iv4n550@noreply.github.com>
|
||||
(cherry picked from commit 398cbe3df03f4e11bb031e07f416dfdde3684e8a)
|
||||
Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
|
||||
---
|
||||
CMakeLists.txt | 12 ++
|
||||
Makefile.am | 9 +-
|
||||
contrib/libtests/pnggetset.c | 328 +++++++++++++++++++++++++++++++++++
|
||||
pngset.c | 29 +++-
|
||||
tests/pnggetset | 5 +
|
||||
5 files changed, 380 insertions(+), 3 deletions(-)
|
||||
create mode 100644 contrib/libtests/pnggetset.c
|
||||
create mode 100755 tests/pnggetset
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 93a2c3434..8888d15cb 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -591,6 +591,9 @@ set(pngvalid_sources
|
||||
set(pngstest_sources
|
||||
contrib/libtests/pngstest.c
|
||||
)
|
||||
+set(pnggetset_sources
|
||||
+ contrib/libtests/pnggetset.c
|
||||
+)
|
||||
set(pngunknown_sources
|
||||
contrib/libtests/pngunknown.c
|
||||
)
|
||||
@@ -758,6 +761,15 @@ if(PNG_TESTS AND PNG_SHARED)
|
||||
COMMAND pngtest
|
||||
FILES "${PNGTEST_PNG}")
|
||||
|
||||
+ # pnggetset test:
|
||||
+ # Getter-to-setter roundtrips for various chunk types.
|
||||
+ add_executable(pnggetset ${pnggetset_sources})
|
||||
+ target_link_libraries(pnggetset
|
||||
+ PRIVATE png_shared)
|
||||
+
|
||||
+ png_add_test(NAME pnggetset
|
||||
+ COMMAND pnggetset)
|
||||
+
|
||||
add_executable(pngvalid ${pngvalid_sources})
|
||||
target_link_libraries(pngvalid PRIVATE png_shared)
|
||||
|
||||
diff --git a/Makefile.am b/Makefile.am
|
||||
index 1f06c703a..bdb40c61c 100644
|
||||
--- a/Makefile.am
|
||||
+++ b/Makefile.am
|
||||
@@ -13,7 +13,7 @@ ACLOCAL_AMFLAGS = -I scripts/autoconf
|
||||
|
||||
# test programs - run on make check, make distcheck
|
||||
if ENABLE_TESTS
|
||||
-check_PROGRAMS= pngtest pngunknown pngstest pngvalid pngimage pngcp
|
||||
+check_PROGRAMS= pngtest pnggetset pngunknown pngstest pngvalid pngimage pngcp
|
||||
if HAVE_CLOCK_GETTIME
|
||||
check_PROGRAMS += timepng
|
||||
endif
|
||||
@@ -42,6 +42,9 @@ if ENABLE_TESTS
|
||||
pngtest_SOURCES = pngtest.c
|
||||
pngtest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
|
||||
|
||||
+pnggetset_SOURCES = contrib/libtests/pnggetset.c
|
||||
+pnggetset_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
|
||||
+
|
||||
pngvalid_SOURCES = contrib/libtests/pngvalid.c
|
||||
pngvalid_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
|
||||
|
||||
@@ -75,6 +78,7 @@ TESTS =\
|
||||
tests/pngtest-all\
|
||||
tests/pngvalid-gamma-16-to-8 tests/pngvalid-gamma-alpha-mode\
|
||||
tests/pngvalid-gamma-background tests/pngvalid-gamma-expand16-alpha-mode\
|
||||
+ tests/pnggetset\
|
||||
tests/pngvalid-gamma-expand16-background\
|
||||
tests/pngvalid-gamma-expand16-transform tests/pngvalid-gamma-sbit\
|
||||
tests/pngvalid-gamma-threshold tests/pngvalid-gamma-transform\
|
||||
@@ -273,9 +277,10 @@ $(srcdir)/scripts/pnglibconf.h.prebuilt:
|
||||
pngtest.o: pnglibconf.h
|
||||
|
||||
contrib/libtests/makepng.o: pnglibconf.h
|
||||
+contrib/libtests/pnggetset.o: pnglibconf.h
|
||||
+contrib/libtests/pngimage.o: pnglibconf.h
|
||||
contrib/libtests/pngstest.o: pnglibconf.h
|
||||
contrib/libtests/pngunknown.o: pnglibconf.h
|
||||
-contrib/libtests/pngimage.o: pnglibconf.h
|
||||
contrib/libtests/pngvalid.o: pnglibconf.h
|
||||
contrib/libtests/readpng.o: pnglibconf.h
|
||||
contrib/libtests/tarith.o: pnglibconf.h
|
||||
diff --git a/contrib/libtests/pnggetset.c b/contrib/libtests/pnggetset.c
|
||||
new file mode 100644
|
||||
index 000000000..b42508094
|
||||
--- /dev/null
|
||||
+++ b/contrib/libtests/pnggetset.c
|
||||
@@ -0,0 +1,328 @@
|
||||
+/* pnggetset.c
|
||||
+ *
|
||||
+ * Copyright (c) 2026 Cosmin Truta
|
||||
+ *
|
||||
+ * This code is released under the libpng license.
|
||||
+ * For conditions of distribution and use, see the disclaimer
|
||||
+ * and license in png.h
|
||||
+ *
|
||||
+ * Test the get-then-set roundtrip pattern for PLTE, tRNS, and hIST.
|
||||
+ *
|
||||
+ * Passing the internal pointer returned by a getter back into the
|
||||
+ * corresponding setter is a natural API usage pattern. A previous
|
||||
+ * version had a use-after-free on this path because the setter freed
|
||||
+ * the internal buffer before copying from the caller-supplied pointer.
|
||||
+ */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
|
||||
+# include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#ifdef PNG_FREESTANDING_TESTS
|
||||
+# include <png.h>
|
||||
+#else
|
||||
+# include "../../png.h"
|
||||
+#endif
|
||||
+
|
||||
+/* Test: get the PLTE, pass it straight back to set, verify roundtrip. */
|
||||
+static int
|
||||
+test_plte_roundtrip(void)
|
||||
+{
|
||||
+ png_structp png_ptr;
|
||||
+ png_infop info_ptr;
|
||||
+ png_color palette[4];
|
||||
+ png_colorp got_palette = NULL;
|
||||
+ int num_palette = 0;
|
||||
+ int i;
|
||||
+
|
||||
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
+ NULL, NULL, NULL);
|
||||
+ if (png_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ info_ptr = png_create_info_struct(png_ptr);
|
||||
+ if (info_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
|
||||
+ png_destroy_write_struct(&png_ptr, NULL);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (setjmp(png_jmpbuf(png_ptr)))
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: libpng error in test_plte_roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Set up a palette-color image header. */
|
||||
+ png_set_IHDR(png_ptr, info_ptr, 1, 1, 8, PNG_COLOR_TYPE_PALETTE,
|
||||
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
+
|
||||
+ /* Populate with recognizable values. */
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ {
|
||||
+ palette[i].red = (png_byte)(i * 10);
|
||||
+ palette[i].green = (png_byte)(i * 20);
|
||||
+ palette[i].blue = (png_byte)(i * 30);
|
||||
+ }
|
||||
+ png_set_PLTE(png_ptr, info_ptr, palette, 4);
|
||||
+
|
||||
+ /* Get the internal pointer and feed it straight back. */
|
||||
+ png_get_PLTE(png_ptr, info_ptr, &got_palette, &num_palette);
|
||||
+ if (got_palette == NULL || num_palette != 4)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_get_PLTE returned unexpected values\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* This is the critical call: the pointer aliases info_ptr->palette. */
|
||||
+ png_set_PLTE(png_ptr, info_ptr, got_palette, num_palette);
|
||||
+
|
||||
+ /* Verify the data survived the roundtrip. */
|
||||
+ got_palette = NULL;
|
||||
+ num_palette = 0;
|
||||
+ png_get_PLTE(png_ptr, info_ptr, &got_palette, &num_palette);
|
||||
+ if (got_palette == NULL || num_palette != 4)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: PLTE lost after roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ {
|
||||
+ if (got_palette[i].red != (png_byte)(i * 10) ||
|
||||
+ got_palette[i].green != (png_byte)(i * 20) ||
|
||||
+ got_palette[i].blue != (png_byte)(i * 30))
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: PLTE entry %d corrupted after roundtrip\n", i);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#ifdef PNG_hIST_SUPPORTED
|
||||
+/* Test: get the hIST, pass it straight back to set, verify roundtrip. */
|
||||
+static int
|
||||
+test_hist_roundtrip(void)
|
||||
+{
|
||||
+ png_structp png_ptr;
|
||||
+ png_infop info_ptr;
|
||||
+ png_color palette[4];
|
||||
+ png_uint_16 hist[4];
|
||||
+ png_uint_16p got_hist = NULL;
|
||||
+ int i;
|
||||
+
|
||||
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
+ NULL, NULL, NULL);
|
||||
+ if (png_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ info_ptr = png_create_info_struct(png_ptr);
|
||||
+ if (info_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
|
||||
+ png_destroy_write_struct(&png_ptr, NULL);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (setjmp(png_jmpbuf(png_ptr)))
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: libpng error in test_hist_roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Set up a palette-color image header. */
|
||||
+ memset(palette, 0, sizeof palette);
|
||||
+ png_set_IHDR(png_ptr, info_ptr, 1, 1, 8, PNG_COLOR_TYPE_PALETTE,
|
||||
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
+ png_set_PLTE(png_ptr, info_ptr, palette, 4);
|
||||
+
|
||||
+ /* Populate with recognizable values. */
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ hist[i] = (png_uint_16)(i * 100 + 42);
|
||||
+
|
||||
+ png_set_hIST(png_ptr, info_ptr, hist);
|
||||
+
|
||||
+ /* Get the internal pointer and feed it straight back. */
|
||||
+ if (png_get_hIST(png_ptr, info_ptr, &got_hist) == 0 || got_hist == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_get_hIST returned unexpected values\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* This is the critical call: the pointer aliases info_ptr->hist. */
|
||||
+ png_set_hIST(png_ptr, info_ptr, got_hist);
|
||||
+
|
||||
+ /* Verify the data survived the roundtrip. */
|
||||
+ got_hist = NULL;
|
||||
+ if (png_get_hIST(png_ptr, info_ptr, &got_hist) == 0 || got_hist == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: hIST lost after roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ {
|
||||
+ if (got_hist[i] != (png_uint_16)(i * 100 + 42))
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: hIST entry %d corrupted after roundtrip\n", i);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* PNG_hIST_SUPPORTED */
|
||||
+
|
||||
+#ifdef PNG_tRNS_SUPPORTED
|
||||
+/* Test: get the tRNS, pass it straight back to set, verify roundtrip. */
|
||||
+static int
|
||||
+test_trns_roundtrip(void)
|
||||
+{
|
||||
+ png_structp png_ptr;
|
||||
+ png_infop info_ptr;
|
||||
+ png_color palette[4];
|
||||
+ png_byte trans_alpha[4];
|
||||
+ png_color_16 trans_color;
|
||||
+ png_bytep got_alpha = NULL;
|
||||
+ png_color_16p got_color = NULL;
|
||||
+ int num_trans = 0;
|
||||
+ int i;
|
||||
+
|
||||
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
+ NULL, NULL, NULL);
|
||||
+ if (png_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ info_ptr = png_create_info_struct(png_ptr);
|
||||
+ if (info_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
|
||||
+ png_destroy_write_struct(&png_ptr, NULL);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (setjmp(png_jmpbuf(png_ptr)))
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: libpng error in test_trns_roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Set up a palette-color image. */
|
||||
+ memset(palette, 0, sizeof palette);
|
||||
+ png_set_IHDR(png_ptr, info_ptr, 1, 1, 8, PNG_COLOR_TYPE_PALETTE,
|
||||
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
+ png_set_PLTE(png_ptr, info_ptr, palette, 4);
|
||||
+
|
||||
+ /* Populate tRNS with recognizable values. */
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ trans_alpha[i] = (png_byte)(0xff - i * 0x11);
|
||||
+ memset(&trans_color, 0, sizeof trans_color);
|
||||
+
|
||||
+ png_set_tRNS(png_ptr, info_ptr, trans_alpha, 4, &trans_color);
|
||||
+
|
||||
+ /* Get the internal pointer and feed it straight back. */
|
||||
+ png_get_tRNS(png_ptr, info_ptr, &got_alpha, &num_trans, &got_color);
|
||||
+ if (got_alpha == NULL || num_trans != 4)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_get_tRNS returned unexpected values\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* This is the critical call: the pointer aliases info_ptr->trans_alpha. */
|
||||
+ png_set_tRNS(png_ptr, info_ptr, got_alpha, num_trans, got_color);
|
||||
+
|
||||
+ /* Verify the data survived the roundtrip. */
|
||||
+ got_alpha = NULL;
|
||||
+ num_trans = 0;
|
||||
+ png_get_tRNS(png_ptr, info_ptr, &got_alpha, &num_trans, &got_color);
|
||||
+ if (got_alpha == NULL || num_trans != 4)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: tRNS lost after roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ {
|
||||
+ if (got_alpha[i] != (png_byte)(0xff - i * 0x11))
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: tRNS entry %d corrupted after roundtrip\n", i);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* PNG_tRNS_SUPPORTED */
|
||||
+
|
||||
+int
|
||||
+main(void)
|
||||
+{
|
||||
+ int result = 0;
|
||||
+
|
||||
+ printf("Testing PLTE get-then-set roundtrip... ");
|
||||
+ fflush(stdout);
|
||||
+ if (test_plte_roundtrip() != 0)
|
||||
+ {
|
||||
+ printf("FAIL\n");
|
||||
+ result = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ printf("PASS\n");
|
||||
+
|
||||
+#ifdef PNG_hIST_SUPPORTED
|
||||
+ printf("Testing hIST get-then-set roundtrip... ");
|
||||
+ fflush(stdout);
|
||||
+ if (test_hist_roundtrip() != 0)
|
||||
+ {
|
||||
+ printf("FAIL\n");
|
||||
+ result = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ printf("PASS\n");
|
||||
+#endif
|
||||
+
|
||||
+#ifdef PNG_tRNS_SUPPORTED
|
||||
+ printf("Testing tRNS get-then-set roundtrip... ");
|
||||
+ fflush(stdout);
|
||||
+ if (test_trns_roundtrip() != 0)
|
||||
+ {
|
||||
+ printf("FAIL\n");
|
||||
+ result = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ printf("PASS\n");
|
||||
+#endif
|
||||
+
|
||||
+ return result;
|
||||
+}
|
||||
diff --git a/pngset.c b/pngset.c
|
||||
index c4a0958aa..9f5c44510 100644
|
||||
--- a/pngset.c
|
||||
+++ b/pngset.c
|
||||
@@ -204,6 +204,7 @@ void PNGAPI
|
||||
png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
png_const_uint_16p hist)
|
||||
{
|
||||
+ png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH];
|
||||
int i;
|
||||
|
||||
png_debug1(1, "in %s storage function", "hIST");
|
||||
@@ -220,6 +221,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
return;
|
||||
}
|
||||
|
||||
+ /* Snapshot the caller's hist before freeing, in case it points to
|
||||
+ * info_ptr->hist (getter-to-setter aliasing).
|
||||
+ */
|
||||
+ memcpy(safe_hist, hist, (unsigned int)info_ptr->num_palette *
|
||||
+ (sizeof (png_uint_16)));
|
||||
+ hist = safe_hist;
|
||||
+
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
|
||||
|
||||
/* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
|
||||
@@ -561,7 +569,7 @@ void PNGAPI
|
||||
png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
|
||||
png_const_colorp palette, int num_palette)
|
||||
{
|
||||
-
|
||||
+ png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
|
||||
png_uint_32 max_palette_length;
|
||||
|
||||
png_debug1(1, "in %s storage function", "PLTE");
|
||||
@@ -595,6 +603,15 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
|
||||
png_error(png_ptr, "Invalid palette");
|
||||
}
|
||||
|
||||
+ /* Snapshot the caller's palette before freeing, in case it points to
|
||||
+ * info_ptr->palette (getter-to-setter aliasing).
|
||||
+ */
|
||||
+ if (num_palette > 0)
|
||||
+ memcpy(safe_palette, palette, (unsigned int)num_palette *
|
||||
+ (sizeof (png_color)));
|
||||
+
|
||||
+ palette = safe_palette;
|
||||
+
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
|
||||
|
||||
/* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
|
||||
@@ -1000,6 +1017,16 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
|
||||
|
||||
if (trans_alpha != NULL)
|
||||
{
|
||||
+ /* Snapshot the caller's trans_alpha before freeing, in case it
|
||||
+ * points to info_ptr->trans_alpha (getter-to-setter aliasing).
|
||||
+ */
|
||||
+ png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
|
||||
+
|
||||
+ if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
|
||||
+ memcpy(safe_trans, trans_alpha, (size_t)num_trans);
|
||||
+
|
||||
+ trans_alpha = safe_trans;
|
||||
+
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
|
||||
|
||||
if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
|
||||
diff --git a/tests/pnggetset b/tests/pnggetset
|
||||
new file mode 100755
|
||||
index 000000000..57ef731a5
|
||||
--- /dev/null
|
||||
+++ b/tests/pnggetset
|
||||
@@ -0,0 +1,5 @@
|
||||
+#!/bin/sh
|
||||
+
|
||||
+# pnggetset test:
|
||||
+# Getter-to-setter roundtrips for various chunk types.
|
||||
+exec ./pnggetset
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
From 2d1c6585d356832bb679ad4d313f5ea542e02064 Mon Sep 17 00:00:00 2001
|
||||
From: Cosmin Truta <ctruta@gmail.com>
|
||||
Date: Mon, 30 Mar 2026 17:43:05 +0300
|
||||
Subject: [PATCH] fix: Handle getter-to-setter aliasing in append-style
|
||||
chunk setters
|
||||
|
||||
Apply the same class of robustness fix from the previous commit to
|
||||
`png_set_text`, `png_set_sPLT` and `png_set_unknown_chunks`. These
|
||||
append-style setters used `png_realloc_array` to grow the internal
|
||||
array, then freed the old array before copying from the caller's
|
||||
input. If the caller's pointer was obtained from the corresponding
|
||||
getter, it aliased the freed array.
|
||||
|
||||
The fix defers the freeing of the old array until after the copy loop.
|
||||
|
||||
Also extend the pnggetset regression test to cover all three setters.
|
||||
|
||||
CVE: CVE-2026-34757
|
||||
Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/55d20aaa322c9274491cda82c5cd4f99b48c6bcc]
|
||||
|
||||
(cherry picked from commit 55d20aaa322c9274491cda82c5cd4f99b48c6bcc)
|
||||
Signed-off-by: Sudhir Dumbhare <sudumbha@cisco.com>
|
||||
---
|
||||
contrib/libtests/pnggetset.c | 330 ++++++++++++++++++++++++++++++++++-
|
||||
pngset.c | 25 ++-
|
||||
2 files changed, 347 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/contrib/libtests/pnggetset.c b/contrib/libtests/pnggetset.c
|
||||
index b42508094..6ae43dc66 100644
|
||||
--- a/contrib/libtests/pnggetset.c
|
||||
+++ b/contrib/libtests/pnggetset.c
|
||||
@@ -6,12 +6,12 @@
|
||||
* For conditions of distribution and use, see the disclaimer
|
||||
* and license in png.h
|
||||
*
|
||||
- * Test the get-then-set roundtrip pattern for PLTE, tRNS, and hIST.
|
||||
+ * Test the get-then-set roundtrip for chunk types whose getters return
|
||||
+ * a pointer to internal storage.
|
||||
*
|
||||
- * Passing the internal pointer returned by a getter back into the
|
||||
- * corresponding setter is a natural API usage pattern. A previous
|
||||
- * version had a use-after-free on this path because the setter freed
|
||||
- * the internal buffer before copying from the caller-supplied pointer.
|
||||
+ * Passing such a pointer back into the corresponding setter must not
|
||||
+ * cause a use-after-free. A previous version freed the internal buffer
|
||||
+ * before copying from the caller-supplied pointer.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -285,6 +285,290 @@ test_trns_roundtrip(void)
|
||||
}
|
||||
#endif /* PNG_tRNS_SUPPORTED */
|
||||
|
||||
+#ifdef PNG_TEXT_SUPPORTED
|
||||
+/* Test: get the text array, pass it straight back to set, verify data. */
|
||||
+#define TEXT_COUNT 6 /* enough to trigger reallocation on the second set */
|
||||
+static int
|
||||
+test_text_roundtrip(void)
|
||||
+{
|
||||
+ png_structp png_ptr;
|
||||
+ png_infop info_ptr;
|
||||
+ png_text text_entries[TEXT_COUNT];
|
||||
+ png_textp got_text = NULL;
|
||||
+ int got_num_text = 0;
|
||||
+ int i;
|
||||
+
|
||||
+ /* Recognizable keys and values. */
|
||||
+ static const char *keys[TEXT_COUNT] = {
|
||||
+ "Title", "Author", "Desc", "Copyright", "Source", "Comment"
|
||||
+ };
|
||||
+ static const char *vals[TEXT_COUNT] = {
|
||||
+ "t0", "t1", "t2", "t3", "t4", "t5"
|
||||
+ };
|
||||
+
|
||||
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
+ NULL, NULL, NULL);
|
||||
+ if (png_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ info_ptr = png_create_info_struct(png_ptr);
|
||||
+ if (info_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
|
||||
+ png_destroy_write_struct(&png_ptr, NULL);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (setjmp(png_jmpbuf(png_ptr)))
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: libpng error in test_text_roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Populate the text entries. */
|
||||
+ memset(text_entries, 0, sizeof text_entries);
|
||||
+ for (i = 0; i < TEXT_COUNT; i++)
|
||||
+ {
|
||||
+ text_entries[i].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
+ text_entries[i].key = (png_charp)keys[i];
|
||||
+ text_entries[i].text = (png_charp)vals[i];
|
||||
+ }
|
||||
+ png_set_text(png_ptr, info_ptr, text_entries, TEXT_COUNT);
|
||||
+
|
||||
+ /* Get the internal pointer and feed it straight back (append). */
|
||||
+ png_get_text(png_ptr, info_ptr, &got_text, &got_num_text);
|
||||
+ if (got_text == NULL || got_num_text != TEXT_COUNT)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_get_text returned unexpected values\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* This is the critical call: got_text aliases info_ptr->text. */
|
||||
+ png_set_text(png_ptr, info_ptr, got_text, got_num_text);
|
||||
+
|
||||
+ /* Verify the original entries survived. */
|
||||
+ got_text = NULL;
|
||||
+ got_num_text = 0;
|
||||
+ png_get_text(png_ptr, info_ptr, &got_text, &got_num_text);
|
||||
+ if (got_text == NULL || got_num_text != TEXT_COUNT * 2)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: text count %d, expected %d after roundtrip\n",
|
||||
+ got_num_text, TEXT_COUNT * 2);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ for (i = 0; i < TEXT_COUNT; i++)
|
||||
+ {
|
||||
+ if (got_text[i].key == NULL ||
|
||||
+ strcmp(got_text[i].key, keys[i]) != 0 ||
|
||||
+ got_text[i].text == NULL ||
|
||||
+ strcmp(got_text[i].text, vals[i]) != 0)
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: text entry %d corrupted after roundtrip\n", i);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 0;
|
||||
+}
|
||||
+#undef TEXT_COUNT
|
||||
+#endif /* PNG_TEXT_SUPPORTED */
|
||||
+
|
||||
+#ifdef PNG_sPLT_SUPPORTED
|
||||
+/* Test: get the sPLT array, pass it straight back to set, verify data. */
|
||||
+static int
|
||||
+test_splt_roundtrip(void)
|
||||
+{
|
||||
+ png_structp png_ptr;
|
||||
+ png_infop info_ptr;
|
||||
+ png_sPLT_t splt;
|
||||
+ png_sPLT_entry splt_entries[4];
|
||||
+ png_sPLT_tp got_spalettes = NULL;
|
||||
+ int got_num, i;
|
||||
+
|
||||
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
+ NULL, NULL, NULL);
|
||||
+ if (png_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ info_ptr = png_create_info_struct(png_ptr);
|
||||
+ if (info_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
|
||||
+ png_destroy_write_struct(&png_ptr, NULL);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (setjmp(png_jmpbuf(png_ptr)))
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: libpng error in test_splt_roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Populate with recognizable values. */
|
||||
+ memset(splt_entries, 0, sizeof splt_entries);
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ {
|
||||
+ splt_entries[i].red = (png_uint_16)(i * 1000);
|
||||
+ splt_entries[i].green = (png_uint_16)(i * 2000);
|
||||
+ splt_entries[i].blue = (png_uint_16)(i * 3000);
|
||||
+ splt_entries[i].alpha = 0xffffU;
|
||||
+ splt_entries[i].frequency = (png_uint_16)(i + 1);
|
||||
+ }
|
||||
+ memset(&splt, 0, sizeof splt);
|
||||
+ splt.name = (png_charp)"test_sPLT";
|
||||
+ splt.depth = 16;
|
||||
+ splt.entries = splt_entries;
|
||||
+ splt.nentries = 4;
|
||||
+
|
||||
+ png_set_sPLT(png_ptr, info_ptr, &splt, 1);
|
||||
+
|
||||
+ /* Get the internal pointer and feed it straight back (append). */
|
||||
+ got_num = png_get_sPLT(png_ptr, info_ptr, &got_spalettes);
|
||||
+ if (got_spalettes == NULL || got_num != 1)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_get_sPLT returned unexpected values\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* This is the critical call: got_spalettes aliases internal storage. */
|
||||
+ png_set_sPLT(png_ptr, info_ptr, got_spalettes, got_num);
|
||||
+
|
||||
+ /* Verify the original entry survived. */
|
||||
+ got_spalettes = NULL;
|
||||
+ got_num = png_get_sPLT(png_ptr, info_ptr, &got_spalettes);
|
||||
+ if (got_spalettes == NULL || got_num != 2)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: sPLT count %d, expected 2 after roundtrip\n",
|
||||
+ got_num);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ if (strcmp(got_spalettes[0].name, "test_sPLT") != 0 ||
|
||||
+ got_spalettes[0].nentries != 4 ||
|
||||
+ got_spalettes[0].depth != 16)
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: sPLT entry 0 corrupted after roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ for (i = 0; i < 4; i++)
|
||||
+ {
|
||||
+ if (got_spalettes[0].entries[i].red != (png_uint_16)(i * 1000) ||
|
||||
+ got_spalettes[0].entries[i].green != (png_uint_16)(i * 2000) ||
|
||||
+ got_spalettes[0].entries[i].blue != (png_uint_16)(i * 3000))
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: sPLT[0] entry %d corrupted after roundtrip\n", i);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* PNG_sPLT_SUPPORTED */
|
||||
+
|
||||
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
+/* Test: get unknown chunks, pass them straight back to set, verify data. */
|
||||
+static int
|
||||
+test_unknown_roundtrip(void)
|
||||
+{
|
||||
+ png_structp png_ptr;
|
||||
+ png_infop info_ptr;
|
||||
+ png_unknown_chunk unk;
|
||||
+ png_unknown_chunkp got_unknowns = NULL;
|
||||
+ int got_num;
|
||||
+ static const png_byte test_data[] = {0xde, 0xad, 0xbe, 0xef};
|
||||
+
|
||||
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
+ NULL, NULL, NULL);
|
||||
+ if (png_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ info_ptr = png_create_info_struct(png_ptr);
|
||||
+ if (info_ptr == NULL)
|
||||
+ {
|
||||
+ fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
|
||||
+ png_destroy_write_struct(&png_ptr, NULL);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (setjmp(png_jmpbuf(png_ptr)))
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: libpng error in test_unknown_roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Set up an unknown chunk with recognizable data. */
|
||||
+ memset(&unk, 0, sizeof unk);
|
||||
+ memcpy(unk.name, "teSt", 5);
|
||||
+ unk.data = (png_bytep)test_data;
|
||||
+ unk.size = sizeof test_data;
|
||||
+ unk.location = PNG_HAVE_IHDR;
|
||||
+
|
||||
+ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);
|
||||
+ png_set_unknown_chunks(png_ptr, info_ptr, &unk, 1);
|
||||
+
|
||||
+ /* Get the internal pointer and feed it straight back (append). */
|
||||
+ got_num = png_get_unknown_chunks(png_ptr, info_ptr, &got_unknowns);
|
||||
+ if (got_unknowns == NULL || got_num != 1)
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: png_get_unknown_chunks returned unexpected values\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* This is the critical call: got_unknowns aliases internal storage. */
|
||||
+ png_set_unknown_chunks(png_ptr, info_ptr, got_unknowns, got_num);
|
||||
+
|
||||
+ /* Verify the original entry survived. */
|
||||
+ got_unknowns = NULL;
|
||||
+ got_num = png_get_unknown_chunks(png_ptr, info_ptr, &got_unknowns);
|
||||
+ if (got_unknowns == NULL || got_num != 2)
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: unknown_chunks count %d, expected 2 after roundtrip\n",
|
||||
+ got_num);
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ if (memcmp(got_unknowns[0].name, "teSt", 4) != 0 ||
|
||||
+ got_unknowns[0].size != sizeof test_data ||
|
||||
+ memcmp(got_unknowns[0].data, test_data, sizeof test_data) != 0)
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ "pnggetset: unknown chunk 0 corrupted after roundtrip\n");
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED */
|
||||
+
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
@@ -324,5 +608,41 @@ main(void)
|
||||
printf("PASS\n");
|
||||
#endif
|
||||
|
||||
+#ifdef PNG_TEXT_SUPPORTED
|
||||
+ printf("Testing tEXt get-then-set roundtrip... ");
|
||||
+ fflush(stdout);
|
||||
+ if (test_text_roundtrip() != 0)
|
||||
+ {
|
||||
+ printf("FAIL\n");
|
||||
+ result = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ printf("PASS\n");
|
||||
+#endif
|
||||
+
|
||||
+#ifdef PNG_sPLT_SUPPORTED
|
||||
+ printf("Testing sPLT get-then-set roundtrip... ");
|
||||
+ fflush(stdout);
|
||||
+ if (test_splt_roundtrip() != 0)
|
||||
+ {
|
||||
+ printf("FAIL\n");
|
||||
+ result = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ printf("PASS\n");
|
||||
+#endif
|
||||
+
|
||||
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
+ printf("Testing unknown chunks get-then-set roundtrip... ");
|
||||
+ fflush(stdout);
|
||||
+ if (test_unknown_roundtrip() != 0)
|
||||
+ {
|
||||
+ printf("FAIL\n");
|
||||
+ result = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ printf("PASS\n");
|
||||
+#endif
|
||||
+
|
||||
return result;
|
||||
}
|
||||
diff --git a/pngset.c b/pngset.c
|
||||
index 9f5c44510..9ffaf2b5a 100644
|
||||
--- a/pngset.c
|
||||
+++ b/pngset.c
|
||||
@@ -789,6 +789,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
png_const_textp text_ptr, int num_text)
|
||||
{
|
||||
int i;
|
||||
+ png_textp old_text = NULL;
|
||||
|
||||
png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
|
||||
png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
|
||||
@@ -836,7 +837,10 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
- png_free(png_ptr, info_ptr->text);
|
||||
+ /* Defer freeing the old array until after the copy loop below,
|
||||
+ * in case text_ptr aliases info_ptr->text (getter-to-setter).
|
||||
+ */
|
||||
+ old_text = info_ptr->text;
|
||||
|
||||
info_ptr->text = new_text;
|
||||
info_ptr->free_me |= PNG_FREE_TEXT;
|
||||
@@ -921,6 +925,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
{
|
||||
png_chunk_report(png_ptr, "text chunk: out of memory",
|
||||
PNG_CHUNK_WRITE_ERROR);
|
||||
+ png_free(png_ptr, old_text);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -974,6 +979,8 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
|
||||
png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
|
||||
}
|
||||
|
||||
+ png_free(png_ptr, old_text);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1112,6 +1119,7 @@ png_set_sPLT(png_const_structrp png_ptr,
|
||||
*/
|
||||
{
|
||||
png_sPLT_tp np;
|
||||
+ png_sPLT_tp old_spalettes;
|
||||
|
||||
png_debug1(1, "in %s storage function", "sPLT");
|
||||
|
||||
@@ -1132,7 +1140,10 @@ png_set_sPLT(png_const_structrp png_ptr,
|
||||
return;
|
||||
}
|
||||
|
||||
- png_free(png_ptr, info_ptr->splt_palettes);
|
||||
+ /* Defer freeing the old array until after the copy loop below,
|
||||
+ * in case entries aliases info_ptr->splt_palettes (getter-to-setter).
|
||||
+ */
|
||||
+ old_spalettes = info_ptr->splt_palettes;
|
||||
|
||||
info_ptr->splt_palettes = np;
|
||||
info_ptr->free_me |= PNG_FREE_SPLT;
|
||||
@@ -1196,6 +1207,8 @@ png_set_sPLT(png_const_structrp png_ptr,
|
||||
}
|
||||
while (--nentries);
|
||||
|
||||
+ png_free(png_ptr, old_spalettes);
|
||||
+
|
||||
if (nentries > 0)
|
||||
png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
|
||||
}
|
||||
@@ -1244,6 +1257,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
|
||||
png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
|
||||
{
|
||||
png_unknown_chunkp np;
|
||||
+ png_unknown_chunkp old_unknowns;
|
||||
|
||||
if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
|
||||
unknowns == NULL)
|
||||
@@ -1290,7 +1304,10 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
|
||||
return;
|
||||
}
|
||||
|
||||
- png_free(png_ptr, info_ptr->unknown_chunks);
|
||||
+ /* Defer freeing the old array until after the copy loop below,
|
||||
+ * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter).
|
||||
+ */
|
||||
+ old_unknowns = info_ptr->unknown_chunks;
|
||||
|
||||
info_ptr->unknown_chunks = np; /* safe because it is initialized */
|
||||
info_ptr->free_me |= PNG_FREE_UNKN;
|
||||
@@ -1336,6 +1353,8 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
|
||||
++np;
|
||||
++(info_ptr->unknown_chunks_num);
|
||||
}
|
||||
+
|
||||
+ png_free(png_ptr, old_unknowns);
|
||||
}
|
||||
|
||||
void PNGAPI
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@@ -29,6 +29,8 @@ SRC_URI = "${SOURCEFORGE_MIRROR}/project/${BPN}/${BPN}${LIBV}/${PV}/${BP}.tar.xz
|
||||
file://CVE-2026-33416-02.patch \
|
||||
file://CVE-2026-33416-03.patch \
|
||||
file://CVE-2026-33416-04.patch \
|
||||
file://CVE-2026-34757_p1.patch \
|
||||
file://CVE-2026-34757_p2.patch \
|
||||
"
|
||||
|
||||
SRC_URI[sha256sum] = "c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450"
|
||||
@@ -66,7 +68,7 @@ do_install_ptest() {
|
||||
install -m 644 ${S}/contrib/tools/*.c ${S}/contrib/tools/*.h ${D}${PTEST_PATH}/src/contrib/tools
|
||||
|
||||
# Install .libs directory binaries to ptest path
|
||||
install -m 755 ${B}/.libs/pngtest ${B}/.libs/pngstest ${B}/.libs/pngimage ${B}/.libs/pngunknown ${B}/.libs/pngvalid ${D}${PTEST_PATH}/src
|
||||
install -m 755 ${B}/.libs/pngtest ${B}/.libs/pnggetset ${B}/.libs/pngstest ${B}/.libs/pngimage ${B}/.libs/pngunknown ${B}/.libs/pngvalid ${D}${PTEST_PATH}/src
|
||||
|
||||
# Copy png files to ptest path
|
||||
cd ${S} && find contrib -name '*.png' | cpio -pd ${D}${PTEST_PATH}/src
|
||||
|
||||
Reference in New Issue
Block a user