From 7c007374e35030b58e47238ee185e34bd4672844 Mon Sep 17 00:00:00 2001 From: lichenggang Date: Thu, 21 May 2026 21:51:06 +0800 Subject: [PATCH] fix(libsixel): fix CVE-2026 security vulnerabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport six CVE-2026 fixes from upstream saitoha/libsixel: - CVE-2026-33023: Integer overflow in DCS parameter scaling - CVE-2026-33020: Parser cursor overflow in SIXEL decoder - CVE-2026-33018: Null pointer dereference in palette allocation - CVE-2026-33021: Integer overflow in highcolor encoder - CVE-2026-44636: Integer overflows in encoder and quantizer - CVE-2026-44637: Bad-free in libpng and improper frame lifecycle Log: Fix six CVE-2026 vulnerabilities in libsixel Influence: 1. Test libsixel decoding with crafted SIXEL/PNG/GIF input 2. Verify no segmentation faults with malformed images 3. Check palette allocation null pointer handling 4. Validate DCS parameter scaling integer overflow prevention 5. Verify encoder delay calculation with large values fix(libsixel): 修复 CVE-2026 安全漏洞 从上游 saitoha/libsixel 回溯六个 CVE-2026 修复: - CVE-2026-33023: DCS 参数缩放整数溢出 - CVE-2026-33020: SIXEL 解码器光标溢出 - CVE-2026-33018: 调色板空指针解引用 - CVE-2026-33021: 高彩色编码器整数溢出 - CVE-2026-44636: 编码器和量化器整数溢出 - CVE-2026-44637: libpng 错误释放和帧生命周期问题 Log: 修复 libsixel 六个 CVE-2026 安全漏洞 Influence: 1. 测试使用恶意构造的 SIXEL/PNG/GIF 输入解码 2. 验证畸形图像不会导致段错误 3. 检查调色板分配空指针处理 4. 验证 DCS 参数缩放整数溢出防护 5. 验证编码器大值延时计算 repo: libsixel #master --- debian/changelog | 12 ++ debian/patches/CVE-2026-33018.patch | 24 ++++ debian/patches/CVE-2026-33020.patch | 87 ++++++++++++ debian/patches/CVE-2026-33021.patch | 79 +++++++++++ debian/patches/CVE-2026-33023.patch | 63 +++++++++ debian/patches/CVE-2026-44636.patch | 199 ++++++++++++++++++++++++++++ debian/patches/CVE-2026-44637.patch | 136 +++++++++++++++++++ debian/patches/series | 6 + 8 files changed, 606 insertions(+) create mode 100644 debian/patches/CVE-2026-33018.patch create mode 100644 debian/patches/CVE-2026-33020.patch create mode 100644 debian/patches/CVE-2026-33021.patch create mode 100644 debian/patches/CVE-2026-33023.patch create mode 100644 debian/patches/CVE-2026-44636.patch create mode 100644 debian/patches/CVE-2026-44637.patch diff --git a/debian/changelog b/debian/changelog index 338bc64..3fb8585 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +libsixel (1.10.5-1deepin3) unstable; urgency=medium + + * Backport CVE-2026 security fixes from upstream saitoha/libsixel + - CVE-2026-33023: Integer overflow in DCS parameter scaling + - CVE-2026-33020: Parser cursor overflow in SIXEL decoder + - CVE-2026-33018: Null pointer dereference in palette allocation + - CVE-2026-33021: Integer overflow in highcolor encoder + - CVE-2026-44636: Integer overflows in encoder and quantizer + - CVE-2026-44637: Bad-free in libpng and improper frame lifecycle + + -- lichenggang Thu, 21 May 2026 21:50:00 +0800 + libsixel (1.10.5-1deepin2) unstable; urgency=medium * Fix CVE-2025-9300: heap buffer overflow in encoder.c diff --git a/debian/patches/CVE-2026-33018.patch b/debian/patches/CVE-2026-33018.patch new file mode 100644 index 0000000..0b81269 --- /dev/null +++ b/debian/patches/CVE-2026-33018.patch @@ -0,0 +1,24 @@ +--- a/src/fromsixel.c ++++ b/src/fromsixel.c +@@ -1030,7 +1030,7 @@ sixel_decode_raw( + alloc_size = SIXEL_PALETTE_MAX; + } + *palette = (unsigned char *)sixel_allocator_malloc(allocator, (size_t)(alloc_size * 3)); +- if (palette == NULL) { ++ if (*palette == NULL) { + sixel_allocator_free(allocator, image.data); + sixel_helper_set_additional_message( + "sixel_deocde_raw: sixel_allocator_malloc() failed."); +@@ -1102,10 +1102,10 @@ sixel_decode(unsigned char /* in */ *p, /* sixel bytes */ + + *ncolors = image.ncolors + 1; + *palette = (unsigned char *)sixel_allocator_malloc(allocator, (size_t)(*ncolors * 3)); +- if (palette == NULL) { ++ if (*palette == NULL) { + sixel_allocator_free(allocator, image.data); + sixel_helper_set_additional_message( +- "sixel_deocde_raw: sixel_allocator_malloc() failed."); ++ "sixel_decode: sixel_allocator_malloc() failed."); + status = SIXEL_BAD_ALLOCATION; + goto end; + } diff --git a/debian/patches/CVE-2026-33020.patch b/debian/patches/CVE-2026-33020.patch new file mode 100644 index 0000000..2e66646 --- /dev/null +++ b/debian/patches/CVE-2026-33020.patch @@ -0,0 +1,87 @@ +--- a/src/fromsixel.c ++++ b/src/fromsixel.c +@@ -412,6 +412,50 @@ end: + } + + ++static SIXELSTATUS ++reject_invalid_position(parser_context_t const *context) ++{ ++ SIXELSTATUS status = SIXEL_FALSE; ++ ++ if (context->pos_x < 0 ++ || context->pos_x >= SIXEL_WIDTH_LIMIT ++ || context->pos_y < 0 ++ || context->pos_y >= SIXEL_HEIGHT_LIMIT) { ++ status = SIXEL_BAD_INPUT; ++ sixel_helper_set_additional_message( ++ "reject_invalid_position: cursor position limit exceeded."); ++ goto end; ++ } ++ ++ status = SIXEL_OK; ++ ++end: ++ return status; ++} ++ ++ ++static SIXELSTATUS ++sixel_parser_advance_line(parser_context_t *context) ++{ ++ SIXELSTATUS status = SIXEL_FALSE; ++ ++ if (context->pos_y < 0 ++ || context->pos_y > SIXEL_HEIGHT_LIMIT - 6) { ++ status = SIXEL_BAD_INPUT; ++ sixel_helper_set_additional_message( ++ "sixel_parser_advance_line: vertical position limit exceeded."); ++ goto end; ++ } ++ ++ context->pos_x = 0; ++ context->pos_y += 6; ++ status = SIXEL_OK; ++ ++end: ++ return status; ++} ++ ++ + /* convert sixel data into indexed pixel bytes and palette data */ + SIXELAPI SIXELSTATUS + sixel_decode_raw_impl( +@@ -616,13 +660,20 @@ sixel_decode_raw_impl( + break; + case '-': + /* DECGNL Graphics Next Line */ +- context->pos_x = 0; +- context->pos_y += 6; ++ status = sixel_parser_advance_line(context); ++ if (SIXEL_FAILED(status)) { ++ goto end; ++ } + p++; + break; + default: + if (*p >= '?' && *p <= '~') { /* sixel characters */ + ++ status = reject_invalid_position(context); ++ if (SIXEL_FAILED(status)) { ++ goto end; ++ } ++ + sx = image->width; + while (sx < context->pos_x + context->repeat_count) { + sx *= 2; +@@ -644,10 +695,6 @@ sixel_decode_raw_impl( + image->ncolors = context->color_index; + } + +- if (context->pos_x < 0 || context->pos_y < 0) { +- status = SIXEL_BAD_INPUT; +- goto end; +- } + bits = *p - '?'; + + if (bits == 0) { diff --git a/debian/patches/CVE-2026-33021.patch b/debian/patches/CVE-2026-33021.patch new file mode 100644 index 0000000..4eaa8e8 --- /dev/null +++ b/debian/patches/CVE-2026-33021.patch @@ -0,0 +1,79 @@ +--- a/src/tosixel.c ++++ b/src/tosixel.c +@@ -1425,10 +1425,11 @@ sixel_encode_highcolor( + unsigned char palstate[SIXEL_PALETTE_MAX]; + int output_count; + int const maxcolors = 1 << 15; +- int whole_size = width * height /* for paletted_pixels */ +- + maxcolors /* for rgbhit */ +- + maxcolors /* for rgb2pal */ +- + width * 6; /* for marks */ ++ size_t image_size; ++ size_t marks_size; ++ size_t normalized_size; ++ size_t whole_size; ++ size_t maxcolors_size; + int x, y; + unsigned char *dst; + unsigned char *mptr; +@@ -1440,10 +1441,49 @@ sixel_encode_highcolor( + int orig_height; + unsigned char *pal; + ++ maxcolors_size = (size_t)maxcolors; ++ if ((size_t)height > ((size_t)-1) / (size_t)width) { ++ sixel_helper_set_additional_message( ++ "sixel_encode_highcolor: image size overflow."); ++ status = SIXEL_BAD_INPUT; ++ goto error; ++ } ++ image_size = (size_t)width * (size_t)height; ++ ++ if (image_size > ((size_t)-1) / 3UL) { ++ sixel_helper_set_additional_message( ++ "sixel_encode_highcolor: normalized size overflow."); ++ status = SIXEL_BAD_INPUT; ++ goto error; ++ } ++ normalized_size = image_size * 3UL; ++ ++ if ((size_t)width > ((size_t)-1) / 6UL) { ++ sixel_helper_set_additional_message( ++ "sixel_encode_highcolor: marks size overflow."); ++ status = SIXEL_BAD_INPUT; ++ goto error; ++ } ++ marks_size = (size_t)width * 6UL; ++ ++ if (image_size > (size_t)-1 - maxcolors_size || ++ image_size + maxcolors_size > (size_t)-1 - maxcolors_size || ++ image_size + maxcolors_size + maxcolors_size ++ > (size_t)-1 - marks_size) { ++ sixel_helper_set_additional_message( ++ "sixel_encode_highcolor: whole size overflow."); ++ status = SIXEL_BAD_INPUT; ++ goto error; ++ } ++ whole_size = image_size /* for paletted_pixels */ ++ + maxcolors_size /* for rgbhit */ ++ + maxcolors_size /* for rgb2pal */ ++ + marks_size; /* for marks */ ++ + if (dither->pixelformat != SIXEL_PIXELFORMAT_RGB888) { + /* normalize pixelfromat */ +- normalized_pixels = (unsigned char *)sixel_allocator_malloc(dither->allocator, +- (size_t)(width * height * 3)); ++ normalized_pixels = (unsigned char *)sixel_allocator_malloc( ++ dither->allocator, normalized_size); + if (normalized_pixels == NULL) { + goto error; + } +@@ -1458,7 +1498,7 @@ sixel_encode_highcolor( + pixels = normalized_pixels; + } + paletted_pixels = (sixel_index_t *)sixel_allocator_malloc(dither->allocator, +- (size_t)whole_size); ++ whole_size); + if (paletted_pixels == NULL) { + goto error; + } diff --git a/debian/patches/CVE-2026-33023.patch b/debian/patches/CVE-2026-33023.patch new file mode 100644 index 0000000..376d2c3 --- /dev/null +++ b/debian/patches/CVE-2026-33023.patch @@ -0,0 +1,63 @@ +--- a/src/fromsixel.c ++++ b/src/fromsixel.c +@@ -392,6 +392,26 @@ safe_addition_for_params(parser_context_t *context, unsigned char *p) + } + + ++static SIXELSTATUS ++safe_multiply_by_params_div10(int lhs, int rhs, int *result) ++{ ++ SIXELSTATUS status = SIXEL_FALSE; ++ ++ if (lhs > 0 && rhs > INT_MAX / lhs) { ++ status = SIXEL_BAD_INTEGER_OVERFLOW; ++ sixel_helper_set_additional_message( ++ "safe_multiply_by_params_div10: integer overflow detected."); ++ goto end; ++ } ++ ++ *result = lhs * rhs / 10; ++ status = SIXEL_OK; ++ ++end: ++ return status; ++} ++ ++ + /* convert sixel data into indexed pixel bytes and palette data */ + SIXELAPI SIXELSTATUS + sixel_decode_raw_impl( +@@ -524,11 +544,31 @@ sixel_decode_raw_impl( + + if (context->nparams > 2) { + /* Pn3 */ ++ int scaled_pan; ++ int scaled_pad; ++ + if (context->params[2] == 0) { + context->params[2] = 10; + } +- context->attributed_pan = context->attributed_pan * context->params[2] / 10; +- context->attributed_pad = context->attributed_pad * context->params[2] / 10; ++ ++ status = safe_multiply_by_params_div10( ++ context->attributed_pan, ++ context->params[2], ++ &scaled_pan); ++ if (SIXEL_FAILED(status)) { ++ goto end; ++ } ++ ++ status = safe_multiply_by_params_div10( ++ context->attributed_pad, ++ context->params[2], ++ &scaled_pad); ++ if (SIXEL_FAILED(status)) { ++ goto end; ++ } ++ ++ context->attributed_pan = scaled_pan; ++ context->attributed_pad = scaled_pad; + if (context->attributed_pan <= 0) { + context->attributed_pan = 1; + } diff --git a/debian/patches/CVE-2026-44636.patch b/debian/patches/CVE-2026-44636.patch new file mode 100644 index 0000000..c5b903a --- /dev/null +++ b/debian/patches/CVE-2026-44636.patch @@ -0,0 +1,199 @@ +--- a/src/encoder.c ++++ b/src/encoder.c +@@ -723,6 +723,8 @@ sixel_encoder_output_without_macro( + int dulation; + int delay; + int lag = 0; ++ long long target_usec; ++ long long remaining_usec; + struct timespec tv; + clock_t start; + unsigned char *pixbuf; +@@ -768,17 +770,29 @@ sixel_encoder_output_without_macro( + } + start = clock(); + delay = sixel_frame_get_delay(frame); +- if (delay > 0 && !encoder->fignore_delay) { +- dulation = (int)((clock() - start) * 1000 * 1000 / CLOCKS_PER_SEC) - (int)lag; +- lag = 0; +- if (dulation < 10000 * delay) { +- tv.tv_sec = 0; +- tv.tv_nsec = (long)((10000 * delay - dulation) * 1000); +- nanosleep(&tv, NULL); +- } else { +- lag = (int)(10000 * delay - dulation); ++ if (delay > 0 && !encoder->fignore_delay && !encoder->fstatic) { ++#if HAVE_CLOCK ++ dulation = (int)((clock() - start) * 1000 * 1000 / CLOCKS_PER_SEC) - (int)lag; ++ lag = 0; ++#else ++ dulation = 0; ++#endif ++ target_usec = 10000LL * (long long)delay; ++ remaining_usec = target_usec - (long long)dulation; ++ if (remaining_usec > 0) { ++ tv.tv_sec = (time_t)(remaining_usec / 1000000LL); ++ tv.tv_nsec = (long)((remaining_usec % 1000000LL) * 1000LL); ++ nanosleep(&tv, NULL); ++ } else { ++ if (remaining_usec > INT_MAX) { ++ lag = INT_MAX; ++ } else if (remaining_usec < INT_MIN) { ++ lag = INT_MIN; ++ } else { ++ lag = (int)remaining_usec; ++ } ++ } + } +- } + + pixbuf = sixel_frame_get_pixels(frame); + memcpy(p, pixbuf, (size_t)(width * height * depth)); +@@ -812,6 +826,8 @@ sixel_encoder_output_with_macro( + int nwrite; + int dulation; + int lag = 0; ++ long long target_usec; ++ long long remaining_usec; + struct timespec tv; + clock_t start; + unsigned char *pixbuf; +@@ -870,16 +886,28 @@ sixel_encoder_output_with_macro( + "sixel_encoder_output_with_macro: sixel_write_callback() failed."); + goto end; + } +- delay = sixel_frame_get_delay(frame); +- if (delay > 0 && !encoder->fignore_delay) { ++ delay = sixel_frame_get_delay(frame); ++ if (delay > 0 && !encoder->fignore_delay && !encoder->fstatic) { ++#if HAVE_CLOCK + dulation = (int)((clock() - start) * 1000 * 1000 / CLOCKS_PER_SEC) - (int)lag; + lag = 0; +- if (dulation < 10000 * delay) { +- tv.tv_sec = 0; +- tv.tv_nsec = (long)((10000 * delay - dulation) * 1000); ++#else ++ dulation = 0; ++#endif ++ target_usec = 10000LL * (long long)delay; ++ remaining_usec = target_usec - (long long)dulation; ++ if (remaining_usec > 0) { ++ tv.tv_sec = (time_t)(remaining_usec / 1000000LL); ++ tv.tv_nsec = (long)((remaining_usec % 1000000LL) * 1000LL); + nanosleep(&tv, NULL); + } else { +- lag = (int)(10000 * delay - dulation); ++ if (remaining_usec > INT_MAX) { ++ lag = INT_MAX; ++ } else if (remaining_usec < INT_MIN) { ++ lag = INT_MIN; ++ } else { ++ lag = (int)remaining_usec; ++ } + } + } + } +--- a/src/frame.c ++++ b/src/frame.c +@@ -401,11 +401,26 @@ sixel_frame_convert_to_rgb888(sixel_frame_t /*in */ *frame) + + sixel_frame_ref(frame); + ++ if (frame->height != 0 && frame->width > INT_MAX / frame->height) { ++ sixel_helper_set_additional_message( ++ "sixel_frame_convert_to_rgb888: image dimensions are too huge."); ++ status = SIXEL_BAD_INPUT; ++ goto end; ++ } ++ pixel_count = (size_t)frame->width * (size_t)frame->height; ++ ++ + switch (frame->pixelformat) { + case SIXEL_PIXELFORMAT_PAL1: + case SIXEL_PIXELFORMAT_PAL2: + case SIXEL_PIXELFORMAT_PAL4: +- size = (size_t)(frame->width * frame->height * 4); ++ if (pixel_count > (size_t)INT_MAX / 4u) { ++ sixel_helper_set_additional_message( ++ "sixel_frame_convert_to_rgb888: image dimensions are too huge."); ++ status = SIXEL_BAD_INPUT; ++ goto end; ++ } ++ size = pixel_count * 4u; + normalized_pixels = (unsigned char *)sixel_allocator_malloc(frame->allocator, size); + if (normalized_pixels == NULL) { + sixel_helper_set_additional_message( +@@ -413,7 +428,7 @@ sixel_frame_convert_to_rgb888(sixel_frame_t /*in */ *frame) + status = SIXEL_BAD_ALLOCATION; + goto end; + } +- src = normalized_pixels + frame->width * frame->height * 3; ++ src = normalized_pixels + pixel_count * 3u; + dst = normalized_pixels; + status = sixel_helper_normalize_pixelformat(src, + &frame->pixelformat, +@@ -435,7 +450,13 @@ sixel_frame_convert_to_rgb888(sixel_frame_t /*in */ *frame) + frame->pixelformat = SIXEL_PIXELFORMAT_RGB888; + break; + case SIXEL_PIXELFORMAT_PAL8: +- size = (size_t)(frame->width * frame->height * 3); ++ if (pixel_count > (size_t)INT_MAX / 3u) { ++ sixel_helper_set_additional_message( ++ "sixel_frame_convert_to_rgb888: image dimensions are too huge."); ++ status = SIXEL_BAD_INPUT; ++ goto end; ++ } ++ size = pixel_count * 3u; + normalized_pixels = (unsigned char *)sixel_allocator_malloc(frame->allocator, size); + if (normalized_pixels == NULL) { + sixel_helper_set_additional_message( +@@ -466,7 +487,13 @@ sixel_frame_convert_to_rgb888(sixel_frame_t /*in */ *frame) + case SIXEL_PIXELFORMAT_RGBA8888: + case SIXEL_PIXELFORMAT_ARGB8888: + /* normalize pixelformat */ +- size = (size_t)(frame->width * frame->height * 3); ++ if (pixel_count > (size_t)INT_MAX / 3u) { ++ sixel_helper_set_additional_message( ++ "sixel_frame_convert_to_rgb888: image dimensions are too huge."); ++ status = SIXEL_BAD_INPUT; ++ goto end; ++ } ++ size = pixel_count * 3u; + normalized_pixels = (unsigned char *)sixel_allocator_malloc(frame->allocator, size); + if (normalized_pixels == NULL) { + sixel_helper_set_additional_message( +--- a/src/quant.c ++++ b/src/quant.c +@@ -1259,8 +1259,11 @@ sixel_quant_apply_palette( + { + typedef int component_t; + enum { max_depth = 4 }; ++ enum { max_channel_diff_sq = 255 * 255 }; + SIXELSTATUS status = SIXEL_FALSE; + int pos, n, x, y, sum1, sum2; ++ int non_weighted_components; ++ long long max_complexion; + component_t offset; + int color_index; + unsigned short *indextable; +@@ -1359,6 +1362,20 @@ sixel_quant_apply_palette( + } + } + ++ ++ if ((f_lookup == lookup_fast || f_lookup == lookup_normal) && complexion > 1) { ++ non_weighted_components = depth > 1 ? depth - 1 : 0; ++ max_complexion = (INT_MAX - (long long)max_channel_diff_sq ++ * (long long)non_weighted_components) ++ / (long long)max_channel_diff_sq; ++ if ((long long)complexion > max_complexion) { ++ status = SIXEL_BAD_ARGUMENT; ++ sixel_helper_set_additional_message( ++ "sixel_quant_apply_palette: complexion parameter is too large."); ++ goto end; ++ } ++ } ++ + if (foptimize_palette) { + *ncolors = 0; + diff --git a/debian/patches/CVE-2026-44637.patch b/debian/patches/CVE-2026-44637.patch new file mode 100644 index 0000000..403c926 --- /dev/null +++ b/debian/patches/CVE-2026-44637.patch @@ -0,0 +1,136 @@ +--- a/src/encoder.c ++++ b/src/encoder.c +@@ -655,19 +655,14 @@ sixel_encoder_do_clip( + clip_h = encoder->clipheight; + + /* adjust clipping width with comparing it to frame width */ +- if (clip_w + clip_x > src_width) { +- if (clip_x > src_width) { +- clip_w = 0; +- } else { ++ if (clip_x >= src_width || clip_y >= src_height) { ++ clip_w = 0; ++ clip_h = 0; ++ } else { ++ if (clip_w > src_width - clip_x) { + clip_w = src_width - clip_x; + } +- } +- +- /* adjust clipping height with comparing it to frame height */ +- if (clip_h + clip_y > src_height) { +- if (clip_y > src_height) { +- clip_h = 0; +- } else { ++ if (clip_h > src_height - clip_y) { + clip_h = src_height - clip_y; + } + } +--- a/src/fromgif.c ++++ b/src/fromgif.c +@@ -617,8 +617,12 @@ load_gif( + char message[256]; + + fnp.p = fn_load; ++ int frame_no; ++ int loop_no; + +- status = sixel_frame_new(&frame, allocator); ++ frame = NULL; ++ ++// sixel_frame_new moved inside loop + if (SIXEL_FAILED(status)) { + goto end; + } +@@ -642,11 +646,11 @@ load_gif( + } + memset(g.out, 0, bytes); + +- frame->loop_count = 0; ++ loop_no = 0; + + for (;;) { /* per loop */ + +- frame->frame_no = 0; ++ frame_no = 0; + + s.img_buffer = s.img_buffer_original; + status = gif_load_header(&s, &g); +@@ -665,6 +669,12 @@ load_gif( + break; + } + ++ status = sixel_frame_new(&frame, allocator); ++ if (SIXEL_FAILED(status)) { ++ goto end; ++ } ++ frame->loop_count = loop_no; ++ frame->frame_no = frame_no; + frame->width = g.actual_width; + frame->height = g.actual_height; + status = gif_init_frame(frame, &g, bgcolor, reqcolors, fuse_palette); +@@ -676,31 +686,37 @@ load_gif( + if (status != SIXEL_OK) { + goto end; + } ++ sixel_frame_unref(frame); ++ frame = NULL; + + if (fstatic) { + goto end; + } +- ++frame->frame_no; ++ ++frame_no; + } + +- ++frame->loop_count; ++ ++loop_no; + + if (g.loop_count < 0) { + break; + } +- if (loop_control == SIXEL_LOOP_DISABLE || frame->frame_no == 1) { ++ if (loop_control == SIXEL_LOOP_DISABLE || frame_no == 1) { + break; + } + if (loop_control == SIXEL_LOOP_AUTO) { +- if (frame->loop_count == g.loop_count) { ++ if (loop_no == g.loop_count) { + break; + } + } + } + + end: +- sixel_allocator_free(frame->allocator, g.out); +- sixel_frame_unref(frame); ++ sixel_allocator_free(allocator, g.out); ++ sixel_allocator_free(allocator, g.prev_out); ++ sixel_allocator_free(allocator, g.history); ++ if (frame != NULL) { ++ sixel_frame_unref(frame); ++ } + + return status; + } +--- a/src/loader.c ++++ b/src/loader.c +@@ -285,6 +285,8 @@ load_png(unsigned char /* out */ **result, + status = SIXEL_FALSE; + *result = NULL; + ++ png_ptr = NULL; ++ info_ptr = NULL; + png_ptr = png_create_read_struct( + PNG_LIBPNG_VER_STRING, NULL, &png_error_callback, NULL); + if (!png_ptr) { +@@ -589,7 +591,9 @@ load_png(unsigned char /* out */ **result, + status = SIXEL_OK; + + cleanup: ++ if (png_ptr != NULL) { + png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)0); ++ } + + if (rows != NULL) { + sixel_allocator_free(allocator, rows); diff --git a/debian/patches/series b/debian/patches/series index 7ce9e10..cc9274a 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -8,3 +8,9 @@ # 0008-check-number-of-repeat_count.patch CVE-2025-61146.patch CVE-2025-9300.patch +CVE-2026-33023.patch +CVE-2026-33020.patch +CVE-2026-33018.patch +CVE-2026-33021.patch +CVE-2026-44636.patch +CVE-2026-44637.patch