Index: generic/tkImgGIF.c ================================================================== --- generic/tkImgGIF.c +++ generic/tkImgGIF.c @@ -1391,10 +1391,11 @@ if (handle->length <= 0 || (size_t) handle->length < hunk*count) { return -1; } memcpy(dst, handle->data, (size_t) (hunk * count)); handle->data += hunk * count; + handle->length -= hunk * count; return (int)(hunk * count); } /* * Otherwise we've got a real file to read. Index: generic/tkImgPhoto.c ================================================================== --- generic/tkImgPhoto.c +++ generic/tkImgPhoto.c @@ -3006,10 +3006,14 @@ } if (masterPtr->userHeight > 0) { height = masterPtr->userHeight; } + if (width > INT_MAX / 4) { + /* Pitch overflows int */ + return TCL_ERROR; + } pitch = width * 4; /* * Test if we're going to (re)allocate the main buffer now, so that any * failures will leave the photo unchanged. @@ -3020,10 +3024,14 @@ /* * Not a u-long, but should be one. */ unsigned /*long*/ newPixSize = (unsigned /*long*/) (height * pitch); + + if (pitch && height > (int)(UINT_MAX / pitch)) { + return TCL_ERROR; + } /* * Some mallocs() really hate allocating zero bytes. [Bug 619544] */ @@ -3071,18 +3079,18 @@ */ if ((masterPtr->pix32 != NULL) && ((width == masterPtr->width) || (width == validBox.width))) { if (validBox.y > 0) { - memset(newPix32, 0, (size_t) (validBox.y * pitch)); + memset(newPix32, 0, ((size_t) validBox.y * pitch)); } h = validBox.y + validBox.height; if (h < height) { - memset(newPix32 + h*pitch, 0, (size_t) ((height - h) * pitch)); + memset(newPix32 + h*pitch, 0, ((size_t) (height - h) * pitch)); } } else { - memset(newPix32, 0, (size_t) (height * pitch)); + memset(newPix32, 0, ((size_t) height * pitch)); } if (masterPtr->pix32 != NULL) { /* * Copy the common area over to the new array array and free the @@ -3095,11 +3103,11 @@ * The region to be copied is contiguous. */ offset = validBox.y * pitch; memcpy(newPix32 + offset, masterPtr->pix32 + offset, - (size_t) (validBox.height * pitch)); + ((size_t) validBox.height * pitch)); } else if ((validBox.width > 0) && (validBox.height > 0)) { /* * Area to be copied is not contiguous - copy line by line. */ @@ -3106,11 +3114,11 @@ destPtr = newPix32 + (validBox.y * width + validBox.x) * 4; srcPtr = masterPtr->pix32 + (validBox.y * masterPtr->width + validBox.x) * 4; for (h = validBox.height; h > 0; h--) { - memcpy(destPtr, srcPtr, (size_t) (validBox.width * 4)); + memcpy(destPtr, srcPtr, ((size_t) validBox.width * 4)); destPtr += width * 4; srcPtr += masterPtr->width * 4; } } @@ -3264,11 +3272,11 @@ */ if (masterPtr->width == instancePtr->width) { offset = validBox.y * masterPtr->width * 3; memcpy(newError + offset, instancePtr->error + offset, - (size_t) (validBox.height + ((size_t) validBox.height * masterPtr->width * 3 * sizeof(schar))); } else if (validBox.width > 0 && validBox.height > 0) { errDestPtr = newError + (validBox.y * masterPtr->width + validBox.x) * 3; @@ -4417,11 +4425,11 @@ && (width <= blockPtr->width) && (height <= blockPtr->height) && ((height == 1) || ((x == 0) && (width == masterPtr->width) && (blockPtr->pitch == pitch))) && (compRule == TK_PHOTO_COMPOSITE_SET)) { memmove(destLinePtr, blockPtr->pixelPtr + blockPtr->offset[0], - (size_t) (height * width * 4)); + ((size_t) height * width * 4)); /* * We know there's an alpha offset and we're setting the data, so skip * directly to the point when we recompute the photo validity region. */ @@ -4449,11 +4457,11 @@ if ((pixelSize == 4) && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3) && (width <= blockPtr->width) && compRuleSet) { - memcpy(destLinePtr, srcLinePtr, (size_t) (width * 4)); + memcpy(destLinePtr, srcLinePtr, ((size_t) width * 4)); srcLinePtr += blockPtr->pitch; destLinePtr += pitch; continue; } @@ -5423,16 +5431,16 @@ * Clear out the 32-bit pixel storage array. Clear out the dithering error * arrays for each instance. */ memset(masterPtr->pix32, 0, - (size_t) (masterPtr->width * masterPtr->height * 4)); + ((size_t) masterPtr->width * masterPtr->height * 4)); for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; instancePtr = instancePtr->nextPtr) { if (instancePtr->error) { memset(instancePtr->error, 0, - (size_t) (masterPtr->width * masterPtr->height + ((size_t) masterPtr->width * masterPtr->height * 3 * sizeof(schar))); } } /* ADDED tests/corruptMangled.gif Index: tests/corruptMangled.gif ================================================================== --- /dev/null +++ tests/corruptMangled.gif cannot compute difference between binary files ADDED tests/corruptMangled4G.gif Index: tests/corruptMangled4G.gif ================================================================== --- /dev/null +++ tests/corruptMangled4G.gif @@ -0,0 +1,2 @@ +GIF89aÂf3ÿÿ33ÿ3ÿ3ÿ33ÿÿÿÿ3ÿÿÿ!ù +,!xºÜ-0Bw¤ïÚ¥µê×Jâ8Uæªkir/3Re7 ; ADDED tests/corruptTruncated.gif Index: tests/corruptTruncated.gif ================================================================== --- /dev/null +++ tests/corruptTruncated.gif cannot compute difference between binary files Index: tests/imgPhoto.test ================================================================== --- tests/imgPhoto.test +++ tests/imgPhoto.test @@ -25,10 +25,18 @@ # find the teapot.ppm file for use in these tests set teapotPhotoFile [file join [file dirname [info script]] teapot.ppm] testConstraint hasTeapotPhoto [file exists $teapotPhotoFile] +proc base64ok {} { + expr { + ![catch {package require base64}] + } +} + +testConstraint base64PackageNeeded [base64ok] + test imgPhoto-1.1 {options for photo images} { image create photo p1 -width 79 -height 83 list [lindex [p1 configure -width] 4] [lindex [p1 configure -height] 4] \ [image width p1] [image height p1] } {79 83 79 83} @@ -721,13 +729,154 @@ set i [image create photo] $i put red -to 0 0 1000 1000 $i copy $i -from 0 0 1000 1000 -to 500 0 image delete $i } {} + +# Reject corrupted or truncated image [Bug b601ce3ab1]. +# WARNING - tests 18.1-18.9 will cause a segfault on 8.5.19 and lower, +# and on 8.6.6 and lower. +test imgPhoto-18.1 {Reject corrupted GIF (binary string)} -constraints { + base64PackageNeeded +} -setup { + package require base64 + set data [base64::decode { + R0lGODlhAAQABP8zM/8z/zP/MzP/////M////yH5CiwheLrcLTBCd6Tv2qW16tdK4jhV + 5qpraXIvM1JlNyAgOw== + }] +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp +test imgPhoto-18.2 {Reject corrupted GIF (base 64 string)} -setup { + set data { + R0lGODlhAAQABP8zM/8z/zP/MzP/////M////yH5CiwheLrcLTBCd6Tv2qW16tdK4jhV + 5qpraXIvM1JlNyAgOw== + } +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp +test imgPhoto-18.3 {Reject corrupted GIF (file)} -setup { + set fileName [file join [file dirname [info script]] corruptMangled.gif] +} -body { + image create photo gif1 -file $fileName +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp +test imgPhoto-18.4 {Reject truncated GIF (binary string)} -constraints { + base64PackageNeeded +} -setup { + package require base64 + set data [base64::decode { + R0lGODlhEAAQAMIHAAAAADMz//8zM/8z/zP/MzP///8= + }] +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map} +test imgPhoto-18.5 {Reject truncated GIF (base 64 string)} -setup { + set data { + R0lGODlhEAAQAMIHAAAAADMz//8zM/8z/zP/MzP///8= + } +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map} +test imgPhoto-18.6 {Reject truncated GIF (file)} -setup { + set fileName [file join [file dirname [info script]] corruptTruncated.gif] +} -body { + image create photo gif1 -file $fileName +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map} +test imgPhoto-18.7 {Reject corrupted GIF (> 4Gb) (binary string)} -constraints { + base64PackageNeeded nonPortable +} -setup { + # About the non portability constraint of this test: see ticket [cc42cc18a5] + # If there is insufficient memory, the error message + # {not enough free memory for image buffer} should be returned. + # Instead, some systems (e.g. FreeBSD 11.1) terminate the test interpreter. + package require base64 + set data [base64::decode { + R0lGODlhwmYz//8zM/8z/zP/MzP/////M////yH5Ciwhe + LrcLTBCd6Tv2qW16tdK4jhV5qpraXIvM1JlNyAgOw== + }] +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp +test imgPhoto-18.8 {Reject corrupted GIF (> 4Gb) (base 64 string)} -constraints { + nonPortable +} -setup { + # About the non portability constraint of this test: see ticket [cc42cc18a5] + # If there is insufficient memory, the error message + # {not enough free memory for image buffer} should be returned. + # Instead, some systems (e.g. FreeBSD 11.1) terminate the test interpreter. + set data { + R0lGODlhwmYz//8zM/8z/zP/MzP/////M////yH5Ciwhe + LrcLTBCd6Tv2qW16tdK4jhV5qpraXIvM1JlNyAgOw== + } +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp +test imgPhoto-18.9 {Reject corrupted GIF (> 4Gb) (file)} -constraints { + nonPortable +} -setup { + # About the non portability constraint of this test: see ticket [cc42cc18a5] + # If there is insufficient memory, the error message + # {not enough free memory for image buffer} should be returned. + # Instead, some systems (e.g. FreeBSD 11.1) terminate the test interpreter. + set fileName [file join [file dirname [info script]] corruptMangled4G.gif] +} -body { + image create photo gif1 -file $fileName +} -cleanup { + catch {image delete gif1} +} -returnCodes error -result {error reading color map|not enough free memory for image buffer} -match regexp +test imgPhoto-18.10 {Valid GIF (binary string)} -constraints { + base64PackageNeeded +} -setup { + # Test the binary string reader with a valid GIF. + # This is not tested elsewhere. + # Tests 18.11, 18.12, with matching data, are included for completeness. + package require base64 + set data [base64::decode { + R0lGODlhEAAQAMIHAAAAADMz//8zM/8z/zP/MzP/////M////yH5BAEKAAcALAAA + AAAQABAAAAMheLrcLTBCd6QV79qlterXB0riOFXmmapraXIvM1IdZTcJADs= + }] +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -result gif1 +test imgPhoto-18.11 {Valid GIF (base 64 string)} -setup { + set data { + R0lGODlhEAAQAMIHAAAAADMz//8zM/8z/zP/MzP/////M////yH5BAEKAAcALAAA + AAAQABAAAAMheLrcLTBCd6QV79qlterXB0riOFXmmapraXIvM1IdZTcJADs= + } +} -body { + image create photo gif1 -data $data +} -cleanup { + catch {image delete gif1} +} -result gif1 +test imgPhoto-18.12 {Valid GIF (file)} -setup { + set fileName [file join [file dirname [info script]] red.gif] +} -body { + image create photo gif1 -file $fileName +} -cleanup { + catch {image delete gif1} +} -result gif1 destroy .c eval image delete [image names] # cleanup removeFile README-imgPhoto cleanupTests return ADDED tests/red.gif Index: tests/red.gif ================================================================== --- /dev/null +++ tests/red.gif cannot compute difference between binary files