Description:
------------
Tested on PHP 7 on 32 bits with ASAN and using USE_ZEND_ALLOC=0.
user@Xenial32-2:~/crashes/gd$ USE_ZEND_ALLOC=0 gdb -q --args /home/user/php-7.0/sapi/cli/php -n phuzz4.php
Reading symbols from /home/user/php-7.0/sapi/cli/php...done.
(gdb) b gd_interpolation.c:890
Breakpoint 1 at 0x81925a9: file /home/user/php-7.0/ext/gd/libgd/gd_interpolation.c, line 890.
(gdb) b gd_interpolation.c:982 if i == 12
Breakpoint 2 at 0x81929fc: file /home/user/php-7.0/ext/gd/libgd/gd_interpolation.c, line 982.
(gdb) r
Starting program: /home/user/php-7.0/sapi/cli/php -n phuzz4.php
Breakpoint 1, _gdContributionsAlloc (line_length=13, windows_size=9) at /home/user/php-7.0/ext/gd/libgd/gd_interpolation.c:890
890 res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
# windows_size is 9
(gdb) c
Continuing.
Breakpoint 2, _gdScaleRow (pSrc=0x8c71c38, src_width=100, dst=0x8c7f5f0, dst_width=13, row=0, contrib=0x8c5c2d8)
at /home/user/php-7.0/ext/gd/libgd/gd_interpolation.c:982
982 r += (unsigned char)(contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetRed(p_src_row[i])));
(gdb) p left_channel
$1 = 9
contrib->ContribRow[x].Weights[left_channel] tries to access 10th element but the size is 9.
As you can see here, this was fixed in 2013 on upstream libgd:
https://github.com/libgd/libgd/commit/4f65a3e4eedaffa1efcf9ee1eb08f0b504fbc31a
While PHP's libgd is still wrong:
https://github.com/php/php-src/blob/master/ext/gd/libgd/gd_interpolation.c#L935-L936
Fix is just moving those two lines below the if condition. Attached a patch.
Test script:
---------------
<?php
$img = imagecreatetruecolor ( 100, 100);
imagescale($img, 13, 1, IMG_BICUBIC);
Expected result:
----------------
No crash
Actual result:
--------------
$ USE_ZEND_ALLOC=0 /ramdisk/php-70/sapi/cli/php -n phuzz4.php
=================================================================
==6666==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf1202ec8 at pc 0x0869258e bp 0xffc3db68 sp 0xffc3db58
READ of size 8 at 0xf1202ec8 thread T0
#0 0x869258d in _gdScaleRow /home/user/php-7.0asan/ext/gd/libgd/gd_interpolation.c:980
#1 0x869258d in _gdScaleHoriz /home/user/php-7.0asan/ext/gd/libgd/gd_interpolation.c:1008
#2 0x869258d in gdImageScaleTwoPass /home/user/php-7.0asan/ext/gd/libgd/gd_interpolation.c:1072
#3 0x86a1525 in gdImageScale /home/user/php-7.0asan/ext/gd/libgd/gd_interpolation.c:1659
#4 0x85ba750 in zif_imagescale /home/user/php-7.0asan/ext/gd/gd.c:4674
#5 0x9a31522 in ZEND_DO_ICALL_SPEC_HANDLER /home/user/php-7.0asan/Zend/zend_vm_execute.h:586
#6 0x980f979 in execute_ex /home/user/php-7.0asan/Zend/zend_vm_execute.h:414
#7 0x9b29bf2 in zend_execute /home/user/php-7.0asan/Zend/zend_vm_execute.h:458
#8 0x95e8bcc in zend_execute_scripts /home/user/php-7.0asan/Zend/zend.c:1427
#9 0x932dfeb in php_execute_script /home/user/php-7.0asan/main/main.c:2494
#10 0x9b32370 in do_cli /home/user/php-7.0asan/sapi/cli/php_cli.c:974
#11 0x80a6596 in main /home/user/php-7.0asan/sapi/cli/php_cli.c:1344
#12 0xf6ceb636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
#13 0x80a6b1a (/ramdisk/php-70/sapi/cli/php+0x80a6b1a)
0xf1202ec8 is located 0 bytes to the right of 72-byte region [0xf1202e80,0xf1202ec8)
allocated by thread T0 here:
#0 0xf72ead06 in malloc (/usr/lib/i386-linux-gnu/libasan.so.2+0x96d06)
#1 0x94b77d9 in _emalloc /home/user/php-7.0asan/Zend/zend_alloc.c:2446
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/user/php-7.0asan/ext/gd/libgd/gd_interpolation.c:980 _gdScaleRow
Shadow bytes around the buggy address:
0x3e240580: 00 00 00 00 00 fa fa fa fa fa 00 00 00 00 00 00
0x3e240590: 00 00 00 fa fa fa fa fa 00 00 00 00 00 00 00 00
0x3e2405a0: 00 fa fa fa fa fa 00 00 00 00 00 00 00 00 00 fa
0x3e2405b0: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa
0x3e2405c0: fa fa 00 00 00 00 00 00 00 00 00 fa fa fa fa fa
=>0x3e2405d0: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa 00 00
0x3e2405e0: 00 00 00 00 00 00 00 fa fa fa fa fa fd fd fd fd
0x3e2405f0: fd fd fd fd fd fa fa fa fa fa 00 00 00 00 00 00
0x3e240600: 00 00 01 fa fa fa fa fa fd fd fd fd fd fd fd fd
0x3e240610: fd fd fa fa fa fa fd fd fd fd fd fd fd fd fd fd
0x3e240620: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
==6666==ABORTING