JNI: Guard against int overflow w/ huge X, Y vals

This is not a security vulnerability, since applications that pass such
values to the Java API would fail regardless, and such a bug would never
make it into the wild.  By contrast, a security vulnerability arises
from applications that work correctly with most input data sets but
trigger a library failure, such as a buffer overrun, with one or more
specific input data sets.  As with most imaging APIs, the libjpeg-turbo
APIs rely upon the calling application to pass appropriately-sized
buffers and appropriate size/dimension arguments.  The failure to do so
is no more the fault of libjpeg-turbo than calling
'buf = malloc(1); buf[2] = 0;' is the fault of the C library.

Buffer size checking is a bonus feature of the Java API that isn't (and
can't be) provided by the C API, so this commit merely hardens the bonus
feature against API abuse, in keeping with the Java paradigm of throwing
an exception rather than crashing due to a caller-imposed buffer
overrun.
This commit is contained in:
DRC
2025-12-03 14:23:21 -05:00
parent dfb0cff989
commit fc324109d5
2 changed files with 18 additions and 0 deletions

View File

@@ -13,6 +13,11 @@ erroneously set `TJPARAM_LOSSLESS` or `TJPARAM_COLORSPACE` prior to calling
`tj3CompressFromYUV*8()` now ignore `TJPARAM_LOSSLESS` and
`TJPARAM_COLORSPACE`.
3. Hardened the TurboJPEG Java API against hypothetical applications that may
erroneously pass huge X or Y offsets to one of the compression, YUV encoding,
decompression, or YUV decoding methods, leading to signed integer overflow in
the JNI wrapper's buffer size checks that rendered those checks ineffective.
3.1.2
=====

View File

@@ -261,6 +261,9 @@ static jint TJCompressor_compress
THROW_ARG("Mismatch between Java and C API");
actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
if (((unsigned long long)y + height - 1ULL) * actualPitch + (x + width) *
tjPixelSize[pf] > (unsigned long long)((unsigned int)-1))
THROW_ARG("Image is too large");
arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
THROW_ARG("Source buffer is not large enough");
@@ -474,6 +477,9 @@ static void TJCompressor_encodeYUV8
THROW_ARG("Strides array is too small for the subsampling type");
actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
if (((unsigned long long)y + height - 1ULL) * actualPitch + (x + width) *
tjPixelSize[pf] > (unsigned long long)((unsigned int)-1))
THROW_ARG("Image is too large");
arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
THROW_ARG("Source buffer is not large enough");
@@ -813,6 +819,10 @@ static void TJDecompressor_decompress
}
actualPitch = (pitch == 0) ? scaledWidth * tjPixelSize[pf] : pitch;
if (((unsigned long long)y + scaledHeight - 1ULL) * actualPitch +
(x + scaledWidth) * tjPixelSize[pf] >
(unsigned long long)((unsigned int)-1))
THROW_ARG("Image is too large");
arraySize = (y + scaledHeight - 1) * actualPitch +
(x + scaledWidth) * tjPixelSize[pf];
if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
@@ -1031,6 +1041,9 @@ static void TJDecompressor_decodeYUV8
THROW_ARG("Strides array is too small for the subsampling type");
actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
if (((unsigned long long)y + height - 1ULL) * actualPitch + (x + width) *
tjPixelSize[pf] > (unsigned long long)((unsigned int)-1))
THROW_ARG("Image is too large");
arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
THROW_ARG("Destination buffer is not large enough");