mjpegdec: consider chroma subsampling in size check

If the chroma components are subsampled, smaller buffers are allocated
for them. In that case the maximal block_offset for the chroma
components is not as large as for the luma component.

This fixes out of bounds writes causing segmentation faults or memory
corruption.

Reviewed-by: Michael Niedermayer <michael@niedermayer.cc>
Signed-off-by: Andreas Cadhalpun <Andreas.Cadhalpun@googlemail.com>
(cherry picked from commit 5adb5d9d89)

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
Andreas Cadhalpun 2015-12-02 21:52:23 +01:00 committed by Michael Niedermayer
parent 9f0e36b101
commit 073fcfe358
1 changed files with 8 additions and 3 deletions

View File

@ -1197,7 +1197,7 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
int mb_bitmask_size, int mb_bitmask_size,
const AVFrame *reference) const AVFrame *reference)
{ {
int i, mb_x, mb_y; int i, mb_x, mb_y, chroma_h_shift, chroma_v_shift, chroma_width, chroma_height;
uint8_t *data[MAX_COMPONENTS]; uint8_t *data[MAX_COMPONENTS];
const uint8_t *reference_data[MAX_COMPONENTS]; const uint8_t *reference_data[MAX_COMPONENTS];
int linesize[MAX_COMPONENTS]; int linesize[MAX_COMPONENTS];
@ -1214,6 +1214,11 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
s->restart_count = 0; s->restart_count = 0;
av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &chroma_h_shift,
&chroma_v_shift);
chroma_width = FF_CEIL_RSHIFT(s->width, chroma_h_shift);
chroma_height = FF_CEIL_RSHIFT(s->height, chroma_v_shift);
for (i = 0; i < nb_components; i++) { for (i = 0; i < nb_components; i++) {
int c = s->comp_index[i]; int c = s->comp_index[i];
data[c] = s->picture_ptr->data[c]; data[c] = s->picture_ptr->data[c];
@ -1250,8 +1255,8 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
if (s->interlaced && s->bottom_field) if (s->interlaced && s->bottom_field)
block_offset += linesize[c] >> 1; block_offset += linesize[c] >> 1;
if ( 8*(h * mb_x + x) < s->width if ( 8*(h * mb_x + x) < ((c == 1) || (c == 2) ? chroma_width : s->width)
&& 8*(v * mb_y + y) < s->height) { && 8*(v * mb_y + y) < ((c == 1) || (c == 2) ? chroma_height : s->height)) {
ptr = data[c] + block_offset; ptr = data[c] + block_offset;
} else } else
ptr = NULL; ptr = NULL;