File: 0003_pdfwrite-avoid-buffer-overrun.patch

package info (click to toggle)
ghostscript 10.05.1~dfsg-1%2Bdeb13u1
  • links: PTS, VCS
  • area: main
  • in suites: trixie-proposed-updates
  • size: 93,856 kB
  • sloc: ansic: 908,927; python: 7,676; cpp: 6,534; cs: 6,457; sh: 6,168; java: 4,028; perl: 2,373; tcl: 1,639; makefile: 529; awk: 66; yacc: 18
file content (136 lines) | stat: -rw-r--r-- 5,472 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
From: Ken Sharp <Ken.Sharp@artifex.com>
Date: Thu, 22 May 2025 12:25:41 +0100
Subject: pdfwrite - avoid buffer overrun
Origin: https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=0cae41b23a9669e801211dd4cf97b6dadd6dbdd7
Bug: https://bugs.ghostscript.com/show_bug.cgi?id=708539
Bug-Debian: https://bugs.debian.org/1116444
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-59798

Bug #708539 "Buffer overflow in pdf_write_cmap"

The proposed fix in the report solves the buffer overrun, but does not
tackle a number of other problems.

This commit checks the result of stream_puts() in
pdf_write_cid_system_info_to_stream() and correctly signals an error to
the caller if that fails.

In pdf_write_cid_system_info we replace a (rather small!) fixed size
buffer with a dynamically allocated one using the lengths of the strings
which pdf_write_cid_system_info_to_stream() will write, and a small
fixed overhead to deal with the keys and initial byte '/'.

Because 'buf' is used in the stream 's', if it is too small to hold all
the CIDSystemInfo then we would get an error which was simply discarded
previously.

We now should avoid the potential error by ensuring the buffer is large
enough for all the information, and if we do get an error we no longer
silently ignore it, which would write an invalid PDF file.
---
 devices/vector/gdevpdtw.c | 52 ++++++++++++++++++++++++++++++---------
 1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/devices/vector/gdevpdtw.c b/devices/vector/gdevpdtw.c
index ced15c9b2bbe..fe24dd73accf 100644
--- a/devices/vector/gdevpdtw.c
+++ b/devices/vector/gdevpdtw.c
@@ -703,7 +703,8 @@ static int
 pdf_write_cid_system_info_to_stream(gx_device_pdf *pdev, stream *s,
                           const gs_cid_system_info_t *pcidsi, gs_id object_id)
 {
-    byte *Registry, *Ordering;
+    byte *Registry = NULL, *Ordering = NULL;
+    int code = 0;
 
     Registry = gs_alloc_bytes(pdev->pdf_memory, pcidsi->Registry.size, "temporary buffer for Registry");
     if (!Registry)
@@ -734,14 +735,19 @@ pdf_write_cid_system_info_to_stream(gx_device_pdf *pdev, stream *s,
         }
         s_arcfour_process_buffer(&sarc4, Ordering, pcidsi->Ordering.size);
     }
-    stream_puts(s, "<<\n/Registry");
+    code = stream_puts(s, "<<\n/Registry");
+    if (code < 0)
+        goto error;
     s_write_ps_string(s, Registry, pcidsi->Registry.size, PRINT_HEX_NOT_OK);
-    stream_puts(s, "\n/Ordering");
+    code = stream_puts(s, "\n/Ordering");
+    if(code < 0)
+        goto error;
     s_write_ps_string(s, Ordering, pcidsi->Ordering.size, PRINT_HEX_NOT_OK);
+error:
     pprintd1(s, "\n/Supplement %d\n>>\n", pcidsi->Supplement);
     gs_free_object(pdev->pdf_memory, Registry, "free temporary Registry buffer");
     gs_free_object(pdev->pdf_memory, Ordering, "free temporary Ordering buffer");
-    return 0;
+    return code;
 }
 
 int
@@ -786,31 +792,55 @@ pdf_write_cmap(gx_device_pdf *pdev, const gs_cmap_t *pcmap,
     *ppres = writer.pres;
     writer.pres->where_used = 0; /* CMap isn't a PDF resource. */
     if (!pcmap->ToUnicode) {
-        byte buf[200];
+        byte *buf = NULL;
+        uint64_t buflen = 0;
         cos_dict_t *pcd = (cos_dict_t *)writer.pres->object;
         stream s;
 
+        /* We use 'buf' for the stream 's' below and that needs to have some extra
+         * space for the CIDSystemInfo. We also need an extra byte for the leading '/'
+         * 100 bytes is ample for the overhead.
+         */
+        buflen = pcmap->CIDSystemInfo->Registry.size + pcmap->CIDSystemInfo->Ordering.size + pcmap->CMapName.size + 100;
+        if (buflen > max_uint)
+            return_error(gs_error_limitcheck);
+
+        buf = gs_alloc_bytes(pdev->memory, buflen, "pdf_write_cmap");
+        if (buf == NULL)
+            return_error(gs_error_VMerror);
+
         code = cos_dict_put_c_key_int(pcd, "/WMode", pcmap->WMode);
-        if (code < 0)
+        if (code < 0) {
+            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
             return code;
+        }
         buf[0] = '/';
         memcpy(buf + 1, pcmap->CMapName.data, pcmap->CMapName.size);
         code = cos_dict_put_c_key_string(pcd, "/CMapName",
                         buf, pcmap->CMapName.size + 1);
-        if (code < 0)
+        if (code < 0) {
+            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
             return code;
+        }
         s_init(&s, pdev->memory);
-        swrite_string(&s, buf, sizeof(buf));
+        swrite_string(&s, buf, buflen);
         code = pdf_write_cid_system_info_to_stream(pdev, &s, pcmap->CIDSystemInfo, 0);
-        if (code < 0)
+        if (code < 0) {
+            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
             return code;
+        }
         code = cos_dict_put_c_key_string(pcd, "/CIDSystemInfo",
                         buf, stell(&s));
-        if (code < 0)
+        if (code < 0) {
+            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
             return code;
+        }
         code = cos_dict_put_string_copy(pcd, "/Type", "/CMap");
-        if (code < 0)
+        if (code < 0) {
+            gs_free_object(pdev->memory, buf, "pdf_write_cmap");
             return code;
+        }
+        gs_free_object(pdev->memory, buf, "pdf_write_cmap");
     }
     if (pcmap->CMapName.size == 0) {
         /* Create an arbitrary name (for ToUnicode CMap). */
-- 
2.51.0