Merge pull request #5173 from radarhere/sgi

Fix for SGI Decode buffer overrun
This commit is contained in:
Andrew Murray 2021-01-02 20:47:36 +11:00 committed by GitHub
commit 120eea2e45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 12 deletions

Binary file not shown.

View File

@ -6,7 +6,12 @@ from PIL import Image
@pytest.mark.parametrize( @pytest.mark.parametrize(
"test_file", "test_file",
["Tests/images/sgi_overrun_expandrowF04.bin", "Tests/images/sgi_crash.bin"], [
"Tests/images/sgi_overrun_expandrowF04.bin",
"Tests/images/sgi_crash.bin",
"Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi",
"Tests/images/ossfuzz-5730089102868480.sgi",
],
) )
def test_crashes(test_file): def test_crashes(test_file):
with open(test_file, "rb") as f: with open(test_file, "rb") as f:

View File

@ -112,14 +112,33 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
int err = 0; int err = 0;
int status; int status;
/* size check */
if (im->xsize > INT_MAX / im->bands ||
im->ysize > INT_MAX / im->bands) {
state->errcode = IMAGING_CODEC_MEMORY;
return -1;
}
/* Get all data from File descriptor */ /* Get all data from File descriptor */
c = (SGISTATE*)state->context; c = (SGISTATE*)state->context;
_imaging_seek_pyFd(state->fd, 0L, SEEK_END); _imaging_seek_pyFd(state->fd, 0L, SEEK_END);
c->bufsize = _imaging_tell_pyFd(state->fd); c->bufsize = _imaging_tell_pyFd(state->fd);
c->bufsize -= SGI_HEADER_SIZE; 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) {
state->errcode = IMAGING_CODEC_OVERRUN;
return -1;
}
ptr = malloc(sizeof(UINT8) * c->bufsize); ptr = malloc(sizeof(UINT8) * c->bufsize);
if (!ptr) { if (!ptr) {
return IMAGING_CODEC_MEMORY; state->errcode = IMAGING_CODEC_MEMORY;
return -1;
} }
_imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET); _imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET);
_imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize); _imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize);
@ -134,18 +153,11 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
state->ystep = 1; 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 */ /* Allocate memory for RLE tables and rows */
free(state->buffer); free(state->buffer);
state->buffer = NULL; state->buffer = NULL;
/* malloc overflow check above */ /* malloc overflow check above */
state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2); state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2);
c->tablen = im->bands * im->ysize;
c->starttab = calloc(c->tablen, sizeof(UINT32)); c->starttab = calloc(c->tablen, sizeof(UINT32));
c->lengthtab = calloc(c->tablen, sizeof(UINT32)); c->lengthtab = calloc(c->tablen, sizeof(UINT32));
if (!state->buffer || if (!state->buffer ||
@ -176,7 +188,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
if (c->rleoffset + c->rlelength > c->bufsize) { if (c->rleoffset + c->rlelength > c->bufsize) {
state->errcode = IMAGING_CODEC_OVERRUN; state->errcode = IMAGING_CODEC_OVERRUN;
return -1; goto sgi_finish_decode;
} }
/* row decompression */ /* row decompression */
@ -188,7 +200,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
} }
if (status == -1) { if (status == -1) {
state->errcode = IMAGING_CODEC_OVERRUN; state->errcode = IMAGING_CODEC_OVERRUN;
return -1; goto sgi_finish_decode;
} else if (status == 1) { } else if (status == 1) {
goto sgi_finish_decode; goto sgi_finish_decode;
} }
@ -209,7 +221,8 @@ sgi_finish_decode: ;
free(c->lengthtab); free(c->lengthtab);
free(ptr); free(ptr);
if (err != 0){ if (err != 0){
return err; state->errcode=err;
return -1;
} }
return state->count - c->bufsize; return state->count - c->bufsize;
} }