Package: mupdf
Version: 1.25.1+ds1-6
Tags: patch security
Justification: remote DoS via infinite recursion
Followup-For: Bug #1110482
Usertags: cve-2025-46206
Control: tags -1 patch

Dear Maintainer,

This non-maintainer upload (NMU) provides a backported patch for CVE-2025-46206 
in the mupdf package for Debian Trixie.

The vulnerability allows a remote attacker to trigger infinite recursion in 
`mutool clean` by crafting a PDF with cyclic `/Next` references in the outline 
structure, causing the process to crash and potentially exhaust system 
resources.

Upstream has fixed this issue in commit 
https://cgit.ghostscript.com/cgi-bin/cgit.cgi/mupdf.git/commit/?id=0ec7e4d2201bb6df217e01c17396d36297abf9ac.
 This patch incorporates that change into version 1.25.1+ds1-7.

Reproduction is straightforward using the upstream PoC from Bug 708521, and 
testing confirms that with the patch the crash and core dump no longer occur.

Please consider including this fix or let me know if further information or 
packaging adjustments are required.

Best regards,  
Yang Wang  
<[email protected]>

-- System Information:
Debian Release: 13.0
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 5.15.0-138-generic (SMP w/88 CPU threads)
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968) (ignored: LC_ALL set to C), 
LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: unable to detect

Versions of packages mupdf depends on:
ii  libc6            2.41-10
ii  libgl1           1.7.0-1+b2
ii  libglut3.12      3.4.0-4
ii  libjbig2dec0     0.20-1+b3
ii  libjs-sphinxdoc  8.1.3-5
ii  libmujs3         1.3.6-1
ii  libmupdf25.1     1.25.1+ds1-6
ii  libssl3t64       3.5.1-1
ii  libx11-6         2:1.8.12-1
ii  libxext6         2:1.3.4-1+b3

mupdf recommends no packages.

Versions of packages mupdf suggests:
ii  mupdf-tools  1.25.1+ds1-6

-- no debconf information
diff -Nru mupdf-1.25.1+ds1/debian/changelog mupdf-1.25.1+ds1/debian/changelog
--- mupdf-1.25.1+ds1/debian/changelog   2025-04-21 22:12:48.000000000 +0000
+++ mupdf-1.25.1+ds1/debian/changelog   2025-08-06 20:24:38.000000000 +0000
@@ -1,3 +1,12 @@
+mupdf (1.25.1+ds1-7) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * Fix CVE-2025-46206: Infinite recursion in `mutool clean` when processing
+    cyclic /Next references in PDF outlines. Backports upstream commit
+    0ec7e4d2201bb6df217e01c17396d36297abf9ac which avoids outline-recursion 
cycles.
+
+ -- Yang Wang <[email protected]> Wed, 06 Aug 2025 16:24:38 -0400
+
 mupdf (1.25.1+ds1-6) unstable; urgency=medium
 
   * Fix segfault when using get_text() on arm64 (Closes: #1100748)
diff -Nru mupdf-1.25.1+ds1/debian/patches/fix-cve-2025-46206.patch 
mupdf-1.25.1+ds1/debian/patches/fix-cve-2025-46206.patch
--- mupdf-1.25.1+ds1/debian/patches/fix-cve-2025-46206.patch    1970-01-01 
00:00:00.000000000 +0000
+++ mupdf-1.25.1+ds1/debian/patches/fix-cve-2025-46206.patch    2025-08-06 
20:24:38.000000000 +0000
@@ -0,0 +1,101 @@
+Description: Fix infinite recursion in mutool clean when processing PDF 
outlines with cyclic /Next references
+Origin: upstream, commit 
https://cgit.ghostscript.com/cgi-bin/cgit.cgi/mupdf.git/commit/?id=0ec7e4d2201bb6df217e01c17396d36297abf9ac
+Bug: https://bugs.ghostscript.com/show_bug.cgi?id=708521
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2025-46206
+Forwarded: yes
+Author: Sebastian Rasmussen <[email protected]> (upstream)
+Reviewed-by: Yang Wang <[email protected]>
+Last-Update: 2025-08-06
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: mupdf-1.25.1+ds1/source/pdf/pdf-clean-file.c
+===================================================================
+--- mupdf-1.25.1+ds1.orig/source/pdf/pdf-clean-file.c
++++ mupdf-1.25.1+ds1/source/pdf/pdf-clean-file.c
+@@ -157,22 +157,25 @@ static int strip_stale_annot_refs(fz_con
+       }
+ }
+ 
+-static int strip_outlines(fz_context *ctx, pdf_document *doc, pdf_obj 
*outlines, int page_count, int *page_object_nums, pdf_obj *names_list);
++static int strip_outlines(fz_context *ctx, pdf_document *doc, pdf_obj 
*outlines, int page_count, int *page_object_nums, pdf_obj *names_list, 
pdf_mark_bits *marks);
+ 
+-static int strip_outline(fz_context *ctx, pdf_document *doc, pdf_obj 
*outlines, int page_count, int *page_object_nums, pdf_obj *names_list, pdf_obj 
**pfirst, pdf_obj **plast)
++static int strip_outline(fz_context *ctx, pdf_document *doc, pdf_obj 
*outlines, int page_count, int *page_object_nums, pdf_obj *names_list, pdf_obj 
**pfirst, pdf_obj **plast, pdf_mark_bits *marks)
+ {
+       pdf_obj *prev = NULL;
+       pdf_obj *first = NULL;
+       pdf_obj *current;
+       int count = 0;
+ 
++      if (pdf_mark_bits_set(ctx, marks, outlines))
++              fz_throw(ctx, FZ_ERROR_FORMAT, "Cycle detected in outlines");
++
+       for (current = outlines; current != NULL; )
+       {
+               int nc;
+ 
+               /* Strip any children to start with. This takes care of
+                * First/Last/Count for us. */
+-              nc = strip_outlines(ctx, doc, current, page_count, 
page_object_nums, names_list);
++              nc = strip_outlines(ctx, doc, current, page_count, 
page_object_nums, names_list, marks);
+ 
+               if (!dest_is_valid(ctx, current, page_count, page_object_nums, 
names_list))
+               {
+@@ -223,7 +226,7 @@ static int strip_outline(fz_context *ctx
+       return count;
+ }
+ 
+-static int strip_outlines(fz_context *ctx, pdf_document *doc, pdf_obj 
*outlines, int page_count, int *page_object_nums, pdf_obj *names_list)
++static int strip_outlines(fz_context *ctx, pdf_document *doc, pdf_obj 
*outlines, int page_count, int *page_object_nums, pdf_obj *names_list, 
pdf_mark_bits *marks)
+ {
+       int nc;
+       pdf_obj *first;
+@@ -232,11 +235,14 @@ static int strip_outlines(fz_context *ct
+       if (!pdf_is_dict(ctx, outlines))
+               return 0;
+ 
++      if (pdf_mark_bits_set(ctx, marks, outlines))
++              fz_throw(ctx, FZ_ERROR_FORMAT, "Cycle detected in outlines");
++
+       first = pdf_dict_get(ctx, outlines, PDF_NAME(First));
+       if (!pdf_is_dict(ctx, first))
+               nc = 0;
+       else
+-              nc = strip_outline(ctx, doc, first, page_count, 
page_object_nums, names_list, &first, &last);
++              nc = strip_outline(ctx, doc, first, page_count, 
page_object_nums, names_list, &first, &last, marks);
+ 
+       if (nc == 0)
+       {
+@@ -268,6 +274,7 @@ static void pdf_rearrange_pages_imp(fz_c
+       pdf_obj *structtreeroot;
+       pdf_obj *ostructparents;
+       pdf_obj *structparents = NULL;
++      pdf_mark_bits *marks = NULL;
+ 
+       /* Keep only pages/type and (reduced) dest entries to avoid
+        * references to unretained pages */
+@@ -286,6 +293,7 @@ static void pdf_rearrange_pages_imp(fz_c
+       fz_var(allfields);
+       fz_var(page_object_nums);
+       fz_var(kids);
++      fz_var(marks);
+ 
+       fz_try(ctx)
+       {
+@@ -423,13 +431,15 @@ static void pdf_rearrange_pages_imp(fz_c
+                               pdf_dict_del(ctx, f, PDF_NAME(A));
+               }
+ 
+-              if (strip_outlines(ctx, doc, outlines, pagecount, 
page_object_nums, names_list) == 0)
++              marks = pdf_new_mark_bits(ctx, doc);
++              if (strip_outlines(ctx, doc, outlines, pagecount, 
page_object_nums, names_list, marks) == 0)
+               {
+                       pdf_dict_del(ctx, root, PDF_NAME(Outlines));
+               }
+       }
+       fz_always(ctx)
+       {
++              pdf_drop_mark_bits(ctx, marks);
+               fz_free(ctx, page_object_nums);
+               pdf_drop_obj(ctx, allfields);
+               pdf_drop_obj(ctx, root);
diff -Nru mupdf-1.25.1+ds1/debian/patches/series 
mupdf-1.25.1+ds1/debian/patches/series
--- mupdf-1.25.1+ds1/debian/patches/series      2025-04-21 22:12:48.000000000 
+0000
+++ mupdf-1.25.1+ds1/debian/patches/series      2025-08-06 20:24:38.000000000 
+0000
@@ -9,3 +9,4 @@
 0008-define-SONAME-header.patch
 0008-Add-fallback-for-missing-SA_NOCLDWAIT.patch
 0009-Use-Charis-SIL-ttf-font-directly.patch
+fix-cve-2025-46206.patch

Reply via email to