CVE-2021-20304 (C++, published 2022-08-23T16:15Z)
Description: value: A flaw was found in OpenEXR's hufDecode functionality. This flaw allows an attacker who can pass a crafted file to be processed by OpenEXR, to trigger an undefined right shift error. The highest threat from this vulnerability is to system availability.
Severity: nan (CVSS v3 base score: 7.5)
Weakness: CWE-190 \u2014 Integer Overflow or Wraparound
The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
Repository: https://github.com/AcademySoftwareFoundation/openexr
Files changed:
OpenEXR/IlmImf/ImfHuf.cpp
OpenEXR/IlmImfTest/testHuf.cpp
Commit message: check for valid Huf code lengths (#849)

* check for valid Huf code lengths
* test non-fast huf decoder in testHuf

Signed-off-by: Peter Hillman <peterh@wetafx.co.nz>

Vulnerable code:
	const int N = 1000000;
	Array <unsigned short> raw (N);

	fill1 (raw, N, 1, rand48);	  // test various symbol distributions
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill1 (raw, N, 10, rand48);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill1 (raw, N, 100, rand48);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill1 (raw, N, 1000, rand48);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);

	fill2 (raw, N, 1, rand48);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill2 (raw, N, 10, rand48);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill2 (raw, N, 100, rand48);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill2 (raw, N, 1000, rand48);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);

	fill3 (raw, N, 0);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill3 (raw, N, 1);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill3 (raw, N, USHRT_MAX - 1);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);
	fill3 (raw, N, USHRT_MAX);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);

	fill4 (raw, USHRT_MAX + 1);
        compressVerify(raw, USHRT_MAX + 1, HUF_COMPRESS_DEK_HASH_FOR_FILL4_USHRT_MAX_PLUS_ONE);
	compressUncompress (raw, USHRT_MAX + 1);
	compressUncompressSubset (raw, USHRT_MAX + 1);
	fill4 (raw, N);
        compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL4_N);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);

	fill4 (raw, 0);
	compressUncompress (raw, 0);	// test small input data sets
	fill4 (raw, 1);
	compressUncompress (raw, 1);
	fill4 (raw, 2);
	compressUncompress (raw, 2);
	fill4 (raw, 3);
	compressUncompress (raw, 3);

	fill5 (raw, N);			// test run-length coding of code table
        compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL5_N);
	compressUncompress (raw, N);
	compressUncompressSubset (raw, N);

Fixed code:

		if ( lc < 0 )
		{
			invalidCode(); // code length too long
		}
            if ( lc < 0 )
            {
   	        invalidCode(); // code length too long
            }
        //
        // FastHufDecoder is used for more than 128 bits, so first test with fewer than 128 bits,
        // then test FastHufDecoder
        //
        for (int pass = 0 ; pass < 2 ; ++pass)
        {

            int N = pass==0 ? 12 : 1000000;
            Array <unsigned short> raw (N);

            fill1 (raw, N, 1, rand48);	  // test various symbol distributions
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill1 (raw, N, 10, rand48);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill1 (raw, N, 100, rand48);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill1 (raw, N, 1000, rand48);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);

            fill2 (raw, N, 1, rand48);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill2 (raw, N, 10, rand48);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill2 (raw, N, 100, rand48);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill2 (raw, N, 1000, rand48);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);

            fill3 (raw, N, 0);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill3 (raw, N, 1);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill3 (raw, N, USHRT_MAX - 1);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);
            fill3 (raw, N, USHRT_MAX);
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);

            if (pass==1)
            {
                fill4 (raw, USHRT_MAX + 1);
                compressVerify(raw, USHRT_MAX + 1, HUF_COMPRESS_DEK_HASH_FOR_FILL4_USHRT_MAX_PLUS_ONE);

                compressUncompress (raw, USHRT_MAX + 1);
                compressUncompressSubset (raw, USHRT_MAX + 1);
                fill4 (raw, N);
                compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL4_N);
            }
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);

            fill4 (raw, 0);
            compressUncompress (raw, 0);	// test small input data sets
            fill4 (raw, 1);
            compressUncompress (raw, 1);
            fill4 (raw, 2);
            compressUncompress (raw, 2);
            fill4 (raw, 3);
            compressUncompress (raw, 3);

            fill5 (raw, N);			// test run-length coding of code table
            if (pass==1)
            {
                compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL5_N);
            }
            compressUncompress (raw, N);
            compressUncompressSubset (raw, N);

        }