You've already forked libjpeg-turbo
mirror of
https://github.com/libjpeg-turbo/libjpeg-turbo.git
synced 2026-10-23 11:48:53 +03:00
jpeg_crop_scanline() doesn't actually work with raw data output. If
buffered-image mode is disabled and raw data output is enabled, the
function throws JERR_BAD_STATE because the global state is DSTATE_RAW_OK
rather than DSTATE_SCANNING. However, due to an oversight in
8162eddf04 (libjpeg-turbo 2.1.4), enabling
both buffered-image mode and raw data output allowed the caller to sneak
through the gates. Thus, executing the following sequence with the same
libjpeg API instance caused a use-after-free issue:
- jpeg_start_decompress(&cinfo)
* calls j*init_upsampler() to allocate the upsampler (cinfo.upsample)
- jpeg_abort_decompress(&cinfo)
* frees the upsampler
- cinfo.raw_data_out = TRUE
- cinfo.buffered_image = TRUE
- jpeg_start_decompress(&cinfo)
* does not call j*init_upsampler(), because cinfo.raw_data_out == TRUE
- jpeg_crop_scanline(&cinfo, &xoffset, &width)
where xoffset and width would cause any of the component planes to be
cropped to a width of 1 sample
* fails to catch that raw data output is enabled, because the global
state is DSTATE_BUFIMAGE rather than DSTATE_RAW_OK
* fails to catch that the previous decompression operation was
aborted, because cinfo->output_scanline is 0 (since
jpeg*_read_scanlines() was never called)
* calls j*init_upsampler() with
cinfo->master->jinit_upsampler_no_alloc == TRUE, which tells
j*init_upsampler() to reuse the upsampler
* j*init_upsampler() tries to reuse the upsampler that has already
been freed.
Any application that did this could never work properly. (The best it
could hope for is a bogus output image or an error.) Thus, this
represented an opportunity for API hardening rather than a security
vulnerability.
This commit also modifies the jpeg_crop_scanline() documentation to
clarify that the function doesn't work with raw data output.
(Previously, the documentation was subtle on that point. It says that
jpeg_crop_scanline() must be called between jpeg_start_decompress() and
jpeg*_read_scanlines(), which implies that it can't be called between
jpeg_start_decompress() and jpeg*_read_raw_data().)