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

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

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

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

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

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

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

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

No known CVEs as of 2020-12-27.

CVEs of openjpeg-2.3.1

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

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

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

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

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

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.