i_circle_aa_low() could buffer overflow
authorTony Cook <tony@develop-help.com>
Thu, 10 Jan 2019 12:24:43 +0000 (23:24 +1100)
committerTony Cook <tony@develop-help.com>
Thu, 10 Jan 2019 12:24:43 +0000 (23:24 +1100)
prevent it.  It still needs some work for other reasons.

Changes
draw.c
t/250-draw/010-draw.t

diff --git a/Changes b/Changes
index 6b0795f..d9f2aec 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,11 @@
 Imager release history.  Older releases can be found in Changes.old
 
+Critical issue:
+
+ - drawing a filled, anti-aliased circle to the left or right of the
+   image (not within the image at all) would cause a buffer overflow.
+   https://rt.cpan.org/Ticket/Display.html?id=128208
+
 General changes:
 
  - to_paletted() and make_palette() now fail (with an error in
diff --git a/draw.c b/draw.c
index e66af53..647c9d2 100644 (file)
--- a/draw.c
+++ b/draw.c
@@ -500,8 +500,11 @@ i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r,
   i_color temp;
   i_img_dim ly;
   dIMCTXim(im);
-  i_img_dim first_row = floor(y) - ceil(rad);
-  i_img_dim last_row = ceil(y) + ceil(rad);
+  double ceil_rad = ceil(rad);
+  i_img_dim first_row = floor(y) - ceil_rad;
+  i_img_dim last_row = ceil(y) + ceil_rad;
+  i_img_dim first_col = floor(x) - ceil_rad;
+  i_img_dim last_col = ceil(x) + ceil_rad;
   double r_sqr = rad * rad;
   i_img_dim max_width = 2 * ceil(rad) + 1;
   unsigned char *coverage = NULL;
@@ -515,8 +518,12 @@ i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r,
     first_row = 0;
   if (last_row > im->ysize-1)
     last_row = im->ysize - 1;
+  if (first_col < 0)
+    first_col = 0;
+  if (last_col > im->xsize-1)
+    last_col = im->xsize - 1;
 
-  if (rad <= 0 || last_row < first_row) {
+  if (rad <= 0 || last_row < first_row || last_col < first_col) {
     /* outside the image */
     return;
   }
@@ -527,9 +534,9 @@ i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r,
   for(ly = first_row; ly < last_row; ly++) {
     frac min_frac_x[16];
     frac max_frac_x[16];
-    i_img_dim min_frac_left_x = im->xsize * 16;
+    i_img_dim min_frac_left_x = 16 *(ceil(x) + ceil(rad));
     i_img_dim max_frac_left_x = -1;
-    i_img_dim min_frac_right_x = im->xsize * 16;
+    i_img_dim min_frac_right_x = 16 * (floor(x) - ceil(rad));
     i_img_dim max_frac_right_x = -1;
     /* reset work_y each row so the error doesn't build up */
     double work_y = ly;
index 138786f..b84f648 100644 (file)
@@ -1,6 +1,6 @@
 #!perl -w
 use strict;
-use Test::More tests => 256;
+use Test::More;
 use Imager ':all';
 use Imager::Test qw(is_color3 is_image);
 use constant PI => 3.14159265358979;
@@ -137,6 +137,13 @@ my $white = '#FFFFFF';
      "saving output");
 }
 
+{
+  # RT #128208
+  my $im = Imager->new(xsize => 200, ysize => 200);
+  ok($im->circle(aa => 1, color => "#FFF", r => 400, x => 1_000_000, y => 100, filled => 1),
+     "draw a very large circle");
+}
+
 {
   my $im = Imager->new(xsize => 400, ysize => 400);
   ok($im->arc(x => 200, y => 202, r => 10, filled => 0),
@@ -320,6 +327,7 @@ my $white = '#FFFFFF';
   is($empty->errstr, "flood_fill: empty input image", "check error message");
 }
 
+done_testing();
 
 malloc_state();