Bug #72526 [Com]: segfault in curl_setopt()

From: Date: Fri, 01 Jul 2016 11:16:14 +0000
Subject: Bug #72526 [Com]: segfault in curl_setopt()
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-201956@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=72526&edit=1

 ID:                 72526
 Comment by:         lazy at iq dot pl
 Reported by:        lazy at iq dot pl
 Summary:            segfault in curl_setopt()
 Status:             Open
 Type:               Bug
 Package:            cURL related
 Operating System:   Debian Wheezy
 PHP Version:        7.0.8
 Block user comment: N
 Private report:     N

 New Comment:

ZEND_ASSUME(0) also segfaults on
gcc version 4.9.2 (Debian 4.9.2-10) - debian 8
gcc version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC) - centos 7


any chance You ware using gcc older then 4.0.5 ?


Previous Comments:
------------------------------------------------------------------------
[2016-07-01 11:03:06] lazy at iq dot pl

with some experiments I have narrowed it to calling

zend_hash_index_update_ptr(ch->to_free->slist, option, slist); with NULL slist,


Breakpoint 2, _zend_hash_index_update (ht=0x3b3e8257268, h=h@entry=10023,
pData=pData@entry=0x3eb430303e0) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_hash.c:838
838		return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
(gdb) bt
#0  _zend_hash_index_update (ht=0x3b3e8257268, h=h@entry=10023, pData=pData@entry=0x3eb430303e0) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_hash.c:838
#1  0x000000000054848e in zend_hash_index_update_ptr (pData=0x0, h=10023, ht=<optimized out>)
at /usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_hash.h:642
#2  _php_curl_setopt (ch=0x3b3e825e780, option=10023, zvalue=0x3b3e8214130) at
/usr/src/new/apache2-suexec/work/pri/php-src/ext/curl/interface.c:2680
#3  0x0000000000549224 in zif_curl_setopt (execute_data=<optimized out>,
return_value=0x3eb43030470) at
/usr/src/new/apache2-suexec/work/pri/php-src/ext/curl/interface.c:3001
#4  0x00000000007472c7 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (execute_data=0x3b3e8214030) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_vm_execute.h:632
#5  0x0000000000736a18 in execute_ex (ex=<optimized out>) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_vm_execute.h:432
#6  0x000000000078ee30 in zend_execute (op_array=op_array@entry=0x3b3e827f000,
return_value=return_value@entry=0x0) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_vm_execute.h:474
#7  0x00000000006ef314 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0,
file_count=file_count@entry=3) at /usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend.c:1441
#8  0x000000000068f0a0 in php_execute_script (primary_file=primary_file@entry=0x3eb43032980) at
/usr/src/new/apache2-suexec/work/pri/php-src/main/main.c:2532
#9  0x0000000000791000 in do_cli (argc=2, argv=0x408b690) at
/usr/src/new/apache2-suexec/work/pri/php-src/sapi/cli/php_cli.c:990
#10 0x000000000043290c in main (argc=2, argv=0x408b690) at
/usr/src/new/apache2-suexec/work/pri/php-src/sapi/cli/php_cli.c:1378
(gdb) cont
Breakpoint 2, _zend_hash_index_update (ht=0x4, h=h@entry=10023, pData=pData@entry=0x3eb430303e0) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_hash.c:838
838		return _zend_hash_index_add_or_update_i(ht, h, pData, HASH_UPDATE ZEND_FILE_LINE_RELAY_CC);
(gdb) bt
#0  _zend_hash_index_update (ht=0x4, h=h@entry=10023, pData=pData@entry=0x3eb430303e0) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_hash.c:838
#1  0x000000000054848e in zend_hash_index_update_ptr (pData=0x0, h=10023, ht=<optimized out>)
at /usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_hash.h:642
#2  _php_curl_setopt (ch=0x3b3e825e780, option=10023, zvalue=0x3b3e8214130) at
/usr/src/new/apache2-suexec/work/pri/php-src/ext/curl/interface.c:2680
#3  0x0000000000549224 in zif_curl_setopt (execute_data=<optimized out>,
return_value=0x3eb43030470) at
/usr/src/new/apache2-suexec/work/pri/php-src/ext/curl/interface.c:3001
#4  0x00000000007472c7 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (execute_data=0x3b3e8214030) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_vm_execute.h:632
#5  0x0000000000736a18 in execute_ex (ex=<optimized out>) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_vm_execute.h:432
#6  0x000000000078ee30 in zend_execute (op_array=op_array@entry=0x3b3e827f000,
return_value=return_value@entry=0x0) at
/usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend_vm_execute.h:474
#7  0x00000000006ef314 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0,
file_count=file_count@entry=3) at /usr/src/new/apache2-suexec/work/pri/php-src/Zend/zend.c:1441
#8  0x000000000068f0a0 in php_execute_script (primary_file=primary_file@entry=0x3eb43032980) at
/usr/src/new/apache2-suexec/work/pri/php-src/main/main.c:2532
#9  0x0000000000791000 in do_cli (argc=2, argv=0x408b690) at
/usr/src/new/apache2-suexec/work/pri/php-src/sapi/cli/php_cli.c:990
#10 0x000000000043290c in main (argc=2, argv=0x408b690) at
/usr/src/new/apache2-suexec/work/pri/php-src/sapi/cli/php_cli.c:1378


zend_hash_index_update_ptr() is called twice maybe because of some curruption in

Zend/zend_hash.h:644			ZEND_ASSUME(Z_PTR_P(zv));

removing Zend/zend_hash.h:644			ZEND_ASSUME(Z_PTR_P(zv));
"fixes" the problem


ZEND_ASSUME is defined as

#elif ((defined(__GNUC__) && ZEND_GCC_VERSION >= 4005) ||
__has_builtin(__builtin_unreachable)) && PHP_HAVE_BUILTIN_EXPECT
# define ZEND_ASSUME(c) do { \
                if (__builtin_expect(!(c), 0)) __builtin_unreachable(); \
        } while (0)

https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
— Built-in Function: long __builtin_expect (long exp, long c)
You may use __builtin_expect to provide the compiler with branch prediction information. In general,
you should prefer to use actual profile feedback for this (-fprofile-arcs), as programmers are
notoriously bad at predicting how their programs actually perform. However, there are applications
in which this data is hard to collect.


c is NULL so !(c) is 1 and __builtin_unreachable is called which leads to segfault maybe becaouse of
some gcc problems with __builtin_unreachable() on debian's gcc (-O0 works fine)

can we fix this by adding

if(zend_hash_num_elements(ph) == 0) {
    php_error_docref(NULL, E_WARNING, "You must pass an non empty argument");
    return 1;
}
before calling zend_hash_index_update_ptr() ?


on debian's gcc
int main() {
int *c=0;

do { \
        if (__builtin_expect(!(c), 0)) __builtin_unreachable(); \
    } while (0);
}

with -O2 is also segfaulting, -O0 is ok


what's the semantic of ZEND_ASSUME should it bail on an NULL argument ?

------------------------------------------------------------------------
[2016-06-30 15:55:20] laruence@php.net

I can not reproduce this on ubuntu

------------------------------------------------------------------------
[2016-06-30 13:48:01] lazy at iq dot pl

Description:
------------
gcc version 4.7.2 (Debian 4.7.2-5) 

compiling with O0 "fixes" the problem,

also works fine on centos 7, so it might be some optimization issue

Breakpoint 1, _php_curl_setopt (ch=0x3d61925b780, option=10023, zvalue=0x3d619213160) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/ext/curl/interface.c:2133
2133	{
(gdb) p zvalue
$1 = (zval *) 0x3d619213160
(gdb) list
2128		dupch->res = Z_RES_P(return_value);
2129	}
2130	/* }}} */
2131	
2132	static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{ */
2133	{
2134		CURLcode error = CURLE_OK;
2135		zend_long lval;
2136	
2137		ZVAL_DEREF(zvalue);
(gdb) next
2137		ZVAL_DEREF(zvalue);
(gdb) 
2133	{
(gdb) 
2137		ZVAL_DEREF(zvalue);
(gdb) 
2138		switch (option) {
(gdb) 
3626	}
(gdb) 
2603				ph = HASH_OF(zvalue);
(gdb) next
2604				if (!ph) {
(gdb) 
2650				ZEND_HASH_FOREACH_VAL(ph, current) {
(gdb) 
2661				if ((*ch->clone) == 1) {
(gdb) 
2662					zend_hash_index_update_ptr(ch->to_free->slist, option, slist);
(gdb) 
2661				if ((*ch->clone) == 1) {
(gdb) 
2662					zend_hash_index_update_ptr(ch->to_free->slist, option, slist);
(gdb) 
2822					zval_ptr_dtor(&ch->handlers->progress->func_name);
(gdb) 

Program received signal SIGSEGV, Segmentation fault.
_zval_ptr_dtor (zval_ptr=0x4) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_execute_API.c:533
533		i_zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_RELAY_CC);


gdb) bt
#0  _zval_ptr_dtor (zval_ptr=0x4) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_execute_API.c:533
#1  0x00000000005807e5 in _php_curl_setopt (ch=ch@entry=0x2c7a8fe3700, option=<optimized out>,
zvalue=zvalue@entry=0x2c7a8fe3520) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/ext/curl/interface.c:2822
#2  0x00000000005814b5 in zif_curl_setopt_array (execute_data=<optimized out>,
return_value=0x2c7a9c16660) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/ext/curl/interface.c:3015
#3  0x00000000008f8fed in ZEND_DO_FCALL_SPEC_HANDLER (execute_data=0x2c7a9c16430) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_vm_execute.h:842
#4  0x00000000008b66a0 in execute_ex (ex=<optimized out>) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_vm_execute.h:417
#5  0x0000000000907097 in zend_execute (op_array=op_array@entry=0x2c7a9c78000,
return_value=return_value@entry=0x0) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_vm_execute.h:458
#6  0x0000000000878a24 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0,
file_count=file_count@entry=3) at /usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend.c:1427
#7  0x000000000081aaa0 in php_execute_script (primary_file=primary_file@entry=0x3dcd7e2eaa0) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/main/main.c:2494
#8  0x00000000004566ca in main (argc=1, argv=0x3dcd7e2ee58) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/sapi/cgi/cgi_main.c:2453

Please look at
https://github.com/php/php-src/blob/master/ext/curl/interface.c#L2663-L2672

May it be running ZEND_HASH_FOREACH_VAL() loop on an empty hash corrupting the stack ?



Test script:
---------------
$ch=curl_init();

curl_setopt($ch, CURLOPT_HTTPHEADER, array());

Expected result:
----------------
Normal execution

Actual result:
--------------
Segfault:
gdb) bt
#0  _zval_ptr_dtor (zval_ptr=0x4) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_execute_API.c:533
#1  0x00000000005807e5 in _php_curl_setopt (ch=ch@entry=0x2c7a8fe3700, option=<optimized out>,
zvalue=zvalue@entry=0x2c7a8fe3520) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/ext/curl/interface.c:2822
#2  0x00000000005814b5 in zif_curl_setopt_array (execute_data=<optimized out>,
return_value=0x2c7a9c16660) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/ext/curl/interface.c:3015
#3  0x00000000008f8fed in ZEND_DO_FCALL_SPEC_HANDLER (execute_data=0x2c7a9c16430) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_vm_execute.h:842
#4  0x00000000008b66a0 in execute_ex (ex=<optimized out>) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_vm_execute.h:417
#5  0x0000000000907097 in zend_execute (op_array=op_array@entry=0x2c7a9c78000,
return_value=return_value@entry=0x0) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend_vm_execute.h:458
#6  0x0000000000878a24 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0,
file_count=file_count@entry=3) at /usr/src/new/apache2-suexec/work/pri/php-7.0.8/Zend/zend.c:1427
#7  0x000000000081aaa0 in php_execute_script (primary_file=primary_file@entry=0x3dcd7e2eaa0) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/main/main.c:2494
#8  0x00000000004566ca in main (argc=1, argv=0x3dcd7e2ee58) at
/usr/src/new/apache2-suexec/work/pri/php-7.0.8/sapi/cgi/cgi_main.c:2453


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=72526&edit=1


Thread (7 messages)

« previous php.bugs (#201956) next »