untrusted comment: verify with openbsd-78-base.pub RWS3/nvFmk4SWQCDRqPczeJHRA/22kAnvJHyDuDg9eaiSE2CayfFuuISrYKloVhkHRCa3MNh6QeXSCvwGtNjj1fhr78mCoEDJAg= OpenBSD 7.8 errata 008, December 3, 2025: Fix buffer overflow vulnerabilities in libpng which is part of libfreetype. CVE-2025-64505 CVE-2025-64506 CVE-2025-64720 CVE-2025-65018 Apply by doing: signify -Vep /etc/signify/openbsd-78-base.pub -x 008_libpng.patch.sig \ -m - | (cd /usr/xenocara && patch -p0) And then rebuild libpng and install libfreetype: cd /usr/xenocara/lib/libpng make -f Makefile.bsd-wrapper obj make -f Makefile.bsd-wrapper build cd /usr/xenocara/lib/freetype make obj make build Index: lib/libpng/pngread.c =================================================================== RCS file: /cvs/xenocara/lib/libpng/pngread.c,v diff -u -p -r1.1.1.1 pngread.c --- lib/libpng/pngread.c 17 Sep 2025 14:44:40 -0000 1.1.1.1 +++ lib/libpng/pngread.c 26 Nov 2025 22:56:34 -0000 @@ -3129,6 +3129,54 @@ png_image_read_colormapped(png_voidp arg } } +/* 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; } @@ -3951,6 +4008,24 @@ png_image_read_direct(png_voidp argument display->local_row = row; result = png_safe_execute(image, png_image_read_background, display); + display->local_row = NULL; + png_free(png_ptr, row); + + 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); Index: lib/libpng/pngrtran.c =================================================================== RCS file: /cvs/xenocara/lib/libpng/pngrtran.c,v diff -u -p -r1.1.1.1 pngrtran.c --- lib/libpng/pngrtran.c 17 Sep 2025 14:44:40 -0000 1.1.1.1 +++ lib/libpng/pngrtran.c 26 Nov 2025 22:56:35 -0000 @@ -501,9 +501,19 @@ png_set_quantize(png_structrp png_ptr, p { 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)num_palette); - 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; } @@ -1774,19 +1784,51 @@ png_init_read_transformations(png_struct } 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 Index: lib/libpng/pngwrite.c =================================================================== RCS file: /cvs/xenocara/lib/libpng/pngwrite.c,v diff -u -p -r1.1.1.1 pngwrite.c --- lib/libpng/pngwrite.c 17 Sep 2025 14:44:40 -0000 1.1.1.1 +++ lib/libpng/pngwrite.c 26 Nov 2025 22:56:35 -0000 @@ -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)));