Source: libjpeg-turbo
Version: 1:1.5.2-2
Severity: important
Tags: security upstream
Forwarded: https://github.com/libjpeg-turbo/libjpeg-turbo/issues/258

Hi,

The following vulnerability was published for libjpeg-turbo.

CVE-2018-14498[0]:
| get_8bit_row in rdbmp.c in libjpeg-turbo through 1.5.90 and MozJPEG
| through 3.3.1 allows attackers to cause a denial of service (heap-based
| buffer over-read and application crash) via a crafted 8-bit BMP in
| which one or more of the color indices is out of range for the number
| of palette entries.

If you fix the vulnerability please also make sure to include the
CVE (Common Vulnerabilities & Exposures) id in your changelog entry.

Build with ASAN one sees the issue as

$ ASAN_OPTIONS="detect_leaks=0" ./cjpeg -outfile /dev/null ~/CVE-2018-14498
=================================================================
==31997==ERROR: AddressSanitizer: heap-buffer-overflow on address 
0x60d0000000d3 at pc 0x56029bfc9ff7 bp 0x7ffe52f5e400 sp 0x7ffe52f5e3f8
READ of size 1 at 0x60d0000000d3 thread T0
    #0 0x56029bfc9ff6 in get_8bit_row /tmp/libjpeg-turbo-1.5.2/rdbmp.c:145
    #1 0x56029bfcaf1b in preload_image /tmp/libjpeg-turbo-1.5.2/rdbmp.c:270
    #2 0x56029bfc3c40 in main /tmp/libjpeg-turbo-1.5.2/cjpeg.c:616
    #3 0x7f8be200109a in __libc_start_main ../csu/libc-start.c:308
    #4 0x56029bfc1359 in _start (/tmp/libjpeg-turbo-1.5.2/.libs/cjpeg+0x5359)

0x60d0000000d3 is located 12 bytes to the right of 135-byte region 
[0x60d000000040,0x60d0000000c7)
allocated by thread T0 here:
    #0 0x7f8be23d6350 in __interceptor_malloc 
(/usr/lib/x86_64-linux-gnu/libasan.so.5+0xe9350)
    #1 0x7f8be229b437 in jpeg_get_large /tmp/libjpeg-turbo-1.5.2/jmemnobs.c:56
    #2 0x7f8be2296e9f in alloc_large /tmp/libjpeg-turbo-1.5.2/jmemmgr.c:393
    #3 0x7f8be22971fc in alloc_sarray /tmp/libjpeg-turbo-1.5.2/jmemmgr.c:477
    #4 0x56029bfcce5a in start_input_bmp /tmp/libjpeg-turbo-1.5.2/rdbmp.c:401
    #5 0x56029bfc3b5d in main /tmp/libjpeg-turbo-1.5.2/cjpeg.c:595
    #6 0x7f8be200109a in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: heap-buffer-overflow 
/tmp/libjpeg-turbo-1.5.2/rdbmp.c:145 in get_8bit_row
Shadow bytes around the buggy address:
  0x0c1a7fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x0c1a7fff8010: 00 00 00 00 00 00 00 00 07 fa[fa]fa fa fa fa fa
  0x0c1a7fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==31997==ABORTING

For further information see:

[0] https://security-tracker.debian.org/tracker/CVE-2018-14498
    https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-14498
[1] https://github.com/libjpeg-turbo/libjpeg-turbo/issues/258

Please adjust the affected versions in the BTS as needed.

Attaching a preliminary backported patch which should apply on top of 1:1.5.2-2
(not yet checked it is fully correct backport).

Regards,
Salvatore
From: DRC <informat...@libjpeg-turbo.org>
Date: Fri, 20 Jul 2018 17:21:36 -0500
Subject: cjpeg: Fix OOB read caused by malformed 8-bit BMP
Origin: 
https://github.com/libjpeg-turbo/libjpeg-turbo/commit/9c78a04df4e44ef6487eee99c4258397f4fdca55
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2018-14498
Bug: https://github.com/libjpeg-turbo/libjpeg-turbo/issues/258

... in which one or more of the color indices is out of range for the
number of palette entries.

Fix partly borrowed from jpeg-9c.  This commit also adopts Guido's
JERR_PPM_OUTOFRANGE enum value in lieu of our project-specific
JERR_PPM_TOOLARGE enum value.

Fixes #258
---
 ChangeLog.md |  5 +++++
 cderror.h    |  5 +++--
 rdbmp.c      | 13 ++++++++++++-
 rdppm.c      | 12 ++++++------
 4 files changed, 26 insertions(+), 9 deletions(-)

--- a/cderror.h
+++ b/cderror.h
@@ -49,6 +49,7 @@ JMESSAGE(JERR_BMP_COLORSPACE, "BMP outpu
 JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported")
 JMESSAGE(JERR_BMP_EMPTY, "Empty BMP image")
 JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM")
+JMESSAGE(JERR_BMP_OUTOFRANGE, "Numeric value out of range in BMP file")
 JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image")
 JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
 JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image")
@@ -75,8 +76,8 @@ JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out o
 #ifdef PPM_SUPPORTED
 JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB")
 JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file")
-JMESSAGE(JERR_PPM_TOOLARGE, "Integer value too large in PPM file")
 JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file")
+JMESSAGE(JERR_PPM_OUTOFRANGE, "Numeric value out of range in PPM file")
 JMESSAGE(JTRC_PGM, "%ux%u PGM image")
 JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image")
 JMESSAGE(JTRC_PPM, "%ux%u PPM image")
--- a/rdbmp.c
+++ b/rdbmp.c
@@ -66,6 +66,7 @@ typedef struct _bmp_source_struct {
   JDIMENSION row_width;         /* Physical width of scanlines in file */
 
   int bits_per_pixel;           /* remembers 8- or 24-bit format */
+  int cmap_length;              /* colormap length */
 } bmp_source_struct;
 
 
@@ -126,6 +127,7 @@ get_8bit_row (j_compress_ptr cinfo, cjpe
 {
   bmp_source_ptr source = (bmp_source_ptr) sinfo;
   register JSAMPARRAY colormap = source->colormap;
+  int cmaplen = source->cmap_length;
   JSAMPARRAY image_ptr;
   register int t;
   register JSAMPROW inptr, outptr;
@@ -142,6 +144,8 @@ get_8bit_row (j_compress_ptr cinfo, cjpe
   outptr = source->pub.buffer[0];
   for (col = cinfo->image_width; col > 0; col--) {
     t = GETJSAMPLE(*inptr++);
+    if (t >= cmaplen)
+      ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);
     *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */
     *outptr++ = colormap[1][t];
     *outptr++ = colormap[2][t];
@@ -401,6 +405,7 @@ start_input_bmp (j_compress_ptr cinfo, c
     source->colormap = (*cinfo->mem->alloc_sarray)
       ((j_common_ptr) cinfo, JPOOL_IMAGE,
        (JDIMENSION) biClrUsed, (JDIMENSION) 3);
+    source->cmap_length = (int)biClrUsed;
     /* and read it from the file */
     read_colormap(source, (int) biClrUsed, mapentrysize);
     /* account for size of colormap */
--- a/rdppm.c
+++ b/rdppm.c
@@ -69,7 +69,7 @@ typedef struct {
   JSAMPROW pixrow;              /* compressor input buffer */
   size_t buffer_width;          /* width of I/O buffer */
   JSAMPLE *rescale;             /* => maxval-remapping array, or NULL */
-  int maxval;
+  unsigned int maxval;
 } ppm_source_struct;
 
 typedef ppm_source_struct *ppm_source_ptr;
@@ -119,7 +119,7 @@ read_pbm_integer (j_compress_ptr cinfo,
   }
 
   if (val > maxval)
-    ERREXIT(cinfo, JERR_PPM_TOOLARGE);
+    ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
 
   return val;
 }
@@ -255,7 +255,7 @@ get_word_gray_row (j_compress_ptr cinfo,
     temp  = UCH(*bufferptr++) << 8;
     temp |= UCH(*bufferptr++);
     if (temp > maxval)
-      ERREXIT(cinfo, JERR_PPM_TOOLARGE);
+      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
     *ptr++ = rescale[temp];
   }
   return 1;
@@ -282,17 +282,17 @@ get_word_rgb_row (j_compress_ptr cinfo,
     temp  = UCH(*bufferptr++) << 8;
     temp |= UCH(*bufferptr++);
     if (temp > maxval)
-      ERREXIT(cinfo, JERR_PPM_TOOLARGE);
+      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
     *ptr++ = rescale[temp];
     temp  = UCH(*bufferptr++) << 8;
     temp |= UCH(*bufferptr++);
     if (temp > maxval)
-      ERREXIT(cinfo, JERR_PPM_TOOLARGE);
+      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
     *ptr++ = rescale[temp];
     temp  = UCH(*bufferptr++) << 8;
     temp |= UCH(*bufferptr++);
     if (temp > maxval)
-      ERREXIT(cinfo, JERR_PPM_TOOLARGE);
+      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
     *ptr++ = rescale[temp];
   }
   return 1;

Reply via email to