overflow an integer would cause too small a buffer to be allocated.
This could potentially be a security hole.
partly resolves https://rt.cpan.org/Ticket/Display.html?id=8213
- updated download locations for the various libraries that Imager
depends on. Added some advice for cygwin.
- more information on gif library versions in README and Makefile.PL
+- creating an image where the size of the allocated image buffer would
+ overflow an integer would cause too small a buffer to be allocated.
+ This could potentially be a security hole.
+ partly resolves https://rt.cpan.org/Ticket/Display.html?id=8213
=================================================================
i_img *
i_img_empty_ch(i_img *im,int x,int y,int ch) {
+ int bytes;
+
mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
if (x < 1 || y < 1) {
i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
return NULL;
}
+ /* check this multiplication doesn't overflow */
+ bytes = x*y*ch;
+ if (bytes / y / ch != x) {
+ i_push_errorf(0, "integer overflow calculating image allocation");
+ return NULL;
+ }
if (im == NULL)
if ( (im=mymalloc(sizeof(i_img))) == NULL)
im->ysize = y;
im->channels = ch;
im->ch_mask = MAXINT;
- im->bytes=x*y*im->channels;
- if ( (im->idata=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
+ im->bytes=bytes;
+ if ( (im->idata=mymalloc(im->bytes)) == NULL)
+ m_fatal(2,"malloc() error\n");
memset(im->idata,0,(size_t)im->bytes);
im->ext_data = NULL;
=cut
*/
i_img *i_img_16_new_low(i_img *im, int x, int y, int ch) {
+ int bytes;
mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
if (x < 1 || y < 1) {
i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
return NULL;
}
+ bytes = x * y * ch * 2;
+ if (bytes / y / ch / 2 != x) {
+ i_push_errorf(0, "integer overflow calculating image allocation");
+ return NULL;
+ }
*im = IIM_base_16bit_direct;
i_tags_new(&im->tags);
im->xsize = x;
im->ysize = y;
im->channels = ch;
- im->bytes = x * y * ch * 2;
+ im->bytes = bytes;
im->ext_data = NULL;
im->idata = mymalloc(im->bytes);
if (im->idata) {
=cut
*/
i_img *i_img_double_new_low(i_img *im, int x, int y, int ch) {
+ int bytes;
+
mm_log((1,"i_img_double_new(x %d, y %d, ch %d)\n", x, y, ch));
if (x < 1 || y < 1) {
i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
return NULL;
}
+ bytes = x * y * ch * sizeof(double);
+ if (bytes / y / ch / sizeof(double) != x) {
+ i_push_errorf(0, "integer overflow calculating image allocation");
+ return NULL;
+ }
*im = IIM_base_double_direct;
i_tags_new(&im->tags);
im->xsize = x;
im->ysize = y;
im->channels = ch;
- im->bytes = x * y * ch * sizeof(double);
+ im->bytes = bytes;
im->ext_data = NULL;
im->idata = mymalloc(im->bytes);
if (im->idata) {
*/
i_img *i_img_pal_new_low(i_img *im, int x, int y, int channels, int maxpal) {
i_img_pal_ext *palext;
+ int bytes;
i_clear_error();
if (maxpal < 0 || maxpal > 256) {
i_push_errorf(0, "Channels must be positive and <= %d", MAXCHANNELS);
return NULL;
}
+ bytes = sizeof(i_palidx) * x * y;
+ if (bytes / y / sizeof(i_palidx) != x) {
+ i_push_errorf(0, "integer overflow calculating image allocation");
+ return NULL;
+ }
memcpy(im, &IIM_base_8bit_pal, sizeof(i_img));
palext = mymalloc(sizeof(i_img_pal_ext));
palext->last_found = -1;
im->ext_data = palext;
i_tags_new(&im->tags);
- im->bytes = sizeof(i_palidx) * x * y;
+ im->bytes = bytes;
im->idata = mymalloc(im->bytes);
im->channels = channels;
memset(im->idata, 0, im->bytes);
use strict;
my $loaded;
-BEGIN { $| = 1; print "1..85\n"; }
+BEGIN { $| = 1; print "1..93\n"; }
END {print "not ok 1\n" unless $loaded;}
use Imager qw(:handy :all);
$loaded = 1;
matchn($num++, Imager->errstr, qr/channels must be between 1 and 4/,
"out of range channel message check");
+{
+ # https://rt.cpan.org/Ticket/Display.html?id=8213
+ # check for handling of memory allocation of very large images
+ # only test this on 32-bit machines - on a 64-bit machine it may
+ # result in trying to allocate 4Gb of memory, which is unfriendly at
+ # least and may result in running out of memory, causing a different
+ # type of exit
+ use Config;
+ if ($Config{ivsize} == 4) {
+ my $uint_range = 256 ** $Config{ivsize};
+ print "# range $uint_range\n";
+ my $dim1 = int(sqrt($uint_range))+1;
+
+ my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1);
+ isn($num++, $im_b, undef, "integer overflow check - 1 channel");
+
+ $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1);
+ okn($num++, $im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1);
+ okn($num++, $im_b, "but same height ok");
+ matchn($num++, Imager->errstr, qr/integer overflow/,
+ "check the error message");
+
+ # do a similar test with a 3 channel image, so we're sure we catch
+ # the same case where the third dimension causes the overflow
+ my $dim3 = int(sqrt($uint_range / 3))+1;
+
+ $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3);
+ isn($num++, $im_b, undef, "integer overflow check - 3 channel");
+
+ $im_b = Imager->new(xisze=>$dim3, ysize=>1, channels=>3);
+ okn($num++, $im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim3, channels=>3);
+ okn($num++, $im_b, "but same height ok");
+
+ matchn($num++, Imager->errstr, qr/integer overflow/,
+ "check the error message");
+ }
+ else {
+ skipn($num, 8, "don't want to allocate 4Gb");
+ $num += 8;
+ }
+}
sub check_add {
my ($base, $im, $color, $expected) = @_;
#!perl -w
use strict;
-BEGIN { $| = 1; print "1..43\n"; }
+BEGIN { $| = 1; print "1..51\n"; }
my $loaded;
END {print "not ok 1\n" unless $loaded;}
use Imager qw(:all :handy);
matchn($num++, Imager->errstr, qr/channels must be between 1 and 4/,
"and correct error message");
+{
+ # https://rt.cpan.org/Ticket/Display.html?id=8213
+ # check for handling of memory allocation of very large images
+ # only test this on 32-bit machines - on a 64-bit machine it may
+ # result in trying to allocate 4Gb of memory, which is unfriendly at
+ # least and may result in running out of memory, causing a different
+ # type of exit
+ use Config;
+ if ($Config{ivsize} == 4) {
+ my $uint_range = 256 ** $Config{ivsize};
+ print "# range $uint_range\n";
+ my $dim1 = int(sqrt($uint_range/2))+1;
+
+ my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1, bits=>16);
+ isn($num++, $im_b, undef, "integer overflow check - 1 channel");
+
+ $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1, bits=>16);
+ okn($num++, $im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1, bits=>16);
+ okn($num++, $im_b, "but same height ok");
+ matchn($num++, Imager->errstr, qr/integer overflow/,
+ "check the error message");
+
+ # do a similar test with a 3 channel image, so we're sure we catch
+ # the same case where the third dimension causes the overflow
+ my $dim3 = int(sqrt($uint_range / 3 / 2))+1;
+
+ $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3, bits=>16);
+ isn($num++, $im_b, undef, "integer overflow check - 3 channel");
+
+ $im_b = Imager->new(xisze=>$dim3, ysize=>1, channels=>3, bits=>16);
+ okn($num++, $im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim3, channels=>3, bits=>16);
+ okn($num++, $im_b, "but same height ok");
+
+ matchn($num++, Imager->errstr, qr/integer overflow/,
+ "check the error message");
+ }
+ else {
+ skipn($num, 8, "don't want to allocate 4Gb");
+ $num += 8;
+ }
+}
+
sub NCF {
return Imager::Color::Float->new(@_);
}
#!perl -w
use strict;
-BEGIN { $| = 1; print "1..42\n"; }
+BEGIN { $| = 1; print "1..50\n"; }
my $loaded;
END {print "not ok 1\n" unless $loaded;}
use Imager qw(:all :handy);
matchn($num++, Imager->errstr, qr/channels must be between 1 and 4/,
"and correct message");
+{
+ # https://rt.cpan.org/Ticket/Display.html?id=8213
+ # check for handling of memory allocation of very large images
+ # only test this on 32-bit machines - on a 64-bit machine it may
+ # result in trying to allocate 4Gb of memory, which is unfriendly at
+ # least and may result in running out of memory, causing a different
+ # type of exit
+ use Config;
+ if ($Config{ivsize} == 4) {
+ my $uint_range = 256 ** $Config{ivsize};
+ my $dbl_size = $Config{doublesize} || 8;
+ my $dim1 = int(sqrt($uint_range/$dbl_size))+1;
+
+ my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1, bits=>'double');
+ isn($num++, $im_b, undef, "integer overflow check - 1 channel");
+
+ $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1, bits=>'double');
+ okn($num++, $im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1, bits=>'double');
+ okn($num++, $im_b, "but same height ok");
+ matchn($num++, Imager->errstr, qr/integer overflow/,
+ "check the error message");
+
+ # do a similar test with a 3 channel image, so we're sure we catch
+ # the same case where the third dimension causes the overflow
+ my $dim3 = int(sqrt($uint_range / 3 / $dbl_size))+1;
+
+ $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3, bits=>'double');
+ isn($num++, $im_b, undef, "integer overflow check - 3 channel");
+
+ $im_b = Imager->new(xisze=>$dim3, ysize=>1, channels=>3, bits=>'double');
+ okn($num++, $im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim3, channels=>3, bits=>'double');
+ okn($num++, $im_b, "but same height ok");
+
+ matchn($num++, Imager->errstr, qr/integer overflow/,
+ "check the error message");
+ }
+ else {
+ skipn($num, 8, "don't want to allocate 4Gb");
+ $num += 8;
+ }
+}
+
sub NCF {
return Imager::Color::Float->new(@_);
}
my $loaded;
BEGIN {
require "t/testtools.pl";
- $| = 1; print "1..49\n";
+ $| = 1; print "1..57\n";
}
END { okx(0, "loading") unless $loaded; }
use Imager;
matchx(Imager->errstr, qr/Channels must be positive and <= 4/,
"and correct error message");
+{
+ # https://rt.cpan.org/Ticket/Display.html?id=8213
+ # check for handling of memory allocation of very large images
+ # only test this on 32-bit machines - on a 64-bit machine it may
+ # result in trying to allocate 4Gb of memory, which is unfriendly at
+ # least and may result in running out of memory, causing a different
+ # type of exit
+ use Config;
+ if ($Config{ivsize} == 4) {
+ my $uint_range = 256 ** $Config{ivsize};
+ my $dim1 = int(sqrt($uint_range))+1;
+
+ my $im_b = Imager->new(xsize=>$dim1, ysize=>$dim1, channels=>1, type=>'paletted');
+ isx($im_b, undef, "integer overflow check - 1 channel");
+
+ $im_b = Imager->new(xisze=>$dim1, ysize=>1, channels=>1, type=>'paletted');
+ okx($im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim1, channels=>1, type=>'paletted');
+ okx($im_b, "but same height ok");
+ matchx(Imager->errstr, qr/integer overflow/,
+ "check the error message");
+
+ # do a similar test with a 3 channel image, so we're sure we catch
+ # the same case where the third dimension causes the overflow
+ # for paletted images the third dimension can't cause an overflow
+ # but make sure we didn't anything too dumb in the checks
+ my $dim3 = $dim1;
+
+ $im_b = Imager->new(xsize=>$dim3, ysize=>$dim3, channels=>3, type=>'paletted');
+ isx($im_b, undef, "integer overflow check - 3 channel");
+
+ $im_b = Imager->new(xisze=>$dim3, ysize=>1, channels=>3, type=>'paletted');
+ okx($im_b, "but same width ok");
+ $im_b = Imager->new(xisze=>1, ysize=>$dim3, channels=>3, type=>'paletted');
+ okx($im_b, "but same height ok");
+
+ matchx(Imager->errstr, qr/integer overflow/,
+ "check the error message");
+ }
+ else {
+ skipx(8, "don't want to allocate 4Gb");
+ }
+}
+
sub coloreq {
my ($left, $right, $comment) = @_;