diff --git a/ChangeLog.md b/ChangeLog.md
index e2ecbf9c..16ec04cd 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -20,6 +20,12 @@ parameter and option serve the same purpose as the `max_memory_to_use` field in
the `jpeg_memory_mgr` struct in the libjpeg API, the `JPEGMEM` environment
variable, and the cjpeg/djpeg/jpegtran `-maxmemory` option.
+3. Introduced a new parameter (`TJPARAM_MAXPIXELS` in the TurboJPEG C API and
+`TJ.PARAM_MAXPIXELS` in the TurboJPEG Java API) and a corresponding TJBench
+option (`-maxpixels`) for specifying the maximum number of pixels that the
+decompression, lossless transformation, and packed-pixel image loading
+functions/methods will process.
+
3.0.1
=====
diff --git a/cdjpeg.h b/cdjpeg.h
index 471b9a3f..f4da2388 100644
--- a/cdjpeg.h
+++ b/cdjpeg.h
@@ -40,9 +40,7 @@ struct cjpeg_source_struct {
J16SAMPARRAY buffer16;
#endif
JDIMENSION buffer_height;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
JDIMENSION max_pixels;
-#endif
};
diff --git a/doc/html/group___turbo_j_p_e_g.html b/doc/html/group___turbo_j_p_e_g.html
index 8fdae045..5ee50a48 100644
--- a/doc/html/group___turbo_j_p_e_g.html
+++ b/doc/html/group___turbo_j_p_e_g.html
@@ -233,7 +233,9 @@ Enumerations
TJPARAM_XDENSITY,
TJPARAM_YDENSITY,
TJPARAM_DENSITYUNITS,
-TJPARAM_MAXMEMORY
+TJPARAM_MAXMEMORY,
+
+ TJPARAM_MAXPIXELS
}
static TJScalingFactor |
UNSCALED |
@@ -1870,6 +1877,31 @@ extends java.lang.Object
+
+
+
+
diff --git a/java/doc/package-search-index.zip b/java/doc/package-search-index.zip
index 70a04c09..c5f302c2 100644
Binary files a/java/doc/package-search-index.zip and b/java/doc/package-search-index.zip differ
diff --git a/java/doc/type-search-index.zip b/java/doc/type-search-index.zip
index fca9ab28..295927d5 100644
Binary files a/java/doc/type-search-index.zip and b/java/doc/type-search-index.zip differ
diff --git a/java/org/libjpegturbo/turbojpeg/TJ.java b/java/org/libjpegturbo/turbojpeg/TJ.java
index 8f96438e..23b1c653 100644
--- a/java/org/libjpegturbo/turbojpeg/TJ.java
+++ b/java/org/libjpegturbo/turbojpeg/TJ.java
@@ -787,6 +787,21 @@ public final class TJ {
*
*/
public static final int PARAM_MAXMEMORY = 23;
+ /**
+ * Image size limit [decompression, lossless transformation]
+ *
+ * Setting this parameter will cause the decompression and transform
+ * operations to throw an error if the number of pixels in the JPEG source
+ * image exceeds the specified limit. This allows security-critical
+ * applications to guard against excessive memory consumption.
+ *
+ * Value
+ *
+ * - maximum number of pixels that the decompression and transform
+ * operations will process [default:
0 (no limit)]
+ *
+ */
+ public static final int PARAM_MAXPIXELS = 24;
/**
diff --git a/java/org_libjpegturbo_turbojpeg_TJ.h b/java/org_libjpegturbo_turbojpeg_TJ.h
index 103e4782..38505f73 100644
--- a/java/org_libjpegturbo_turbojpeg_TJ.h
+++ b/java/org_libjpegturbo_turbojpeg_TJ.h
@@ -109,6 +109,8 @@ extern "C" {
#define org_libjpegturbo_turbojpeg_TJ_PARAM_DENSITYUNITS 22L
#undef org_libjpegturbo_turbojpeg_TJ_PARAM_MAXMEMORY
#define org_libjpegturbo_turbojpeg_TJ_PARAM_MAXMEMORY 23L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_MAXPIXELS
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_MAXPIXELS 24L
#undef org_libjpegturbo_turbojpeg_TJ_FLAG_BOTTOMUP
#define org_libjpegturbo_turbojpeg_TJ_FLAG_BOTTOMUP 2L
#undef org_libjpegturbo_turbojpeg_TJ_FLAG_FASTUPSAMPLE
diff --git a/rdbmp.c b/rdbmp.c
index 88ee7512..c2c06fd0 100644
--- a/rdbmp.c
+++ b/rdbmp.c
@@ -6,7 +6,7 @@
* Modified 2009-2017 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Modified 2011 by Siarhei Siamashka.
- * Copyright (C) 2015, 2017-2018, 2021-2022, D. R. Commander.
+ * Copyright (C) 2015, 2017-2018, 2021-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -523,11 +523,9 @@ start_input_bmp(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
if (biWidth <= 0 || biHeight <= 0)
ERREXIT(cinfo, JERR_BMP_EMPTY);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)biWidth * biHeight > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
if (biPlanes != 1)
ERREXIT(cinfo, JERR_BMP_BADPLANES);
@@ -681,9 +679,7 @@ jinit_read_bmp(j_compress_ptr cinfo, boolean use_inversion_array)
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_bmp;
source->pub.finish_input = finish_input_bmp;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
source->use_inversion_array = use_inversion_array;
diff --git a/rdgif.c b/rdgif.c
index 0cbd2796..23e8b9e1 100644
--- a/rdgif.c
+++ b/rdgif.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2019 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2021-2022, D. R. Commander.
+ * Copyright (C) 2021-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -418,11 +418,9 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
height = LM_to_uint(hdrbuf, 2);
if (width == 0 || height == 0)
ERREXIT(cinfo, JERR_GIF_EMPTY);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)width * height > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
/* we ignore the color resolution, sort flag, and background color index */
aspectRatio = UCH(hdrbuf[6]);
if (aspectRatio != 0 && aspectRatio != 49)
@@ -467,11 +465,9 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
height = LM_to_uint(hdrbuf, 6);
if (width == 0 || height == 0)
ERREXIT(cinfo, JERR_GIF_EMPTY);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)width * height > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
source->is_interlaced = (BitSet(hdrbuf[8], INTERLACE) != 0);
/* Read local colormap if header indicates it is present */
@@ -715,9 +711,7 @@ _jinit_read_gif(j_compress_ptr cinfo)
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_gif;
source->pub.finish_input = finish_input_gif;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
return (cjpeg_source_ptr)source;
}
diff --git a/rdppm.c b/rdppm.c
index 57058069..84e26f7b 100644
--- a/rdppm.c
+++ b/rdppm.c
@@ -689,10 +689,8 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
ERREXIT(cinfo, JERR_PPM_NOT);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels && (unsigned long long)w * h > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
cinfo->image_width = (JDIMENSION)w;
@@ -883,9 +881,7 @@ _jinit_read_ppm(j_compress_ptr cinfo)
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_ppm;
source->pub.finish_input = finish_input_ppm;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
return (cjpeg_source_ptr)source;
}
diff --git a/rdtarga.c b/rdtarga.c
index dae0b58d..b78a1653 100644
--- a/rdtarga.c
+++ b/rdtarga.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* Modified 2017 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2018, 2021-2022, D. R. Commander.
+ * Copyright (C) 2018, 2021-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -363,11 +363,9 @@ start_input_tga(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
interlace_type != 0 || /* currently don't allow interlaced image */
width == 0 || height == 0) /* image width/height must be non-zero */
ERREXIT(cinfo, JERR_TGA_BADPARMS);
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
if (sinfo->max_pixels &&
(unsigned long long)width * height > sinfo->max_pixels)
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
-#endif
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, sinfo->max_pixels);
if (subtype > 8) {
/* It's an RLE-coded file */
@@ -501,9 +499,7 @@ jinit_read_targa(j_compress_ptr cinfo)
/* Fill in method ptrs, except get_pixel_rows which start_input sets */
source->pub.start_input = start_input_tga;
source->pub.finish_input = finish_input_tga;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
source->pub.max_pixels = 0;
-#endif
return (cjpeg_source_ptr)source;
}
diff --git a/tjbench.c b/tjbench.c
index 566fe8cf..bedc94b4 100644
--- a/tjbench.c
+++ b/tjbench.c
@@ -90,7 +90,7 @@ int tjErrorLine = -1, tjErrorCode = -1;
int stopOnWarning = 0, bottomUp = 0, noRealloc = 1, fastUpsample = 0,
fastDCT = 0, optimize = 0, progressive = 0, limitScans = 0, maxMemory = 0,
- arithmetic = 0, lossless = 0, restartIntervalBlocks = 0,
+ maxPixels = 0, arithmetic = 0, lossless = 0, restartIntervalBlocks = 0,
restartIntervalRows = 0;
int precision = 8, sampleSize, compOnly = 0, decompOnly = 0, doYUV = 0,
quiet = 0, doTile = 0, pf = TJPF_BGR, yuvAlign = 1, doWrite = 1;
@@ -204,6 +204,8 @@ static int decomp(unsigned char **jpegBufs, size_t *jpegSizes, void *dstBuf,
THROW_TJ();
if (tj3Set(handle, TJPARAM_MAXMEMORY, maxMemory) == -1)
THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXPIXELS, maxPixels) == -1)
+ THROW_TJ();
if (IS_CROPPED(cr)) {
if (tj3DecompressHeader(handle, jpegBufs[0], jpegSizes[0]) == -1)
@@ -659,6 +661,8 @@ static int decompTest(char *fileName)
THROW_TJ();
if (tj3Set(handle, TJPARAM_MAXMEMORY, maxMemory) == -1)
THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXPIXELS, maxPixels) == -1)
+ THROW_TJ();
if (tj3DecompressHeader(handle, srcBuf, srcSize) == -1)
THROW_TJ();
@@ -910,6 +914,7 @@ static void usage(char *progName)
printf(" progressive JPEG compression and decompression, optimized baseline entropy\n");
printf(" coding, lossless JPEG compression, and lossless transformation\n");
printf(" [default = no limit]\n");
+ printf("-maxpixels = Input image size limit (in pixels) [default = no limit]\n");
printf("-nowrite = Do not write reference or output images (improves consistency of\n");
printf(" benchmark results)\n");
printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
@@ -1161,6 +1166,11 @@ int main(int argc, char *argv[])
if (tempi < 0) usage(argv[0]);
maxMemory = tempi;
+ } else if (!strcasecmp(argv[i], "-maxpixels") && i < argc - 1) {
+ int tempi = atoi(argv[++i]);
+
+ if (tempi < 0) usage(argv[0]);
+ maxPixels = tempi;
} else if (!strcasecmp(argv[i], "-restart") && i < argc - 1) {
int tempi = -1, nscan; char tempc = 0;
@@ -1228,6 +1238,8 @@ int main(int argc, char *argv[])
THROW_TJ();
if (tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp) == -1)
THROW_TJ();
+ if (tj3Set(handle, TJPARAM_MAXPIXELS, maxPixels) == -1)
+ THROW_TJ();
if (precision == 8) {
if ((srcBuf = tj3LoadImage8(handle, argv[1], &w, 1, &h, &pf)) == NULL)
diff --git a/turbojpeg-mp.c b/turbojpeg-mp.c
index 2ca23aa7..9bf346b4 100644
--- a/turbojpeg-mp.c
+++ b/turbojpeg-mp.c
@@ -179,6 +179,9 @@ DLLEXPORT int GET_NAME(tj3Decompress, BITS_IN_JSAMPLE)
jpeg_read_header(dinfo, TRUE);
}
setDecompParameters(this);
+ if (this->maxPixels &&
+ (unsigned long long)this->jpegWidth * this->jpegHeight > this->maxPixels)
+ THROW("Image is too large");
this->dinfo.out_color_space = pf2cs[pixelFormat];
#if BITS_IN_JSAMPLE != 16
scaledWidth = TJSCALED(dinfo->image_width, this->scalingFactor);
@@ -347,10 +350,8 @@ DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE)
cinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
src->input_file = file;
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- /* Refuse to load images larger than 1 Megapixel when fuzzing. */
+ /* Refuse to load images larger than the specified size. */
src->max_pixels = this->maxPixels;
-#endif
(*src->start_input) (cinfo, src);
if (tempc == 'B') {
if (cinfo->X_density && cinfo->Y_density) {
diff --git a/turbojpeg.c b/turbojpeg.c
index 519a868e..b9fe6e9f 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -109,9 +109,6 @@ typedef struct _tjinstance {
char errStr[JMSG_LENGTH_MAX];
boolean isInstanceError;
/* Parameters */
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- int maxPixels;
-#endif
boolean bottomUp;
boolean noRealloc;
int quality;
@@ -137,6 +134,7 @@ typedef struct _tjinstance {
tjscalingfactor scalingFactor;
tjregion croppingRegion;
int maxMemory;
+ int maxPixels;
} tjinstance;
static tjhandle _tjInitCompress(tjinstance *this);
@@ -592,11 +590,6 @@ DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
GET_TJINSTANCE(handle, -1);
switch (param) {
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- case TJPARAM_MAXPIXELS:
- SET_PARAM(maxPixels, 0, -1);
- break;
-#endif
case TJPARAM_STOPONWARNING:
SET_BOOL_PARAM(jerr.stopOnWarning);
break;
@@ -709,6 +702,9 @@ DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
case TJPARAM_MAXMEMORY:
SET_PARAM(maxMemory, 0, (int)(min(LONG_MAX / 1048576L, (long)INT_MAX)));
break;
+ case TJPARAM_MAXPIXELS:
+ SET_PARAM(maxPixels, 0, -1);
+ break;
default:
THROW("Invalid parameter");
}
@@ -773,6 +769,8 @@ DLLEXPORT int tj3Get(tjhandle handle, int param)
return this->densityUnits;
case TJPARAM_MAXMEMORY:
return this->maxMemory;
+ case TJPARAM_MAXPIXELS:
+ return this->maxPixels;
}
return -1;
@@ -2350,6 +2348,9 @@ DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
jpeg_read_header(dinfo, TRUE);
}
setDecompParameters(this);
+ if (this->maxPixels &&
+ (unsigned long long)this->jpegWidth * this->jpegHeight > this->maxPixels)
+ THROW("Image is too large");
if (this->subsamp == TJSAMP_UNKNOWN)
THROW("Could not determine subsampling level of JPEG image");
@@ -2715,6 +2716,10 @@ DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
if (dinfo->global_state <= DSTATE_INHEADER)
jpeg_read_header(dinfo, TRUE);
+ if (this->maxPixels &&
+ (unsigned long long)dinfo->image_width * dinfo->image_height >
+ this->maxPixels)
+ THROW("Image is too large");
this->subsamp = getSubsamp(&this->dinfo);
for (i = 0; i < n; i++) {
diff --git a/turbojpeg.h b/turbojpeg.h
index 3058199a..4a09c64d 100644
--- a/turbojpeg.h
+++ b/turbojpeg.h
@@ -429,9 +429,6 @@ enum TJCS {
* Parameters
*/
enum TJPARAM {
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- TJPARAM_MAXPIXELS = -1,
-#endif
/**
* Error handling behavior
*
@@ -763,7 +760,21 @@ enum TJPARAM {
* decompression, optimized baseline entropy coding, lossless JPEG
* compression, and lossless transformation *[default: `0` (no limit)]*
*/
- TJPARAM_MAXMEMORY
+ TJPARAM_MAXMEMORY,
+ /**
+ * Image size limit [decompression, lossless transformation, packed-pixel
+ * image loading]
+ *
+ * Setting this parameter will cause the decompression, transform, and image
+ * loading functions to return an error if the number of pixels in the source
+ * image exceeds the specified limit. This allows security-critical
+ * applications to guard against excessive memory consumption.
+ *
+ * **Value**
+ * - maximum number of pixels that the decompression, transform, and image
+ * loading functions will process *[default: `0` (no limit)]*
+ */
+ TJPARAM_MAXPIXELS
};
|