Bug 708539

Summary: Buffer overflow in pdf_write_cmap
Product: Ghostscript Reporter: Piotr Kajda <petermasterperfect>
Component: Security (public)Assignee: Chris Liddell (chrisl) <chris.liddell>
Status: RESOLVED FIXED    
Severity: normal CC: carnil, dr, jsmeix, ken.sharp, marc.deslauriers, robin.watts, sam, till.kamppeter, zdohnal
Priority: P2    
Version: unspecified   
Hardware: PC   
OS: Linux   
Customer: Word Size: ---
Attachments: Proof of concept

Description Piotr Kajda 2025-05-12 01:23:13 UTC
Created attachment 26787 [details]
Proof of concept

# Title: Stack-based buffer overflow in pdf_write_cmap
# Date Found: 2025-05-12
# Version: Tested on commit e77e13e11708335555a27ea0c5ec7c005d159049
# Author: Piotr Kajda
# Tested On: Arch Linux


I have discovered a stack-based buffer overflow in the pdf_write_cmap function located in devices/vector/gdevpdtw.c at line 797. There is no check of cmap name size before memcpy to statically allocated buffer. I have attached poc.pdf which triggers the bug.

Step to reproduce with asan output:
sanbin/gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=test.pdf poc.pdf
=================================================================
==21330==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x72118034ff38 at pc 0x721186cfaf59 bp 0x7fffe0101430 sp 0x7fffe0100bd8
WRITE of size 218 at 0x72118034ff38 thread T0
    #0 0x721186cfaf58 in memcpy /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115
    #1 0x6069115184d9 in pdf_write_cmap devices/vector/gdevpdtw.c:797
    #2 0x6069114e2599 in pdf_cmap_alloc devices/vector/gdevpdtf.c:1280
    #3 0x6069114b4e4a in attach_cmap_resource devices/vector/gdevpdtc.c:310
    #4 0x6069114bb721 in scan_cmap_text devices/vector/gdevpdtc.c:823
    #5 0x6069114bcf7d in process_cmap_text devices/vector/gdevpdtc.c:968
    #6 0x606911512779 in pdf_text_process devices/vector/gdevpdtt.c:3832
    #7 0x60691191d8b1 in gs_text_process base/gstext.c:682
    #8 0x606912171377 in pdfi_show_simple pdf/pdf_text.c:436
    #9 0x606912173ede in pdfi_show_Tr_preserve pdf/pdf_text.c:806
    #10 0x60691217468b in pdfi_show pdf/pdf_text.c:857
    #11 0x6069121789e5 in pdfi_TJ pdf/pdf_text.c:1270
    #12 0x60691204715e in pdfi_interpret_stream_operator pdf/pdf_int.c:1669
    #13 0x60691204aa23 in pdfi_interpret_content_stream pdf/pdf_int.c:2148
    #14 0x6069120b2a31 in pdfi_process_page_contents pdf/pdf_page.c:135
    #15 0x6069120b2cb3 in pdfi_process_one_page pdf/pdf_page.c:159
    #16 0x6069120ba987 in pdfi_page_render pdf/pdf_page.c:1029
    #17 0x60691200be94 in zPDFdrawpage psi/zpdfops.c:963
    #18 0x606911df1e90 in do_call_operator psi/interp.c:91
    #19 0x606911dffcae in interp psi/interp.c:1772
    #20 0x606911df3cb9 in gs_call_interp psi/interp.c:535
    #21 0x606911df32dc in gs_interpret psi/interp.c:488
    #22 0x606911dc5f89 in gs_main_interpret psi/imain.c:257
    #23 0x606911dcae38 in gs_main_run_string_end psi/imain.c:945
    #24 0x606911dca7e4 in gs_main_run_string_with_length psi/imain.c:889
    #25 0x606911dca756 in gs_main_run_string psi/imain.c:870
    #26 0x606911dd7dd5 in run_string psi/imainarg.c:1188
    #27 0x606911dd7ae3 in runarg psi/imainarg.c:1147
    #28 0x606911dd7341 in argproc psi/imainarg.c:1069
    #29 0x606911dd1632 in gs_main_init_with_args01 psi/imainarg.c:250
    #30 0x606911dd1b9f in gs_main_init_with_args psi/imainarg.c:304
    #31 0x606911ddd5b9 in psapi_init_with_args psi/psapi.c:294
    #32 0x6069121d9476 in gsapi_init_with_args psi/iapi.c:253
    #33 0x606910894721 in main psi/gs.c:104
    #34 0x721185a35487  (/usr/lib/libc.so.6+0x27487) (BuildId: 0b707b217b15b106c25fe51df3724b25848310c0)
    #35 0x721185a3554b in __libc_start_main (/usr/lib/libc.so.6+0x2754b) (BuildId: 0b707b217b15b106c25fe51df3724b25848310c0)
    #36 0x606910894404 in _start (/home/zxcv/ghostpdl_org/sanbin/gs+0x3af404) (BuildId: 27a3edd0d99c18eca2535260d6c81a6aa7d42689)

Address 0x72118034ff38 is located in stack of thread T0 at offset 824 in frame
    #0 0x6069115180f5 in pdf_write_cmap devices/vector/gdevpdtw.c:772


My fix:
diff --git a/devices/vector/gdevpdtw.c b/devices/vector/gdevpdtw.c
index ced15c9b2..4c433ccd4 100644
--- a/devices/vector/gdevpdtw.c
+++ b/devices/vector/gdevpdtw.c
@@ -794,6 +794,10 @@ pdf_write_cmap(gx_device_pdf *pdev, const gs_cmap_t *pcmap,
         if (code < 0)
             return code;
         buf[0] = '/';
+
+               if(pcmap->CMapName.size >= sizeof(buf))
+                       return_error(gs_error_limitcheck);
+
         memcpy(buf + 1, pcmap->CMapName.data, pcmap->CMapName.size);
         code = cos_dict_put_c_key_string(pcd, "/CMapName",
                         buf, pcmap->CMapName.size + 1);
Comment 1 Ken Sharp 2025-05-22 11:37:30 UTC
Fixed in commit 0cae41b23a9669e801211dd4cf97b6dadd6dbdd7

There's nothing wrong with the proposed patch, but this deals with the problem in (I think) a neater way using dynamic allocation. Previously a lengthy CMap name could easily cause an error writing the CIDSystemInfo which would be ignored and produce an invalid PDF file.