jchuff.c: Test for out-of-range coefficients

Restore two coefficient range checks from libjpeg to the C baseline
Huffman encoder.  This fixes an issue
(https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=60253) whereby
the encoder could read from uninitialized memory when attempting to
transform a specially-crafted malformed arithmetic-coded JPEG source
image into a baseline Huffman-coded JPEG destination image with default
Huffman tables.  More specifically, the out-of-range coefficients caused
r to equal 256, which overflowed the actbl->ehufsi[] array.  Because the
overflow was contained within the huff_entropy_encoder structure, this
issue was not exploitable (nor was it observable at all on x86 or Arm
CPUs unless JSIMD_NOHUFFENC=1 or JSIMD_FORCENONE=1 was set in the
environment or unless libjpeg-turbo was built with WITH_SIMD=0.)

The fix is performance-neutral (+/- 1-2%) for x86-64 code and causes a
0-4% (avg. 1-2%, +/- 1-2%) compression regression for i386 code on Intel
CPUs when the C baseline Huffman encoder is used (JSIMD_NOHUFFENC=1).
The fix is performance-neutral (+/- 1-2%) on Intel CPUs when all of the
libjpeg-turbo SIMD extensions are disabled (JSIMD_FORCENONE=1).  The fix
causes a 0-2% (avg. <1%, +/- 1%) compression regression for PowerPC
code.
This commit is contained in:
DRC
2023-06-30 17:58:45 -04:00
parent 4a831d6e48
commit e0c53aa38f
2 changed files with 15 additions and 1 deletions

View File

@@ -55,6 +55,11 @@ metadata unless automatic JPEG destination buffer (re)allocation is used or
`-map` option from working when decompressing 12-bit-per-component lossy JPEG
images.
7. Fixed an issue that caused the C Huffman encoder (which is not used by
default on x86 and Arm CPUs) to read from uninitialized memory when attempting
to transform a specially-crafted malformed arithmetic-coded JPEG source image
into a baseline Huffman-coded JPEG destination image.
2.1.91 (3.0 beta2)
==================

View File

@@ -6,7 +6,7 @@
* Lossless JPEG Modifications:
* Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, 2014-2016, 2018-2022, D. R. Commander.
* Copyright (C) 2009-2011, 2014-2016, 2018-2023, D. R. Commander.
* Copyright (C) 2015, Matthieu Darbois.
* Copyright (C) 2018, Matthias Räncker.
* Copyright (C) 2020, Arm Limited.
@@ -584,6 +584,7 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
bit_buf_type put_buffer;
JOCTET _buffer[BUFSIZE], *buffer;
int localbuf = 0;
int max_coef_bits = state->cinfo->data_precision + 2;
free_bits = state->cur.free_bits;
put_buffer = state->cur.put_buffer.c;
@@ -604,6 +605,11 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = JPEG_NBITS(nbits);
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
if (nbits > max_coef_bits + 1)
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
/* Emit the Huffman-coded symbol for the number of bits.
* Emit that number of bits of the value, if positive,
@@ -629,6 +635,9 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
temp += nbits; \
nbits ^= temp; \
nbits = JPEG_NBITS_NONZERO(nbits); \
/* Check for out-of-range coefficient values */ \
if (nbits > max_coef_bits) \
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); \
/* if run length > 15, must emit special run-length-16 codes (0xF0) */ \
while (r >= 16 * 16) { \
r -= 16 * 16; \