diff --git a/0001-Bug-705911-Fix-Ghostscript-s-encoding-decoding-of-UT.patch b/0001-Bug-705911-Fix-Ghostscript-s-encoding-decoding-of-UT.patch new file mode 100644 index 0000000..36b70b2 --- /dev/null +++ b/0001-Bug-705911-Fix-Ghostscript-s-encoding-decoding-of-UT.patch @@ -0,0 +1,239 @@ +From 4fcf527584da20538ebf9c3c43c3fda25d97cd18 Mon Sep 17 00:00:00 2001 +From: Robin Watts +Date: Tue, 4 Oct 2022 17:36:56 +0100 +Subject: [PATCH] Bug 705911: Fix Ghostscript's encoding/decoding of UTF-8 from + UTF-16. + +We were not coping with high/low surrogate pairs in UTF-16, +meaning that we could encode/decode strings fine for our own +purposes, but when we passed them off to other users (such +as SmartOffice), it would fail to understand our utf-8 encoded +surrogate pairs. + +Thanks to Pete, Joseph and Fred for their help here, and to Silver +for having spotted it! +--- + base/gp_wutf8.c | 162 +++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 127 insertions(+), 35 deletions(-) + +diff --git a/base/gp_wutf8.c b/base/gp_wutf8.c +index b7b1d0758..920114cd1 100644 +--- a/base/gp_wutf8.c ++++ b/base/gp_wutf8.c +@@ -16,6 +16,56 @@ + + #include "windows_.h" + ++static int ++decode_utf8(const char **inp, unsigned int i) ++{ ++ const char *in = *inp; ++ unsigned char c; ++ ++ if (i < 0x80) { ++ } else if ((i & 0xE0) == 0xC0) { ++ i &= 0x1F; ++ c = (unsigned char)*in++; ++ if ((c & 0xC0) != 0x80) ++ goto fail; ++ i = (i<<6) | (c & 0x3f); ++ } else if ((i & 0xF0) == 0xE0) { ++ i &= 0xF; ++ c = (unsigned char)*in++; ++ if ((c & 0xC0) != 0x80) ++ goto fail; ++ i = (i<<6) | (c & 0x3f); ++ c = (unsigned char)*in++; ++ if ((c & 0xC0) != 0x80) ++ goto fail; ++ i = (i<<6) | (c & 0x3f); ++ } else if ((i & 0xF8) == 0xF0) { ++ i &= 0x7; ++ c = (unsigned char)*in++; ++ if ((c & 0xC0) != 0x80) ++ goto fail; ++ i = (i<<6) | (c & 0x3f); ++ c = (unsigned char)*in++; ++ if ((c & 0xC0) != 0x80) ++ goto fail; ++ i = (i<<6) | (c & 0x3f); ++ c = (unsigned char)*in++; ++ if ((c & 0xC0) != 0x80) ++ goto fail; ++ i = (i<<6) | (c & 0x3f); ++ } ++ if (0) ++ { ++ /* If we fail, unread the last one, and return the unicode replacement char. */ ++fail: ++ in--; ++ i = 0xfffd; ++ } ++ *inp = in; ++ ++ return i; ++} ++ + int utf8_to_wchar(wchar_t *out, const char *in) + { + unsigned int i; +@@ -24,47 +74,37 @@ int utf8_to_wchar(wchar_t *out, const char *in) + + if (out) { + while (i = *(unsigned char *)in++) { +- if (i < 0x80) { +- *out++ = (wchar_t)i; +- len++; +- } else if ((i & 0xE0) == 0xC0) { +- i &= 0x1F; +- c = (unsigned char)*in++; +- if ((c & 0xC0) != 0x80) +- return -1; +- i = (i<<6) | (c & 0x3f); +- *out++ = (wchar_t)i; +- len++; +- } else if ((i & 0xF0) == 0xE0) { +- i &= 0xF; +- c = (unsigned char)*in++; +- if ((c & 0xC0) != 0x80) +- return -1; +- i = (i<<6) | (c & 0x3f); +- c = (unsigned char)*in++; +- if ((c & 0xC0) != 0x80) +- return -1; +- i = (i<<6) | (c & 0x3f); +- *out++ = (wchar_t)i; ++ /* Decode UTF-8 */ ++ i = decode_utf8(&in, i); ++ ++ /* Encode, allowing for surrogates. */ ++ if (i >= 0x10000 && i <= 0x10ffff) ++ { ++ i -= 0x10000; ++ *out++ = 0xd800 + (i>>10); ++ *out++ = 0xdc00 + (i & 0x3ff); + len++; +- } else { ++ } ++ else if (i > 0x10000) ++ { + return -1; + } ++ else ++ *out++ = (wchar_t)i; ++ len++; + } + *out = 0; + } else { + while (i = *(unsigned char *)in++) { +- if (i < 0x80) { +- len++; +- } else if ((i & 0xE0) == 0xC0) { +- in++; +- len++; +- } else if ((i & 0xF0) == 0xE0) { +- in+=2; ++ /* Decode UTF-8 */ ++ i = decode_utf8(&in, i); ++ ++ /* Encode, allowing for surrogates. */ ++ if (i >= 0x10000 && i <= 0x10ffff) + len++; +- } else { ++ else if (i > 0x10000) + return -1; +- } ++ len++; + } + } + return len; +@@ -74,9 +114,32 @@ int wchar_to_utf8(char *out, const wchar_t *in) + { + unsigned int i; + unsigned int len = 1; ++ int hi = -1; + + if (out) { + while (i = (unsigned int)*in++) { ++ /* Decode surrogates */ ++ if (i >= 0xD800 && i <= 0xDBFF) ++ { ++ /* High surrogate. Must be followed by a low surrogate, or this is a failure. */ ++ int hi = i & 0x3ff; ++ int j = (unsigned int)*in++; ++ if (j == 0 || (j <= 0xDC00 || j >= 0xDFFF)) ++ { ++ /* Failure! Unicode replacement char! */ ++ in--; ++ i = 0xfffd; ++ } else { ++ /* Decode surrogates */ ++ i = 0x10000 + (hi<<10) + (j & 0x3ff); ++ } ++ } else if (i >= 0xDC00 && i <= 0xDFFF) ++ { ++ /* Lone low surrogate. Failure. Unicode replacement char. */ ++ i = 0xfffd; ++ } ++ ++ /* Encode output */ + if (i < 0x80) { + *out++ = (char)i; + len++; +@@ -84,22 +147,51 @@ int wchar_to_utf8(char *out, const wchar_t *in) + *out++ = 0xC0 | ( i>> 6 ); + *out++ = 0x80 | ( i & 0x3F); + len+=2; +- } else /* if (i < 0x10000) */ { ++ } else if (i < 0x10000) { + *out++ = 0xE0 | ( i>>12 ); + *out++ = 0x80 | ((i>> 6) & 0x3F); + *out++ = 0x80 | ( i & 0x3F); + len+=3; ++ } else { ++ *out++ = 0xF0 | ( i>>18 ); ++ *out++ = 0x80 | ((i>>12) & 0x3F); ++ *out++ = 0x80 | ((i>> 6) & 0x3F); ++ *out++ = 0x80 | ( i & 0x3F); ++ len+=4; + } + } + *out = 0; + } else { + while (i = (unsigned int)*in++) { ++ /* Decode surrogates */ ++ if (i >= 0xD800 && i <= 0xDBFF) ++ { ++ /* High surrogate. Must be followed by a low surrogate, or this is a failure. */ ++ int hi = i & 0x3ff; ++ int j = (unsigned int)*in++; ++ if (j == 0 || (j <= 0xDC00 || j >= 0xDFFF)) ++ { ++ /* Failure! Unicode replacement char! */ ++ in--; ++ i = 0xfffd; ++ } else { ++ /* Decode surrogates */ ++ i = 0x10000 + (hi<<10) + (j & 0x3ff); ++ } ++ } else if (i >= 0xDC00 && i <= 0xDFFF) ++ { ++ /* Lone low surrogate. Failure. Unicode replacement char. */ ++ i = 0xfffd; ++ } ++ + if (i < 0x80) { + len++; + } else if (i < 0x800) { + len += 2; +- } else /* if (i < 0x10000) */ { ++ } else if (i < 0x10000) { + len += 3; ++ } else { ++ len += 4; + } + } + } +-- +2.49.0 + diff --git a/0001-Bug-707788-Fix-decode_utf8-to-forbid-overlong-encodi.patch b/0001-Bug-707788-Fix-decode_utf8-to-forbid-overlong-encodi.patch new file mode 100644 index 0000000..078a505 --- /dev/null +++ b/0001-Bug-707788-Fix-decode_utf8-to-forbid-overlong-encodi.patch @@ -0,0 +1,42 @@ +diff --git a/base/gp_wutf8.c b/base/gp_wutf8.c +index 56bedc1..23fcdd1 100644 +--- a/base/gp_wutf8.c ++++ b/base/gp_wutf8.c +@@ -25,12 +25,16 @@ decode_utf8(const char **inp, unsigned int i) + if (i < 0x80) { + } else if ((i & 0xE0) == 0xC0) { + i &= 0x1F; ++ if (i == 0) ++ goto fail_overlong; + c = (unsigned char)*in++; + if ((c & 0xC0) != 0x80) + goto fail; + i = (i<<6) | (c & 0x3f); + } else if ((i & 0xF0) == 0xE0) { + i &= 0xF; ++ if (i == 0) ++ goto fail_overlong; + c = (unsigned char)*in++; + if ((c & 0xC0) != 0x80) + goto fail; +@@ -41,6 +45,8 @@ decode_utf8(const char **inp, unsigned int i) + i = (i<<6) | (c & 0x3f); + } else if ((i & 0xF8) == 0xF0) { + i &= 0x7; ++ if (i == 0) ++ goto fail_overlong; + c = (unsigned char)*in++; + if ((c & 0xC0) != 0x80) + goto fail; +@@ -59,6 +65,11 @@ decode_utf8(const char **inp, unsigned int i) + /* If we fail, unread the last one, and return the unicode replacement char. */ + fail: + in--; ++fail_overlong: ++ /* If we jump to here it's because we've detected an 'overlong' encoding. ++ * While this seems harmless, it's actually illegal, for good reason; ++ * this is typically an attempt to sneak stuff past security checks, like ++ * "../" in paths. Fail this. */ + i = 0xfffd; + } + *inp = in; diff --git a/ghostscript.spec b/ghostscript.spec index 651ce8c..549dfc8 100644 --- a/ghostscript.spec +++ b/ghostscript.spec @@ -122,9 +122,16 @@ Patch014: gs-CVE-2024-33869.patch # RHEL-44731 CVE-2024-29510 ghostscript: format string injection leads to shell command execution (SAFER bypass) Patch015: 0001-Uniprint-device-prevent-string-configuration-changes.patch # RHEL-18397 CVE-2023-46751 ghostscript: dangling pointer in gdev_prn_open_printer_seekable() +# partially taken from https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=dcdbc595c13c9 Patch016: gs-cve-2023-46751.patch # RHEL-67048 CVE-2024-46951 ghostscript: Arbitrary Code Execution in Artifex Ghostscript Pattern Color Space +# https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=f49812186baa7 Patch017: 0001-PS-interpreter-check-the-type-of-the-Pattern-Impleme.patch +# RHEL-67053 CVE-2024-46954 ghostscript: Directory Traversal in Ghostscript via Overlong UTF-8 Encoding +# implementing decode_utf8() https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=4fcf527584da2053 +# CVE fix, updated for gp_wutf8() in 9.27 https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=282f691f5e57b6b +Patch031: 0001-Bug-705911-Fix-Ghostscript-s-encoding-decoding-of-UT.patch +Patch032: 0001-Bug-707788-Fix-decode_utf8-to-forbid-overlong-encodi.patch # Downstream patches -- these should be always included when doing rebase: # ------------------ @@ -461,6 +468,7 @@ done * Tue Apr 15 2025 Zdenek Dohnal - 9.54.0-18 - RHEL-18397 CVE-2023-46751 ghostscript: dangling pointer in gdev_prn_open_printer_seekable() - RHEL-67048 CVE-2024-46951 ghostscript: Arbitrary Code Execution in Artifex Ghostscript Pattern Color Space +- RHEL-67053 CVE-2024-46954 ghostscript: Directory Traversal in Ghostscript via Overlong UTF-8 Encoding * Mon Jul 08 2024 Zdenek Dohnal - 9.54.0-17 - RHEL-44759 CVE-2024-33870 ghostscript: path traversal to arbitrary files if the current directory is in the permitted paths