clazzes-ghostscript 9.53.3 Security Review
Resources
List of third party libraries
https://www.ghostscript.com/doc/current/thirdparty.htm
Configuration of clazzes-ghostscript
The following configure options are used for clazzes-ghostscript
./configure --prefix=/usr/clazzes-ghostscript --enable-dynamic
--disable-cups --disable-gtk --without-x
Hence, the security review does not need to cover the CUPS library or any X-Windows or GTK-releated ghostscript issues.
Applicable Third Party Libraries
Library Name | Version | Function | License | URL |
---|---|---|---|---|
eXpat | 2.2.9 | XML parsing for XPS interpreter | MIT/eXpat License | |
FreeType | 2.10.1 | Font scaling and rendering for Ghostscript | FreeType License | |
jbig2dec | 0.17 | JBIG2 decoding for the PDF interpreter | Licensed with Ghostscript/GhostPDL | |
libjpeg | 9c | JPEG/DCT decoding/encoding | "Free" | |
LittleCMS 2 mt | 2.9mt | ICC profile based color conversion and management | MIT LICENSE | |
libpng | 1.6.37 | PNG image encoding/decoding. | libpng license | |
OpenJPEG | 2.3.1 | JPEG2000 image decoding for the PDF interpreter | BSD-style | |
libtiff | 4.1.0 | TIFF image encoding/decoding | BSD-style | |
zlib | 1.2.11 | (De)Flate compression | zlib License |
Review of CVEs
CVEs of ghostscript-9.53.3
Query:
As of 2020-12-27 no major CVEs are open against the core ghostscript project.
A long list of vulnerabilites (CVE-2020-16287 up to CVE-2020-16310 and CVE-2020-17538)has been fixed for ghostscript-9.51 after a thorough security review.
The most recent CVE, https://nvd.nist.gov/vuln/detail/CVE-2020-14373 is a problem specific to ghostscript-9.25, which has been delivered with RHEL. This CVE has been fixed for ghostscript-9.53, see https://bugs.ghostscript.com/show_bug.cgi?id=702851
CVEs of libexpat 2.2.9
No known CVEs as of 2020-12-27.
CVEs of freetype 2.10.1
freetype-2.10.1 is subject to the zero-day exploit
https://nvd.nist.gov/vuln/detail/CVE-2020-15999
Hence, we upgraded to freetype-2.10.4 as of svn rev. 71
CVEs of jbig2dec 0.17
jbig2dec-0.17 is subject to the following severe vulnerability
https://nvd.nist.gov/vuln/detail/CVE-2020-12268
The patch originates from April 2020 and is actually include in the sources of ghostscript-9.53.3, which ha been manually verified.
CVEs of libjpeg-9c
libjpeg-9c is vulnerable to
https://nvd.nist.gov/vuln/detail/CVE-2020-14152
https://nvd.nist.gov/vuln/detail/CVE-2020-14153
Hence, we upgraded to libjpeg-9d as of svn rev. 72
CVEs of libpng-1.6.37
No known CVEs as of 2020-12-27.
CVEs of openjpeg-2.3.1
The vulnerability
https://nvd.nist.gov/vuln/detail/CVE-2020-15389
only affects openjpeg cmdline tools, which are not included in ghostscript, because ghostscript actually uses the openjpeg library.
CVEs fo libtiff-4.1.0
All CVEs are reported against libtiff-4.0.x and a review of git commits revealed, that libtiff-4.1.0 is indeed incorporating all fixes for the CVEs listed above.
CVEs of zlib 1.2.11
This list contains only CVEs of third parties with correctly applying the awkward zlib API with buffer over- and/or underruns. zlib itself is not subject to any CVE, which appeared during the last 3 years.
valgrind Runs
These valgrind runs are based on an example from our customers, which crashes ghostscript-9.25 when rendering to the pngalpha output device. The example involves fonts, image masks and is other wise not very complex.
The test runs have been executed on a centos8 machine with recent centos 8.2 updates as of 2020-12-28.
valgrind clazzes-ghostscript-9.53.3-1 pngalpha
[root@centos8 ~]# valgrind /usr/clazzes-ghostscript/bin/gs -sDEVICE=pngalpha -sOutputFile=tmp.png -dSAFER -dBATCH -dNOPAUSE -dUseCropBox -dFirstPage=1 -dLastPage=1 -r100.0 -f tmp.pdf
==408600== Memcheck, a memory error detector
==408600== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==408600== Using Valgrind-3.16.0 and LibVEX; rerun with -h for copyright info
==408600== Command: /usr/clazzes-ghostscript/bin/gs -sDEVICE=pngalpha -sOutputFile=tmp.png -dSAFER -dBATCH -dNOPAUSE -dUseCropBox -dFirstPage=1 -dLastPage=1 -r100.0 -f tmp.pdf
==408600==
GPL Ghostscript 9.53.3 (2020-10-01)
Copyright (C) 2020 Artifex Software, Inc. All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
Processing pages 1 through 1.
Page 1
==408600== Syscall param pwrite64(buf) points to uninitialised byte(s)
==408600== at 0x53D6278: pwrite (in /usr/lib64/libpthread-2.28.so)
==408600== by 0x45B984: gp_pwrite_impl (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x560CF7: clist_fwrite_chars (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x54B5FB: cmd_write_pseudo_band (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x538918: clist_icc_writetable (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x538D3B: clist_end_page (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x54509F: clist_close_writer_and_init_reader (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x5459E2: clist_get_bits_rectangle (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x85C31A: gx_default_get_bits (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x52D933: gx_downscaler_getbits (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x75A061: do_png_print_page (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x525662: gdev_prn_output_page_aux (in /usr/clazzes-ghostscript/bin/gs)
==408600== Address 0x81a9ef8 is 11,960 bytes inside a block of size 20,048 alloc'd
==408600== at 0x4C30F0B: malloc (vg_replace_malloc.c:307)
==408600== by 0x780777: gs_heap_alloc_bytes (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x75DFE4: alloc_acquire_clump (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x75EEA1: alloc_obj.isra.4 (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x8DEA18: alloc_save_change_alloc (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x8D9915: gs_alloc_ref_array (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x8A3DCD: dict_create_unpacked_keys.isra.0 (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x8A4105: dict_unpack (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x8A50B1: dict_put (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x8BC5F1: zput (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x8A95F5: gs_interpret (in /usr/clazzes-ghostscript/bin/gs)
==408600== by 0x89D5B8: gs_main_run_string_end (in /usr/clazzes-ghostscript/bin/gs)
==408600==
==408600==
==408600== HEAP SUMMARY:
==408600== in use at exit: 0 bytes in 0 blocks
==408600== total heap usage: 7,108 allocs, 7,108 frees, 108,179,726 bytes allocated
==408600==
==408600== All heap blocks were freed -- no leaks are possible
==408600==
==408600== Use --track-origins=yes to see where uninitialised values come from
==408600== For lists of detected and suppressed errors, rerun with: -s
==408600== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
The reported writing of uninitialized memory seems to be immanent to the png output writer, this is a frequent warning for compressed output wrriting.
valgrind ghostscript-9.25-7.el8 pngalpha crash
[root@centos8 ~]# valgrind /usr/bin/gs -sDEVICE=pngalpha -sOutputFile=tmp.png -dSAFER -dBATCH -dNOPAUSE -dUseCropBox -dFirstPage=1 -dLastPage=1 -r100.0 -f tmp.pdf
==408602== Memcheck, a memory error detector
==408602== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==408602== Using Valgrind-3.16.0 and LibVEX; rerun with -h for copyright info
==408602== Command: /usr/bin/gs -sDEVICE=pngalpha -sOutputFile=tmp.png -dSAFER -dBATCH -dNOPAUSE -dUseCropBox -dFirstPage=1 -dLastPage=1 -r100.0 -f tmp.pdf
==408602==
GPL Ghostscript 9.25 (2018-09-13)
Copyright (C) 2018 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 1.
Page 1
==408602== Syscall param pwrite64(buf) points to uninitialised byte(s)
==408602== at 0x60AFBD7: pwrite (in /usr/lib64/libc-2.28.so)
==408602== by 0x4F56396: gp_fpwrite (in /usr/lib64/libgs.so.9.25)
==408602== by 0x503AFAC: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x502618F: cmd_write_pseudo_band (in /usr/lib64/libgs.so.9.25)
==408602== by 0x50132C2: clist_icc_writetable (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501371F: clist_end_page (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501F747: clist_close_writer_and_init_reader (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5020172: clist_get_bits_rectangle (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5039059: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x51F71D2: gx_default_get_bits (in /usr/lib64/libgs.so.9.25)
==408602== by 0x500741E: gx_downscaler_getbits (in /usr/lib64/libgs.so.9.25)
==408602== by 0x516A279: ??? (in /usr/lib64/libgs.so.9.25)
==408602== Address 0xf00db00 is 11,728 bytes inside a block of size 20,048 alloc'd
==408602== at 0x4C30F0B: malloc (vg_replace_malloc.c:307)
==408602== by 0x518F6B3: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x516C3D4: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x516D2EE: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x52757F7: gs_alloc_ref_array (in /usr/lib64/libgs.so.9.25)
==408602== by 0x523D1E5: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x523D385: dict_alloc (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5242194: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5243C16: gs_interpret (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5236BCB: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x52370BF: gs_main_init2aux (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5237695: gs_main_init2 (in /usr/lib64/libgs.so.9.25)
==408602==
==408602== Invalid read of size 8
==408602== at 0x5000D77: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x50015A2: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x4FC3F7F: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x4FC9854: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5017320: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501E131: clist_playback_band (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501F94B: clist_playback_file_bands (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501FD8D: clist_render_rectangle (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501FFAE: clist_rasterize_lines (in /usr/lib64/libgs.so.9.25)
==408602== by 0x502021E: clist_get_bits_rectangle (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5039059: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x51F71D2: gx_default_get_bits (in /usr/lib64/libgs.so.9.25)
==408602== Address 0x18 is not stack'd, malloc'd or (recently) free'd
==408602==
==408602==
==408602== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==408602== Access not within mapped region at address 0x18
==408602== at 0x5000D77: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x50015A2: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x4FC3F7F: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x4FC9854: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5017320: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501E131: clist_playback_band (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501F94B: clist_playback_file_bands (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501FD8D: clist_render_rectangle (in /usr/lib64/libgs.so.9.25)
==408602== by 0x501FFAE: clist_rasterize_lines (in /usr/lib64/libgs.so.9.25)
==408602== by 0x502021E: clist_get_bits_rectangle (in /usr/lib64/libgs.so.9.25)
==408602== by 0x5039059: ??? (in /usr/lib64/libgs.so.9.25)
==408602== by 0x51F71D2: gx_default_get_bits (in /usr/lib64/libgs.so.9.25)
==408602== If you believe this happened as a result of a stack
==408602== overflow in your program's main thread (unlikely but
==408602== possible), you can try to increase the size of the
==408602== main thread stack using the --main-stacksize= flag.
==408602== The main thread stack size used in this run was 8388608.
==408602==
==408602== HEAP SUMMARY:
==408602== in use at exit: 24,266,244 bytes in 1,985 blocks
==408602== total heap usage: 9,208 allocs, 7,223 frees, 89,693,975 bytes allocated
==408602==
==408602== LEAK SUMMARY:
==408602== definitely lost: 0 bytes in 0 blocks
==408602== indirectly lost: 0 bytes in 0 blocks
==408602== possibly lost: 0 bytes in 0 blocks
==408602== still reachable: 24,266,244 bytes in 1,985 blocks
==408602== suppressed: 0 bytes in 0 blocks
==408602== Rerun with --leak-check=full to see details of leaked memory
==408602==
==408602== Use --track-origins=yes to see where uninitialised values come from
==408602== For lists of detected and suppressed errors, rerun with: -s
==408602== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
This crash (occurring in other customers examples too) was the original cause for our clazzes-ghostscript efforts.
valgrind clazzes-ghostscript-9.53.3-1 png16m
[root@centos8 ~]# valgrind /usr/clazzes-ghostscript/bin/gs -sDEVICE=png16m -sOutputFile=tmp.png -dSAFER -dBATCH -dNOPAUSE -dUseCropBox -dFirstPage=1 -dLastPage=1 -r100.0 -f tmp.pdf
==408615== Memcheck, a memory error detector
==408615== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==408615== Using Valgrind-3.16.0 and LibVEX; rerun with -h for copyright info
==408615== Command: /usr/clazzes-ghostscript/bin/gs -sDEVICE=png16m -sOutputFile=tmp.png -dSAFER -dBATCH -dNOPAUSE -dUseCropBox -dFirstPage=1 -dLastPage=1 -r100.0 -f tmp.pdf
==408615==
GPL Ghostscript 9.53.3 (2020-10-01)
Copyright (C) 2020 Artifex Software, Inc. All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
Processing pages 1 through 1.
Page 1
==408615== Syscall param pwrite64(buf) points to uninitialised byte(s)
==408615== at 0x53D6278: pwrite (in /usr/lib64/libpthread-2.28.so)
==408615== by 0x45B984: gp_pwrite_impl (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x560CF7: clist_fwrite_chars (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x54B5FB: cmd_write_pseudo_band (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x538918: clist_icc_writetable (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x538D3B: clist_end_page (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x54509F: clist_close_writer_and_init_reader (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x5459E2: clist_get_bits_rectangle (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x85C31A: gx_default_get_bits (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x52D933: gx_downscaler_getbits (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x75A061: do_png_print_page (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x525662: gdev_prn_output_page_aux (in /usr/clazzes-ghostscript/bin/gs)
==408615== Address 0x81181a8 is 10,792 bytes inside a block of size 20,048 alloc'd
==408615== at 0x4C30F0B: malloc (vg_replace_malloc.c:307)
==408615== by 0x780777: gs_heap_alloc_bytes (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x75DFE4: alloc_acquire_clump (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x75EEA1: alloc_obj.isra.4 (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x8DEA18: alloc_save_change_alloc (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x8D9915: gs_alloc_ref_array (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x8A3DCD: dict_create_unpacked_keys.isra.0 (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x8A4105: dict_unpack (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x8A50B1: dict_put (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x8BC5F1: zput (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x8A95F5: gs_interpret (in /usr/clazzes-ghostscript/bin/gs)
==408615== by 0x89D5B8: gs_main_run_string_end (in /usr/clazzes-ghostscript/bin/gs)
==408615==
==408615==
==408615== HEAP SUMMARY:
==408615== in use at exit: 0 bytes in 0 blocks
==408615== total heap usage: 6,256 allocs, 6,256 frees, 96,871,426 bytes allocated
==408615==
==408615== All heap blocks were freed -- no leaks are possible
==408615==
==408615== Use --track-origins=yes to see where uninitialised values come from
==408615== For lists of detected and suppressed errors, rerun with: -s
==408615== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
This works as expected.
valgrind ghostscript-9.25-7.el8 png16m
This shows, that the crash we observed is related to the pngalpha output device.