Dekoder kafelkowanych obrazów TIFF w Pillow odczytuje dane poza buforem kafelka w copy4 (Unpack.c:1290)
Podsumowanie
Dekoder _decodeTile w libImaging biblioteki Pillow, służący do dekodowania kafelkowanych obrazów TIFF, alokuje bufor dla każdego kafelka za pomocą realloc(state->buffer, TIFFTileSize(tiff)). Po każdym wywołaniu TIFFReadTile wykonuje iterację zmiennej tile_y od 0 do current_tile_length i wywołuje skonfigurowany mechanizm rozpakowywania wierszy (tutaj copy4) ze wskaźnikiem źródłowym state->buffer + tile_y * row_byte_size. Kiedy libtiff zwraca wartość tile_bytes_size mniejszą niż pesymistyczny przypadek row_byte_size * tile_length, wewnętrzna pętla kroku i kopiowania wykracza poza realokowany obszar, a funkcja copy4 wykonuje operację memcpy o wielkości 1024 bajtów, która odczytuje do (tile_length-1) * row_byte_size + row_byte_size bajtów z bufora o rozmiarze zaledwie tile_bytes_size. Dostarczony plik PoC TIFF wywołuje odczyt poza zakresem o wielkości 1024 bajtów dokładnie 0 bajtów za alokacją wynoszącą 196608 bajtów. Osoba atakująca, która nakłoni aplikację korzystającą z Pillow do zdekodowania spreparowanego pliku TIFF, może spowodować awarię procesu (DoS) oraz doprowadzić do skopiowania sąsiadującej pamięci sterty do zdekodowanego bufora pikseli.
Szczegóły
Gdy libtiff zgłasza, że plik jest kafelkowany, dekoder TIFF w Pillow wybiera ścieżkę _decodeTile. Funkcja ta:
- Odpytuje libtiff o
TIFFTileSize(tiff)(liczbę bajtów na kafelek) orazTIFFTileRowSize(tiff)(liczbę bajtów na wiersz w postaci zapisanej przez libtiff). - Realokuje
state->bufferdo dokładnietile_bytes_size. - Dla każdego punktu początkowego kafelka
(x, y)i każdej płaszczyzny wywołujeTIFFReadTiledostate->buffer, a następnie przetwarza kafelek wiersz po wierszu, wywołując skonfigurowanyImagingShuffler(tutajcopy4) dla porcji bajtów źródłowych każdego wiersza.
Weryfikacja przeprowadzana przed pętlą ma postać:
if (tile_bytes_size > ((tile_length * state->bits / planes + 7) / 8) * tile_width) {
state->errcode = IMAGING_CODEC_BROKEN;
return -1;
}
Odrzuca ona zbyt duże kafelki libtiff, jednak nie odrzuca kafelków zbyt małych — tj. sytuacji, gdy libtiff zwraca wartość tile_bytes_size ściśle mniejszą niż row_byte_size * tile_length. Ciało pętli indeksuje bufor przy założeniu, że ma on co najmniej row_byte_size * tile_length bajtów długości.
Podatny kod
// src/libImaging/TiffDecode.c:446-490 — _decodeTile
new_data = realloc(state->buffer, state->bytes); // bytes = tile_bytes_size
if (!new_data) { ... }
state->buffer = new_data;
for (y = state->yoff; y < state->ysize; y += tile_length) {
for (plane = 0; plane < planes; plane++) {
ImagingShuffler shuffler = unpackers[plane];
for (x = state->xoff; x < state->xsize; x += tile_width) {
if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { ... }
current_tile_width = min((INT32)tile_width, state->xsize - x);
current_tile_length = min((INT32)tile_length, state->ysize - y);
for (tile_y = 0; tile_y < current_tile_length; tile_y++) {
shuffler(
(UINT8 *)im->image[tile_y + y] + x * im->pixelsize,
state->buffer + tile_y * row_byte_size, // <-- OOB stride
current_tile_width
);
}
}
}
}
// src/libImaging/Unpack.c:1288-1291 — copy4 (the crash site)
static void
copy4(UINT8 *out, const UINT8 *in, int pixels) {
/* RGBA, CMYK quadruples */
memcpy(out, in, 4 * pixels); // <-- ASAN-detected READ here
}
Metadane kafelka w PoC dają tile_width = tile_length = 256, row_byte_size = 1024 (4 bajtów/piksel × 256 pikseli) oraz tile_bytes_size = 196608 (co daje 256·256·3 = trzykanałowy magazyn bajtów). Realokowany bufor ma rozmiar 196608 bajtów. Mechanizm rozpakowywania iteruje tile_y od 0 do 255, a dla najwyższych wierszy wskaźnik źródłowy state->buffer + tile_y * 1024 znajduje się już na poziomie przesunięcia 196608 lub poza nim — wywołanie memcpy(in=buffer+255·1024, 1024) dla ostatniego wiersza odczytuje 1024 bajtów, zaczynając 260096 - 196608 = 63488 bajtów za alokacją; ASAN zgłasza już pierwszy bajt poza obszarem sterty (READ of size 1024 at … 0 bytes after 196608-byte region).
Niezgodność jest faktyczna: funkcja TIFFTileSize w libtiff zwraca spakowany rozmiar kafelka (który zależy od układu fotometrycznego/separacji w pliku — może być zgodnie ze standardem mniejszy niż row_byte_size × tile_length), podczas gdy pętla wewnętrzna przesuwa się tak, jakby bufor zawsze był równy row_byte_size × tile_length.
Źródło
Problem ten został znaleziony przez firmę Anthropic przy użyciu modelu Claude do badania bezpieczeństwa projektów open source, a ja reprezentuję Ada Logics, pomagając w weryfikacji znalezionych problemów i zgłaszaniu ich twórcom oprogramowania. Dane zawarte w tym raporcie zostały sprawdzone ręcznie.
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 | >= 8.2.0, < 13.0.0 | 13.0.0 |
Odnośniki
- https://github.com/python-pillow/Pillow/security/advisories/GHSA-462x-pgg6-55fp
- https://nvd.nist.gov/vuln/detail/CVE-2026-112395
- https://github.com/python-pillow/Pillow/commit/76869efdbbf2ad7dccd7536520fb61b7a00ab61e
- https://github.com/python-pillow/Pillow
- https://github.com/python-pillow/Pillow/releases/tag/13.0.0
- Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L- Słabość (CWE)
CWE-122- Platforma
- Python (PyPI)
- Paczka
pillow- Ujawniono
- 20.10.2026
- Aktualizacja
- 20.10.2026 23:28
Źródła i licencje · Redakcja lub tłumaczenie: DockRay. Zachowano prawa źródeł i obowiązujące licencje.
OSV / GitHub Advisory Database - GHSA-462x-pgg6-55fp - 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
- 81
- Pierwsza → ostatnia
- 04.2014 10.2026
- Bez poprawki
- 0
- Wykorzystywana w atakach
- 1
Rozkład istotności
- Krytyczna 10
- Wysoka 53
- Średnia 16
- 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: 23
wcześniej: 12
-
Dekoder kafelkowanych obrazów TIFF w Pillow odczytuje dane poza buforem kafelka w copy4 (Unpack.c:1290) 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.