PHP 7.0.6 imagescale out-of-bounds read
Posted on 30 November -0001
<HTML><HEAD><TITLE>PHP 7.0.6 imagescale out-of-bounds read</TITLE><META http-equiv="Content-Type" content="text/html; charset=utf-8"></HEAD><BODY>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 </BODY></HTML>