Strona główna / Blog / Ghostscript w RHEL 8: regresja po rebase

Blog · analiza

Ghostscript w RHEL 8, CVE-2026-112177: skaner pokazuje CVE-2019-14869 jako naprawione, a paczka znów omija -dSAFER

20 października 2026 Red Hat opublikował CVE-2026-112177 (CVSS 3.1 7.3, „Important”). To nie jest nowy błąd w Ghostscript, tylko błąd w pakiecie. Gdy w RHEL 8 przebudowano Ghostscript z wersji 9.25 do 9.27 (rebase), z pakietu wypadła poprawka CVE-2019-14869 z 2019 roku. W efekcie spreparowany plik PostScript znów może obejść tryb -dSAFER, czytać pliki spoza dozwolonych ścieżek i uruchamiać polecenia. Skaner pokazuje przy tym CVE-2019-14869 jako naprawione, bo numer wersji paczki jest wyższy niż w erracie z 2019 roku. W chwili pisania nie ma erraty, a najnowsza paczka z 15 października nadal ma podatny kod. Ten wpis opisuje, jak traktować status „fixed” w pakietach z backportami i co zrobić do czasu poprawki.

Komponent: Ghostscript w Red Hat Enterprise Linux 8, procedura .charkeys w Resource/Init/gs_ttf.ps (ładowanie fontów TrueType). Według Red Hat VEX dotyczy pakietów ghostscript, libgs, libgs-devel, ghostscript-x11, ghostscript-doc i ghostscript-tools-*.
CVE: CVE-2026-112177. Red Hat: publikacja 20.10.2026 07:04 UTC, Bugzilla 2555564 założony 19.10.2026. NVD: rekord z 20.10.2026 08:16 UTC, status „Received”, bez własnej oceny NVD.
Ocena CNA (Red Hat): CVSS 3.1 7.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L), na stronie Red Hat ze statusem „DRAFT”. Severity Important. CWE-648 (Incorrect Use of Privileged APIs). Wektor i ocena są takie same jak dla CVE-2019-14869 w 2019 roku.
Dotknięte: RHEL 8 „Affected”. RHEL 6, 7, 9 i 10 „Not affected” z uzasadnieniem „Vulnerable Code not Present”.
Poprawka: brak erraty w chwili pisania (20.10.2026). Na stronie CVE lista erraty dla RHEL 8 jest pusta, a VEX ma none_available. Red Hat Security Data API dla tego CVE zwraca jeszcze „Not Found”. Mitygacja według Red Hat: brak takiej, która spełnia jego kryteria.
Threat state: brak w CISA KEV (katalog 2026.10.16). CVE-2019-14869 też tam nie ma. Jedyny wpis Ghostscript w KEV to CVE-2017-8291. Strona Red Hat ma exploit_known: false. Publicznego PoC dla nowego CVE nie znalazłem. Exploity dla błędów -dSAFER w .forceput z 2019 roku są natomiast dobrze opisane, a tu chodzi dokładnie o ten kod.

Co dokładnie zginęło

W listopadzie 2019 Chris Liddell z Artifex usunął .forceput z procedury .charkeys (commit 485904772c5f, „Bug 701841: remove .forceput from /.charkeys”). .forceput to operator uprzywilejowany, który zapisuje do słowników tylko do odczytu, także systemowych. Jeśli skrypt PostScript w trybie -dSAFER zdobędzie do niego dostęp, może wyłączyć ograniczenia i np. otworzyć plik albo pipe do polecenia. Z opisu commita wynika, że dla fontów TrueType .forceput nie był potrzebny, więc zamieniono go na zwykłe put. Red Hat przeniósł tę poprawkę do RHEL 8 w RHSA-2019:3890 (ghostscript-9.25-5.el8_1.1).

Później RHEL 8 dostał rebase do Ghostscript 9.27 (RHSA-2021:1852, ghostscript-9.27-1.el8, maj 2021). Upstreamowe 9.27 to wydanie sprzed poprawki, więc patch z 9.25 trzeba było przenieść na nową bazę. Według Red Hat to się nie stało. Bugzilla 2555564 opisuje to tak: rebase „reintroducing three privileged .forceput calls in the .charkeys procedure”.

Sprawdziłem to na plikach. W libgs-9.25-5.el8_1.1 (CentOS 8.1, vault) plik gs_ttf.ps nie ma ani jednego .forceput. W libgs-9.27-19.el8_10 z AlmaLinux 8, czyli przebudowie najnowszej erraty RHSA-2026:83552 z 15 października 2026, w .charkeys są trzy wywołania .forceput, identyczne jak w upstreamowym tagu ghostpdl-9.27. Binarnej paczki Red Hat nie sprawdzałem, zakładam, że AlmaLinux ma ten sam kod źródłowy. W upstreamie te trzy linie są jeszcze w tagu ghostpdl-9.50, a znikają w ghostpdl-9.51. NVD podaje dla CVE-2019-14869 zakres „before 9.50”. Czy tarball 9.50 różnił się od tagu, nie sprawdzałem.

DataPakiet w RHEL 8Errata.forceput w .charkeysCVE-2019-14869 w skanerze
przed 11.2019ghostscript-9.25-5.el8—obecne (podatny)open
18.11.2019ghostscript-9.25-5.el8_1.1RHSA-2019:38900 (sprawdzone w paczce CentOS 8.1)fixed
18.05.2021ghostscript-9.27-1.el8 (rebase)RHSA-2021:1852według Red Hat poprawka pominiętafixed (EVR wyższy)
15.10.2026ghostscript-9.27-19.el8_10RHSA-2026:835523 (sprawdzone w przebudowie AlmaLinux)fixed (EVR wyższy)
20.10.2026bez zmian, RHEL 8 „Affected”brak3fixed, a obok nowe CVE-2026-112177

Najważniejsza jest ostatnia kolumna. Host, który 15 października zainstalował najnowszą erratę Ghostscript dla RHEL 8, jest „w pełni załatany” według każdego narzędzia, które porównuje wersje z erratą. Mimo to ma ten sam kod, który Red Hat naprawił w 2019 roku.

Dlaczego skaner pokazuje „fixed”

Definicja OVAL dla RHSA-2019:3890 sprawdza, czy zainstalowany ghostscript ma wersję niższą niż 9.25-5.el8_1.1. 9.27-19.el8_10 jest wyższa, więc test zwraca „niepodatny”. To poprawne zachowanie według reguł porównywania wersji RPM (EVR). Problem leży w założeniu, że wyższa wersja zawiera wszystkie wcześniejsze poprawki. Przy zwykłych aktualizacjach tak jest. Przy rebase na nową wersję upstream to założenie trzeba sprawdzić, bo każdą poprawkę przeniesioną wcześniej do starej wersji trzeba przenieść jeszcze raz albo potwierdzić, że upstream ją już ma.

Drugi sygnał też wprowadza w błąd. Changelog paczki ghostscript-9.27-19.el8_10 (przebudowa AlmaLinux, nagłówek RPM) nadal zawiera wpis „CVE-2019-14869 - -dSAFER escape in .charkeys”, bo historia z gałęzi 9.25 została przy rebase zachowana. Kto weryfikuje poprawki przez rpm -q --changelog ghostscript | grep CVE-2019-14869, dostanie trafienie na podatnej paczce. Changelog opisuje historię pakietu, a nie zawartość obecnej wersji.

Nowe CVE-2026-112177 widać tylko w źródłach, które publikują stan „affected bez poprawki”. Red Hat ma je w VEX (CSAF) jako known_affected z none_available. Skaner, który korzysta wyłącznie z OVAL opartego na RHSA, nie zobaczy nowego CVE, dopóki nie będzie erraty. Którzy dostawcy skanerów już pokazują 112177, nie sprawdzałem.

Jak sprawdzić, czy host ma podatny kod

Wersja paczki tu nie pomoże, ale plik, którego dotyczy błąd, leży na dysku. W przebudowie AlmaLinux gs_ttf.ps należy do libgs i nie jest wkompilowany w bibliotekę:

rpm -q ghostscript libgs rpm -qf /usr/share/ghostscript/Resource/Init/gs_ttf.ps grep -cE '\.forceput\s*$' /usr/share/ghostscript/Resource/Init/gs_ttf.ps # 3 = trzy wywołania .forceput w .charkeys (stan 9.27-19.el8_10, podatny) # 0 = stan po poprawce (9.25-5.el8_1.1, upstream 9.51) rpm -V libgs # zmieniony plik pakietu = ktoś go edytował ręcznie

Wynik „3” i „0” to wartości, które zmierzyłem na paczkach AlmaLinux i CentOS oraz w upstreamie. Na binarce Red Hat ich nie sprawdzałem. Komenda to filtr do inwentaryzacji, a nie test exploita. Rocky Linux i Oracle Linux 8 budują Ghostscript z tych samych źródeł, więc najpewniej mają ten sam problem. Ich statusu w trackerach jednak nie weryfikowałem.

Kogo to naprawdę dotyczy

Wektor AV:N/PR:N/UI:N zakłada najgorszy przypadek: serwer, który automatycznie przetwarza PostScript od kogoś z zewnątrz. Red Hat w statement wymienia „document-conversion and printing services”. W praktyce na RHEL 8 Ghostscript wywołują między innymi:

  • konwertery dokumentów i generatory miniatur w aplikacjach, które przyjmują pliki od użytkowników: ImageMagick i GraphicsMagick (delegate gs dla PS, EPS, PDF i XPS), PHP Imagick, skrypty z ps2pdf albo gs;
  • bibliotekę Pillow w Pythonie, która dla EPS uruchamia binarkę gs. To osobny temat, o którym piszemy w innym wpisie: tam problemem jest Pillow, tu paczka systemowa, z której korzysta;
  • filtry drukowania CUPS (ghostscript-tools-printing jest na liście Red Hat), czyli serwery wydruku przyjmujące zadania PostScript;
  • desktopy z podglądem PS i PDF (biblioteka libgs, miniatury w menedżerze plików).

Jedna rzecz zmienia ocenę bardziej niż CVSS. W Ghostscript 9.27 w RHEL 8 tryb SAFER nie jest domyślny. W gs_init.ps z paczki 9.27-19 (przebudowa AlmaLinux) SAFER włącza się tylko, gdy wywołujący poda -dSAFER. Upstream zmienił to w 9.50 i tam SAFER jest domyślny. Wynikają z tego dwa wnioski. Jeśli Twoja aplikacja woła gs bez -dSAFER, CVE-2026-112177 nie ma dla niej znaczenia, bo przetwarza pliki bez sandboxa i od dawna jest wystawiona na wszystko. Jeśli podaje -dSAFER, to właśnie ta ochrona przestała działać.

Czy spreparowany PDF dochodzi do .charkeys, nie potwierdziłem. W Ghostscript 9.27 interpreter PDF jest napisany w PostScript i działa na tej samej maszynerii, więc ostrożnie traktowałbym PDF przekazywany do gs tak samo jak PS i EPS. To moja ocena, Red Hat ani Artifex tego nie piszą.

Co zrobić do czasu erraty

Red Hat nie podaje mitygacji dla tego CVE. Poniższe kontrole to moja propozycja. Część z nich Red Hat opisał w 2018 roku przy CVE-2018-16509 (inny błąd -dSAFER, ten sam wektor), a resztę stosuje się w praktyce przy każdym błędzie Ghostscript.

1. ImageMagick: wyłącz formaty, które idą przez Ghostscript

Przepis Red Hat z CVE-2018-16509 dla policy.xml, w sekcji <policymap>:

<policy domain="coder" rights="none" pattern="PS" /> <policy domain="coder" rights="none" pattern="EPS" /> <policy domain="coder" rights="none" pattern="PDF" /> <policy domain="coder" rights="none" pattern="XPS" /> <policy domain="delegate" rights="none" pattern="gs" />

Red Hat podaje ścieżkę /etc/ImageMagick/policy.xml dla RHEL 6 i 7. ImageMagick dla RHEL 8 to, o ile wiem, paczka z EPEL, nie z repozytoriów Red Hat. Tam plik zwykle leży w /etc/ImageMagick-6/ albo /etc/ImageMagick-7/ (tego nie weryfikowałem). Ścieżkę i działanie sprawdzisz poleceniem convert -list policy albo magick -list policy. Jeśli aplikacja potrzebuje PDF, zostaw tylko PDF i przenieś te konwersje do izolowanego procesu (punkt 3).

2. Nie przyjmuj PS i EPS tam, gdzie nie są potrzebne

Większość aplikacji przyjmujących „obrazki” nie potrzebuje PostScriptu. Filtruj po zawartości, a nie po rozszerzeniu: PostScript zaczyna się od %!, binarny EPS od bajtów C5 D0 D3 C6. W kodzie, który sam wybiera dekoder, ogranicz listę formatów jawnie (w Pillow służy do tego parametr formats w Image.open). Jeśli PS ani EPS nie są potrzebne na serwerze w ogóle, sprawdź rpm -q --whatrequires ghostscript libgs. Może się okazać, że paczkę da się usunąć.

3. Izoluj każde wywołanie Ghostscript

Skoro błąd omija sandbox Ghostscript, granica musi być poza nim. Konwersja powinna działać jako osobny, nieuprzywilejowany użytkownik, bez sieci i bez dostępu do danych aplikacji. Przykład z systemd-run:

systemd-run --wait --pipe -p DynamicUser=yes -p PrivateNetwork=yes \ -p ProtectSystem=strict -p ProtectHome=yes -p PrivateTmp=yes \ -p NoNewPrivileges=yes -p ReadWritePaths=/var/spool/konwersje \ gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=png16m \ -sOutputFile=/var/spool/konwersje/out.png /var/spool/konwersje/in.ps

Ten sam efekt da kontener bez sieci z katalogiem roboczym jako jedynym wolumenem albo sandbox z policycoreutils-sandbox (Red Hat poleca go przy CVE-2018-16509 dla przeglądarek PDF/PS). Komendę napisałem jako przykład i nie testowałem jej na exploicie. Niezależnie od izolacji dopisz -dSAFER do każdego wywołania, w którym go nie ma, bo w 9.27 w RHEL 8 nie jest domyślny.

4. Zobacz, kto naprawdę uruchamia gs

auditctl -w /usr/bin/gs -p x -k ghostscript-exec ausearch -k ghostscript-exec --format text

Po kilku dniach będziesz wiedzieć, które usługi wywołują Ghostscript i z jakimi argumentami. Uruchomienie gs przez proces aplikacji webowej bez -dSAFER to finding sam w sobie, niezależnie od tego CVE. Pamiętaj, że to obejmuje tylko binarkę. Programy linkowane z libgs się tu nie pojawią.

Czego bym nie robił

Poprawka upstream to zamiana trzech .forceput na put w pliku tekstowym, więc kusi, żeby ją wprowadzić ręcznie. Nie polecam tego jako rozwiązania. Plik należy do pakietu, więc rpm -V zgłosi zmianę, a najbliższa aktualizacja ją nadpisze. Nie wiadomo też, czy w paczce 9.27 nie brakuje czegoś więcej. Jeśli ktoś mimo to to zrobi, niech zapisze to jako tymczasową kontrolę kompensującą z datą wygaśnięcia i wyjątkiem dla rpm -V.

Jak VM ma traktować „naprawione” CVE w pakietach z backportami

Ten przypadek jest odwrotnością sytuacji, którą opisywałem przy BIND 9.18 w Ubuntu. Tam numer upstreamu był niższy, niż „powinien”, a paczka była naprawiona. Tutaj numer jest wyższy, a paczka nie jest naprawiona. Najbliższy jest OpenSSL w Ubuntu 26.04, gdzie status „Patched” był błędny, bo poprawka nie trafiła do paczki. Z Ghostscript wynikają cztery zasady:

  1. „Fixed” to stan konkretnej wersji paczki, a nie trwała cecha CVE. W rejestrze podatności zapisuj, w której wersji (EVR) i na podstawie jakiego źródła uznano CVE za zamknięte. Gdy wersja się zmienia w sposób, który nie jest zwykłą aktualizacją, ta decyzja wymaga ponownego sprawdzenia.
  2. Rebase to zdarzenie, które unieważnia stare backporty. Jeśli changelog paczki zawiera „Rebase to X”, lista CVE naprawionych w poprzedniej gałęzi to lista do weryfikacji, a nie do skopiowania. Dla krytycznych komponentów (parsery plików, kryptografia, interpretery) warto mieć prostą listę „kod poprawki obecny” per CVE, jak grep powyżej.
  3. Korzystaj z VEX, a nie tylko z OVAL opartego na errata. OVAL z RHSA pokazuje tylko to, co już naprawiono. Stan „affected bez poprawki” jest w CSAF VEX Red Hat. Bez niego CVE-2026-112177 w ogóle nie trafi do kolejki, dopóki nie będzie erraty.
  4. Stare PoC to testy regresji. Jeśli przetwarzasz niezaufane PostScript na dużą skalę, publiczne PoC dla -dSAFER z lat 2018–2019 uruchamiane w odizolowanym środowisku na każdej nowej paczce wykryłyby ten błąd w 2021 roku, a nie w 2026.

Co powinien zrobić VE

(1) Znajdź hosty RHEL 8 i klony z ghostscript albo libgs i sprawdź gs_ttf.ps grepem. Wersja paczki niczego tu nie powie. (2) Ustal, które z nich przetwarzają pliki z zewnątrz: aplikacje z uploadem, konwertery, serwery wydruku. To one dostają priorytet, reszta czeka na erratę. (3) Na hostach z priorytetem wprowadź policy.xml, blokadę PS/EPS i izolację konwersji. Dopisz -dSAFER wszędzie tam, gdzie go nie ma. (4) Zostaw CVE-2019-14869 w rejestrze jako zamknięte, ale z notatką, że na RHEL 8 z 9.27 jest ponownie otwarte jako CVE-2026-112177. Inaczej ktoś za rok zamknie nowe CVE, widząc stare „fixed”. (5) Obserwuj stronę CVE Red Hat i wróć do tematu, gdy pojawi się RHSA dla ghostscript w RHEL 8. (6) Tam, gdzie to możliwe, planuj migrację do RHEL 9 lub 10, które według Red Hat nie mają podatnego kodu.

Powiązane na blogu

Źródła

  • Red Hat — CVE-2026-112177 (CVSS, severity Important, statement, mitigation, stany produktów) — access.redhat.com
  • Red Hat Bugzilla — 2555564 (CVE-2026-112177, „Reintroduction of .charkeys -dSAFER bypass in RHEL 8”) — bugzilla.redhat.com
  • Red Hat CSAF VEX — cve-2026-112177.json (known_affected RHEL 8, none_available) — security.access.redhat.com
  • NVD — CVE-2026-112177 — nvd.nist.gov
  • ghostpdl — commit 485904772c5f „Bug 701841: remove .forceput from /.charkeys” (5.11.2019) — github.com
  • Ghostscript Bugzilla — 701841 — bugs.ghostscript.com
  • Red Hat — CVE-2019-14869 (RHSA-2019:3888, RHSA-2019:3890, RHSA-2020:0222) — access.redhat.com
  • NVD — CVE-2019-14869 — nvd.nist.gov
  • Red Hat — RHSA-2019:3890 (ghostscript-9.25-5.el8_1.1) — access.redhat.com
  • Red Hat — RHSA-2021:1852 (rebase do ghostscript-9.27-1.el8) — access.redhat.com
  • Red Hat — RHSA-2026:83552 (ghostscript-9.27-19.el8_10, 15.10.2026) — access.redhat.com
  • Red Hat — CVE-2018-16509 (mitygacja: policy.xml ImageMagick, evince-thumbnailer, SELinux sandbox) — access.redhat.com
  • AlmaLinux 8 AppStream — paczki ghostscript i libgs 9.27-19.el8_10 (analiza gs_ttf.ps, gs_init.ps i changelogu) — repo.almalinux.org
  • CentOS vault 8.1.1911 — libgs-9.25-5.el8_1.1 (analiza gs_ttf.ps) — vault.centos.org
  • CISA Known Exploited Vulnerabilities Catalog (brak CVE-2026-112177 i CVE-2019-14869 w wersji 2026.10.16) — cisa.gov

Nota redakcyjna: stan informacji 20 października 2026, ok. 13:30 CEST. Podstawa: strona CVE-2026-112177 w Red Hat Customer Portal (severity Important, CVSS 3.1 7.3 ze statusem DRAFT, statement, tekst mitygacji, stany produktów, data publikacji 20.10.2026 07:04 UTC), Red Hat CSAF VEX dla tego CVE, Red Hat Security Data API (CVE-2026-112177 jeszcze „Not Found”, CVE-2019-14869, erraty RHSA-2019:3890, RHSA-2021:1852 i RHSA-2026:83552), Bugzilla 2555564, rekordy NVD dla CVE-2026-112177 i CVE-2019-14869, commit ghostpdl 485904772c5f i pliki gs_ttf.ps oraz gs_init.ps w tagach ghostpdl-9.27, 9.50 i 9.51, a także katalog CISA KEV w wersji 2026.10.16. Liczbę wywołań .forceput, domyślny stan SAFER i wpis w changelogu sprawdziłem w paczkach AlmaLinux 8 (libgs i ghostscript 9.27-19.el8_10) i CentOS 8.1 (libgs-9.25-5.el8_1.1), a nie w binarkach Red Hat. Zgodność z RHEL to moje założenie. Niepotwierdzone: numer i data erraty z poprawką (w chwili pisania brak), status Rocky Linux i Oracle Linux 8, to, czy rebase 9.27-1.el8 był pierwszą podatną wersją, zawartość tarballa 9.50 w porównaniu z tagiem, możliwość dojścia do .charkeys przez spreparowany PDF, istnienie publicznego PoC i eksploatacji dla CVE-2026-112177, ścieżki policy.xml w ImageMagick z EPEL i to, które skanery już pokazują nowe CVE. Komendy grep, systemd-run i auditctl to przykłady autora, nietestowane na exploicie. Ocena ekspozycji, uwaga o PDF, zasady dla VM i lista „Co powinien zrobić VE” to oceny autora, nie ustalenia Red Hat ani Artifex.

Zapamiętaj jedno

CVE-2026-112177 to stara podatność CVE-2019-14869, która wróciła do RHEL 8, bo przy rebase Ghostscript 9.25→9.27 pominięto poprawkę. Skaner pokaże stare CVE jako „fixed”, bo numer wersji jest wyższy, a changelog nadal je wymienia. Najnowsza paczka 9.27-19.el8_10 ma jednak trzy .forceput w .charkeys, a erraty jeszcze nie ma. Sprawdzaj kod, nie numer wersji: grep po gs_ttf.ps. Do czasu poprawki zablokuj PS/EPS w policy.xml, izoluj konwersje i dopisz -dSAFER, bo w RHEL 8 nie jest domyślny. Po każdym rebase traktuj stare backporty jako niesprawdzone.