CVE-2020-35538 (C, published 2022-08-31T16:15Z)
Description: value: A crafted input file could cause a null pointer dereference in jcopy_sample_rows() when processed by libjpeg-turbo.
Severity: nan (CVSS v3 base score: 5.5)
Weakness: CWE-476 \u2014 NULL Pointer Dereference
The product dereferences a pointer that it expects to be valid but is NULL.
Repository: https://github.com/libjpeg-turbo/libjpeg-turbo
Files changed:
ChangeLog.md
jdapistd.c
jdmerge.c
jdmerge.h
jdmrg565.c
jdmrgext.c
Commit message: Fix jpeg_skip_scanlines() segfault w/merged upsamp

The additional segfault mentioned in #244 was due to the fact that
the merged upsamplers use a different private structure than the
non-merged upsamplers.  jpeg_skip_scanlines() was assuming the latter, so
when merged upsampling was enabled, jpeg_skip_scanlines() clobbered one
of the IDCT method pointers in the merged upsampler's private structure.

For reasons unknown, the test image in #441 did not encounter this
segfault (too small?), but it encountered an issue similar to the one
fixed in 5bc43c7821df982f65aa1c738f67fbf7cba8bd69, whereby it was
necessary to set up a dummy postprocessing function in
read_and_discard_scanlines() when merged upsampling was enabled.
Failing to do so caused either a segfault in merged_2v_upsample() (due
to a NULL pointer being passed to jcopy_sample_rows()) or an error
("Corrupt JPEG data: premature end of data segment"), depending on the
number of scanlines skipped and whether the first scanline skipped was
an odd- or even-numbered row.

Fixes #441
Fixes #244 (for real this time)


Vulnerable code:
 * Copyright (C) 2010, 2015-2018, D. R. Commander.
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
    upsample->next_row_out = cinfo->max_v_samp_factor;
    upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
      upsample->next_row_out = cinfo->max_v_samp_factor;
      upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
    upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
  upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
 * Copyright (C) 2009, 2011, 2014-2015, D. R. Commander.
/* Private subobject */

typedef struct {
  struct jpeg_upsampler pub;    /* public fields */

  /* Pointer to routine to do actual upsampling/conversion of one row group */
  void (*upmethod) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
                    JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);

  /* Private state for YCC->RGB conversion */
  int *Cr_r_tab;                /* => table for Cr to R conversion */
  int *Cb_b_tab;                /* => table for Cb to B conversion */
  JLONG *Cr_g_tab;              /* => table for Cr to G conversion */
  JLONG *Cb_g_tab;              /* => table for Cb to G conversion */

  /* For 2:1 vertical sampling, we produce two output rows at a time.
   * We need a "spare" row buffer to hold the second output row if the
   * application provides just a one-row buffer; we also use the spare
   * to discard the dummy last row if the image height is odd.
   */
  JSAMPROW spare_row;
  boolean spare_full;           /* T if spare buffer is occupied */

  JDIMENSION out_row_width;     /* samples per output row */
  JDIMENSION rows_to_go;        /* counts rows remaining in image */
} my_upsampler;

typedef my_upsampler *my_upsample_ptr;

  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample;
  upsample = (my_upsample_ptr)
                                sizeof(my_upsampler));
 * Copyright (C) 2014-2015, 2018, D. R. Commander.
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
 * Copyright (C) 2011, 2015, D. R. Commander.
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
  my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;

Fixed code:
2. Fixed segfaults or "Corrupt JPEG data: premature end of data segment" errors
in `jpeg_skip_scanlines()` that occurred when decompressing 4:2:2 or 4:2:0 JPEG
images using the merged (non-fancy) upsampling algorithms (that is, when
setting `cinfo.do_fancy_upsampling` to `FALSE`.)  2.0.0[6] was a similar fix,
but it did not cover all cases.

 * Copyright (C) 2010, 2015-2018, 2020, D. R. Commander.
#include "jdmaster.h"
#include "jdmerge.h"
/* Dummy postprocessing function used by jpeg_skip_scanlines() */
LOCAL(void)
noop_post_process (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
                   JDIMENSION *in_row_group_ctr,
                   JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
                   JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
}


  my_master_ptr master = (my_master_ptr)cinfo->master;
  void (*post_process_data) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
                             JDIMENSION *in_row_group_ctr,
                             JDIMENSION in_row_groups_avail,
                             JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
                             JDIMENSION out_rows_avail) = NULL;
  if (master->using_merged_upsample && cinfo->post &&
      cinfo->post->post_process_data) {
    post_process_data = cinfo->post->post_process_data;
    cinfo->post->post_process_data = noop_post_process;
  }


  if (post_process_data)
    cinfo->post->post_process_data = post_process_data;
  my_master_ptr master = (my_master_ptr)cinfo->master;
    if (master->using_merged_upsample) {
      my_merged_upsample_ptr upsample =
        (my_merged_upsample_ptr)cinfo->upsample;
      upsample->spare_full = FALSE;
      upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
    } else {
      my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
      upsample->next_row_out = cinfo->max_v_samp_factor;
      upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
    }
      if (master->using_merged_upsample) {
        my_merged_upsample_ptr upsample =
          (my_merged_upsample_ptr)cinfo->upsample;
        upsample->spare_full = FALSE;
        upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
      } else {
        my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
        upsample->next_row_out = cinfo->max_v_samp_factor;
        upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
      }
    if (master->using_merged_upsample) {
      my_merged_upsample_ptr upsample =
        (my_merged_upsample_ptr)cinfo->upsample;
      upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
    } else {
      my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
      upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
    }
  if (master->using_merged_upsample) {
    my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
    upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
  } else {
    my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
    upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
  }
 * Copyright (C) 2009, 2011, 2014-2015, 2020, D. R. Commander.
#include "jdmerge.h"
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample;
  upsample = (my_merged_upsample_ptr)
                                sizeof(my_merged_upsampler));
/*
 * jdmerge.h
 *
 * This file was part of the Independent JPEG Group's software:
 * Copyright (C) 1994-1996, Thomas G. Lane.
 * libjpeg-turbo Modifications:
 * Copyright (C) 2020, D. R. Commander.
 * For conditions of distribution and use, see the accompanying README.ijg
 * file.
 */

#define JPEG_INTERNALS
#include "jpeglib.h"

#ifdef UPSAMPLE_MERGING_SUPPORTED


/* Private subobject */

typedef struct {
  struct jpeg_upsampler pub;    /* public fields */

  /* Pointer to routine to do actual upsampling/conversion of one row group */
  void (*upmethod) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
                    JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);

  /* Private state for YCC->RGB conversion */
  int *Cr_r_tab;                /* => table for Cr to R conversion */
  int *Cb_b_tab;                /* => table for Cb to B conversion */
  JLONG *Cr_g_tab;              /* => table for Cr to G conversion */
  JLONG *Cb_g_tab;              /* => table for Cb to G conversion */

  /* For 2:1 vertical sampling, we produce two output rows at a time.
   * We need a "spare" row buffer to hold the second output row if the
   * application provides just a one-row buffer; we also use the spare
   * to discard the dummy last row if the image height is odd.
   */
  JSAMPROW spare_row;
  boolean spare_full;           /* T if spare buffer is occupied */

  JDIMENSION out_row_width;     /* samples per output row */
  JDIMENSION rows_to_go;        /* counts rows remaining in image */
} my_merged_upsampler;

typedef my_merged_upsampler *my_merged_upsample_ptr;

#endif /* UPSAMPLE_MERGING_SUPPORTED */
 * Copyright (C) 2014-2015, 2018, 2020, D. R. Commander.
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
 * Copyright (C) 2011, 2015, 2020, D. R. Commander.
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
  my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;