Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions ext/gd/libgd/gd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2326,8 +2326,47 @@ void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int
_gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
}

static int _gdValidateCopyRectBounds(
const gdImagePtr dst,
const gdImagePtr src,
int dstX, int dstY,
int srcX, int srcY,
int w, int h
) {
/* Check for null pointers */
if (!dst || !src) {
return 0;
}

/* Check for overflow in dstX + w */
if (w > 0 && dstX > INT_MAX - w) {
return 0;
}

/* Check for overflow in dstY + h */
if (h > 0 && dstY > INT_MAX - h) {
return 0;
}

/* Check for overflow in srcX + w */
if (w > 0 && srcX > INT_MAX - w) {
return 0;
}

/* Check for overflow in srcY + h */
if (h > 0 && srcY > INT_MAX - h) {
return 0;
}

return 1;
}

void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
{
if (!_gdValidateCopyRectBounds(dst, src, dstX, dstY, srcX, srcY, w, h)) {
return;
}

int c;
int x, y;
int tox, toy;
Expand Down Expand Up @@ -2409,6 +2448,10 @@ void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX,
so it doesn't pay attention to the alpha channel. */
void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
{
if (!_gdValidateCopyRectBounds(dst, src, dstX, dstY, srcX, srcY, w, h)) {
return;
}

int c, dc;
int x, y;
int tox, toy;
Expand Down Expand Up @@ -2449,6 +2492,10 @@ void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int s
so it doesn't pay attention to the alpha channel. */
void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
{
if (!_gdValidateCopyRectBounds(dst, src, dstX, dstY, srcX, srcY, w, h)) {
return;
}

int c, dc;
int x, y;
int tox, toy;
Expand Down Expand Up @@ -2503,6 +2550,14 @@ void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, i

void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
{
if (!_gdValidateCopyRectBounds(dst, src, dstX, dstY, srcX, srcY, dstW, dstH)) {
return;
}

if (!_gdValidateCopyRectBounds(dst, src, dstX, dstY, srcX, srcY, srcW, srcH)) {
return;
}

int c;
int x, y;
int tox, toy;
Expand Down Expand Up @@ -2613,6 +2668,14 @@ void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int

void gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
{
if (!_gdValidateCopyRectBounds(dst, src, dstX, dstY, srcX, srcY, dstW, dstH)) {
return;
}

if (!_gdValidateCopyRectBounds(dst, src, dstX, dstY, srcX, srcY, srcW, srcH)) {
return;
}

int x, y;
double sy1, sy2, sx1, sx2;

Expand Down
79 changes: 79 additions & 0 deletions ext/gd/tests/gh21163.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
--TEST--
GH-17772 (prevents signed int overflow in gdImageCopy functions)
--EXTENSIONS--
gd
--SKIPIF--
<?php
if (!GD_BUNDLED) die("skip requires bundled GD library");
?>
--FILE--
<?php
function makeImages(): array {
$dst = imagecreatetruecolor(2, 2);
$src = imagecreatetruecolor(2, 2);

$blackDst = imagecolorallocate($dst, 0, 0, 0);
$whiteSrc = imagecolorallocate($src, 255, 255, 255);

imagefilledrectangle($dst, 0, 0, 1, 1, $blackDst);
imagefilledrectangle($src, 0, 0, 1, 1, $whiteSrc);

return [$dst, $src];
}

function assertDstUnchanged(string $label, $dst, int $expectedColor): void {
$actual = imagecolorat($dst, 0, 0);
if ($actual !== $expectedColor) {
echo "FAIL $label: dst changed, got $actual expected $expectedColor\n";
return;
}
echo "OK $label\n";
}

/*
Use values that will overflow a 32 bit signed int when adding w or h.
INT_MAX is 0x7fffffff.
*/
$nearIntMax = 0x7fffffff - 5;
$w = 10;
$h = 10;

/* imagecopy */
[$dst, $src] = makeImages();
$expected = imagecolorat($dst, 0, 0);
imagecopy($dst, $src, $nearIntMax, 0, 0, 0, $w, $h);
assertDstUnchanged('imagecopy', $dst, $expected);

/* imagecopymerge */
[$dst, $src] = makeImages();
$expected = imagecolorat($dst, 0, 0);
imagecopymerge($dst, $src, $nearIntMax, 0, 0, 0, $w, $h, 50);
assertDstUnchanged('imagecopymerge', $dst, $expected);

/* imagecopymergegray */
[$dst, $src] = makeImages();
$expected = imagecolorat($dst, 0, 0);
imagecopymergegray($dst, $src, $nearIntMax, 0, 0, 0, $w, $h, 50);
assertDstUnchanged('imagecopymergegray', $dst, $expected);

/* imagecopyresized */
[$dst, $src] = makeImages();
$expected = imagecolorat($dst, 0, 0);
imagecopyresized($dst, $src, $nearIntMax, 0, 0, 0, $w, $h, 1, 1);
assertDstUnchanged('imagecopyresized', $dst, $expected);

/* imagecopyresampled */
[$dst, $src] = makeImages();
$expected = imagecolorat($dst, 0, 0);
imagecopyresampled($dst, $src, $nearIntMax, 0, 0, 0, $w, $h, 1, 1);
assertDstUnchanged('imagecopyresampled', $dst, $expected);

echo "done\n";
?>
--EXPECT--
OK imagecopy
OK imagecopymerge
OK imagecopymergegray
OK imagecopyresized
OK imagecopyresampled
done
Loading