tj3Transform(): Ensure JPEG hdr successfully read
Because of the TurboJPEG 3 API overhaul, the legacy decompression and lossless transformation functions now wrap the new TurboJPEG 3 functions. For performance reasons, we don't want to read the JPEG header more than once during the same operation, so the wrapped functions do not read the header if it has already been read by a wrapper function. Initially the TurboJPEG 3 functions used a state variable to track whether the header had already been read, butb94041390cmade this more robust by using the libjpeg global decompression state instead. If a wrapper function has already read the JPEG header successfully, then the global decompression state will be DSTATE_READY, and the logic introduced inb94041390cwill prevent the header from being read again. A subtle issue arises because tj3DecompressHeader() does not call jpeg_abort_decompress() if jpeg_read_header() fails. (That is arguably a bug, but it has existed since the very first implementation of the function.) Depending on the nature of the failure, this can cause tj3DecompressHeader() to return an error code and leave the libjpeg global decompression state set to DSTATE_INHEADER. If a misbehaved application ignored the error and subsequently called a TurboJPEG decompression or lossless transformation function, then the function would fail to read the JPEG header because the global decompression state was greater than DSTATE_START. In the case of the decompression functions, this was innocuous, because jpeg_calc_output_dimensions() and jpeg_start_decompress() both sanity check the global decompression state. However, it was possible for a misbehaved application to call tj3DecompressHeader() with junk data, ignore the return value, and pass the same junk data into tj3Transform(). Because tj3DecompressHeader() left the global decompression state set to DSTATE_INHEADER, tj3Transform() failed to detect the junk data (because it didn't try to read the JPEG header), and it called jtransform_request_workspace() with dinfo->image_width and dinfo->image_height still initialized to 0. Because jtransform_request_workspace() does not sanity check the decompression state, a division-by-zero error occurred with certain combinations of transform options in which TJXOPT_TRIM or TJXOPT_CROP was specified. However, it should be noted that TJXOPT_TRIM and TJXOPT_CROP cannot be expected to work properly without foreknowledge of the JPEG source image dimensions, which cannot be gained except by calling tj3DecompressHeader() successfully. Thus, a calling application is inviting trouble if it does not check the return value of tj3DecompressHeader() and sanity check the JPEG source image dimensions before calling tj3Transform(). This commit softens the failure, but the failure is still due to improper API usage.
This commit is contained in:
@@ -174,7 +174,7 @@ DLLEXPORT int GET_NAME(tj3Decompress, BITS_IN_JSAMPLE)
|
||||
retval = -1; goto bailout;
|
||||
}
|
||||
|
||||
if (dinfo->global_state <= DSTATE_START) {
|
||||
if (dinfo->global_state <= DSTATE_INHEADER) {
|
||||
jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
|
||||
jpeg_read_header(dinfo, TRUE);
|
||||
}
|
||||
|
||||
@@ -2345,7 +2345,7 @@ DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
|
||||
retval = -1; goto bailout;
|
||||
}
|
||||
|
||||
if (dinfo->global_state <= DSTATE_START) {
|
||||
if (dinfo->global_state <= DSTATE_INHEADER) {
|
||||
jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
|
||||
jpeg_read_header(dinfo, TRUE);
|
||||
}
|
||||
@@ -2536,7 +2536,7 @@ DLLEXPORT int tj3DecompressToYUV8(tjhandle handle,
|
||||
retval = -1; goto bailout;
|
||||
}
|
||||
|
||||
if (dinfo->global_state <= DSTATE_START) {
|
||||
if (dinfo->global_state <= DSTATE_INHEADER) {
|
||||
jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
|
||||
jpeg_read_header(dinfo, TRUE);
|
||||
}
|
||||
@@ -2683,7 +2683,7 @@ DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
|
||||
retval = -1; goto bailout;
|
||||
}
|
||||
|
||||
if (dinfo->global_state <= DSTATE_START)
|
||||
if (dinfo->global_state <= DSTATE_INHEADER)
|
||||
jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
@@ -2711,7 +2711,7 @@ DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
|
||||
}
|
||||
|
||||
jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
|
||||
if (dinfo->global_state <= DSTATE_START)
|
||||
if (dinfo->global_state <= DSTATE_INHEADER)
|
||||
jpeg_read_header(dinfo, TRUE);
|
||||
this->subsamp = getSubsamp(&this->dinfo);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user