From f276de1139ec16395dc8b382860fb58e331fbd53 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 29 Oct 2020 23:07:15 +0000 Subject: [PATCH 1/2] Fix for SGI Decode buffer overrun CVE-2020-35655 * Independently found by a contributor and sent to Tidelift, and by Google's OSS Fuzz. --- src/libImaging/SgiRleDecode.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c index eb8fc84..c256169 100644 --- a/src/libImaging/SgiRleDecode.c +++ b/src/libImaging/SgiRleDecode.c @@ -107,11 +107,27 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, int err = 0; int status; + /* size check */ + if (im->xsize > INT_MAX / im->bands || + im->ysize > INT_MAX / im->bands) { + return IMAGING_CODEC_MEMORY; + } + /* Get all data from File descriptor */ c = (SGISTATE*)state->context; _imaging_seek_pyFd(state->fd, 0L, SEEK_END); c->bufsize = _imaging_tell_pyFd(state->fd); c->bufsize -= SGI_HEADER_SIZE; + + c->tablen = im->bands * im->ysize; + /* below, we populate the starttab and lentab into the bufsize, + each with 4 bytes per element of tablen + Check here before we allocate any memory + */ + if (c->bufsize < 8*c->tablen) { + return IMAGING_CODEC_MEMORY; + } + ptr = malloc(sizeof(UINT8) * c->bufsize); if (!ptr) { return IMAGING_CODEC_MEMORY; @@ -129,18 +145,11 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, state->ystep = 1; } - if (im->xsize > INT_MAX / im->bands || - im->ysize > INT_MAX / im->bands) { - err = IMAGING_CODEC_MEMORY; - goto sgi_finish_decode; - } - /* Allocate memory for RLE tables and rows */ free(state->buffer); state->buffer = NULL; /* malloc overflow check above */ state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2); - c->tablen = im->bands * im->ysize; c->starttab = calloc(c->tablen, sizeof(UINT32)); c->lengthtab = calloc(c->tablen, sizeof(UINT32)); if (!state->buffer || -- 2.29.2 From 18aa14484fa63dabcafea63cf0b7bfb4066e979c Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Fri, 30 Oct 2020 09:57:23 +0000 Subject: [PATCH 2/2] Make the SGI code return -1 as an error flag, error in state --- src/libImaging/SgiRleDecode.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c index c256169..2259159 100644 --- a/src/libImaging/SgiRleDecode.c +++ b/src/libImaging/SgiRleDecode.c @@ -110,7 +110,8 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, /* size check */ if (im->xsize > INT_MAX / im->bands || im->ysize > INT_MAX / im->bands) { - return IMAGING_CODEC_MEMORY; + state->errcode = IMAGING_CODEC_MEMORY; + return -1; } /* Get all data from File descriptor */ @@ -125,12 +126,14 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, Check here before we allocate any memory */ if (c->bufsize < 8*c->tablen) { - return IMAGING_CODEC_MEMORY; + state->errcode = IMAGING_CODEC_OVERRUN; + return -1; } ptr = malloc(sizeof(UINT8) * c->bufsize); if (!ptr) { - return IMAGING_CODEC_MEMORY; + state->errcode = IMAGING_CODEC_MEMORY; + return -1; } _imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET); _imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize); @@ -178,7 +181,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, if (c->rleoffset + c->rlelength > c->bufsize) { state->errcode = IMAGING_CODEC_OVERRUN; - return -1; + goto sgi_finish_decode; } /* row decompression */ @@ -190,7 +193,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state, } if (status == -1) { state->errcode = IMAGING_CODEC_OVERRUN; - return -1; + goto sgi_finish_decode; } else if (status == 1) { goto sgi_finish_decode; } @@ -211,7 +214,8 @@ sgi_finish_decode: ; free(c->lengthtab); free(ptr); if (err != 0){ - return err; + state->errcode=err; + return -1; } return state->count - c->bufsize; } -- 2.29.2