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

Library Name

Version

Function

License

URL

eXpat

2.2.9

XML parsing for XPS interpreter

MIT/eXpat License

http://expat.sourceforge.net/

FreeType

2.10.1

Font scaling and rendering for Ghostscript

FreeType License
(BSD-style license with a credit clause)

http://www.freetype.org/

jbig2dec

0.17

JBIG2 decoding for the PDF interpreter

Licensed with Ghostscript/GhostPDL
(copyright owned by Artifex)

http://www.ghostscript.com/

libjpeg

9c
with patches

JPEG/DCT decoding/encoding

"Free"
Can be used in commercial applications without royalty, with acknowledgement.

http://www.ijg.org/

LittleCMS 2 mt
(lcms2mt – thread save fork of lcms2)

2.9mt

ICC profile based color conversion and management

MIT LICENSE

http://www.ghostscript.com/

libpng

1.6.37

PNG image encoding/decoding.

libpng license
classified as "a permissive free software license"

http://www.libpng.org/

OpenJPEG

2.3.1

JPEG2000 image decoding for the PDF interpreter

BSD-style

http://www.openjpeg.org/

libtiff

4.1.0

TIFF image encoding/decoding

BSD-style

http://www.remotesensing.org/libtiff/

zlib

1.2.11

(De)Flate compression

zlib License
classified as "a permissive free software license"

http://www.zlib.net/

Review of CVEs

CVEs of ghostscript-9.53.3

Query:

https://nvd.nist.gov/vuln/search/results?form_type=Basic&results_type=overview&query=ghostscript&search_type=last3years

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

https://nvd.nist.gov/vuln/search/results?form_type=Basic&results_type=overview&query=expat&search_type=last3years

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

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

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

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

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.