Maksymilian Arciemowicz reported multiple NULL pointer dereference flaws in PHP. PHP contains multiple unchecked calls to malloc(). If one of these flaws fail, it could lead to a NULL pointer dereference, potentially overwriting arbitrary memory. It is not currently known how to exploit this flaw in PHP. The possibility cannot be ruled out though.
Advisory from Full Disclosure: [ PHP 5.3.6 multiple null pointer dereference ] Author: Maksymilian Arciemowicz http://securityreason.com/ http://securityreason.net/ http://cxib.net/ Date: - - Dis.: 20.07.2011 - - Pub.: 19.08.2011 Affected Software (verified): PHP 5.3.6 and prior Fixed: PHP 5.3.7 Original URL: http://securityreason.com/achievement_securityalert/101 - --- 0.Description --- PHP is a general-purpose scripting language originally designed for web development to produce dynamic web pages. For this purpose, PHP code is embedded into the HTML source document and interpreted by a web server with a PHP processor module, which generates the web page document. It also has evolved to include a command-line interface capability and can be used in standalone graphical applications. - --- 1. PHP 5.3.6 multiple null pointer dereference --- Some time ago we have reported list with possible NULL pointer dereferences in php 5.3.6. If user may change size of malloc, it's possible to get NULL pointer dereferences. I haven't enought time to check security impacts for all these bugs. To demonstrate these flaws, we may use default memory limit in OpenBSD [512MB]. We should allocate a lot of memory like 510MB (still 2MB free). If some string is longer than 2MB (example 4MB), and php try copy this string using malloc/strlen etc then malloc return NULL. Then program is counting with possible NULL pointer dereference or buffer overflow sympthons. Example: http://cwe.mitre.org/data/definitions/690.html where CWE-690 give CWE-476 NULL pointer dereference good example for CWE-690 is tz->location.comments = malloc(comments_len + 1); memcpy(tz->location.comments, *tzf, comments_len); This code may provide to null pointer dereference or simple crash with nulling memory with memset() in.str = malloc((e - s) + YYMAXFILL); memset(in.str, 0, (e - s) + YYMAXFILL); memcpy(in.str, s, (e - s)); Program received signal SIGSEGV, Segmentation fault. 0xbba7581c in memset () from /usr/lib/libc.so.12 (gdb) x/i $eip 0xbba7581c <memset+44>: rep stos %eax,%es:(%edi) (gdb) x/x $eax 0x0: Cannot access memory at address 0x0 (gdb) x/x $edi 0x0: Cannot access memory at address 0x0 In this case, memset() overwrite the memory with 0x0 char. If attacker can put something else that 0x0, it would have security impact. There are more interesting places, where user may try change size of malloc. See bellow - -id0-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/curl/interface.c?view=markup 820 if (!CRYPTO_get_id_callback()) { 821 int i, c = CRYPTO_num_locks(); 822 823 php_curl_openssl_tsl = malloc(c * sizeof(MUTEX_T)); 824 825 for (i = 0; i < c; ++i) { 826 php_curl_openssl_tsl[i] = tsrm_mutex_alloc(); 827 } 828 829 CRYPTO_set_id_callback(php_curl_ssl_id); 830 CRYPTO_set_locking_callback(php_curl_ssl_lock); 831 } - -id0-end--------- - -id1-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_date.c?view=markup http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_iso_intervals.c?view=markup multiple malloc/calloc/realloc 323 uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BSIZE)*sizeof(uchar)); 324 memcpy(buf, s->tok, s->lim - s->tok); 496 str = calloc(1, end - begin + 1); 497 memcpy(str, begin, end - begin); 346 s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message)); 347 s->errors->warning_messages[s->errors->warning_count - 1].position = s->tok ? s->tok - s->str : 0; 348 s->errors->warning_messages[s->errors->warning_count - 1].character = s->tok ? *s->tok : 0; 349 s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error); - -id1-end--------- - -id2-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_tz.c?view=markup 210 tz->location.comments = malloc(comments_len + 1); 211 memcpy(tz->location.comments, *tzf, comments_len); 212 tz->location.comments[comments_len] = '\0'; 213 *tzf += comments_len; - -id2-end--------- - -id3-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/timelib.c?revision=305315&view=markup 124 tmp->trans = (int32_t *) malloc(tz->timecnt * sizeof(int32_t)); 125 tmp->trans_idx = (unsigned char*) malloc(tz->timecnt * sizeof(unsigned char)); 126 memcpy(tmp->trans, tz->trans, tz->timecnt * sizeof(int32_t)); 127 memcpy(tmp->trans_idx, tz->trans_idx, tz->timecnt * sizeof(unsigned char)); 128 129 tmp->type = (ttinfo*) malloc(tz->typecnt * sizeof(struct ttinfo)); 130 memcpy(tmp->type, tz->type, tz->typecnt * sizeof(struct ttinfo)); 131 132 tmp->timezone_abbr = (char*) malloc(tz->charcnt); 133 memcpy(tmp->timezone_abbr, tz->timezone_abbr, tz->charcnt); 134 135 tmp->leap_times = (tlinfo*) malloc(tz->leapcnt * sizeof(tlinfo)); 136 memcpy(tmp->leap_times, tz->leap_times, tz->leapcnt * sizeof(tlinfo)); - -id3-end--------- - -id4-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/pdo_odbc/pdo_odbc.c?view=markup 98 char *instance = INI_STR("pdo_odbc.db2_instance_name"); 99 if (instance) { 100 char *env = malloc(sizeof("DB2INSTANCE=") + strlen(instance)); 101 strcpy(env, "DB2INSTANCE="); 102 strcat(env, instance); 103 putenv(env); - -id4-end--------- - -id5-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/reflection/php_reflection.c?view=markup 238 class_entry->interfaces = (zend_class_entry **) realloc(class_entry->interfaces, sizeof(zend_class_entry *) * num_interfaces); 239 class_entry->interfaces[num_interfaces - 1] = interface_entry; - -id5-end--------- - -id6-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/soap/php_sdl.c?view=markup 2368 prest = malloc(sizeof(sdlRestrictionChar)); 2369 memset(prest, 0, sizeof(sdlRestrictionChar)); - -id6-end--------- - -id7-start--------- http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/xmlrpc/libxmlrpc/base64.c?view=markup 26 b->data = malloc(sizeof(char)*(b->length)); 27 b->data[0] = 0; 38 b->data = realloc(b->data, b->length); 39 b->ptr = b->data + b->offset; - -id7-end--------- - -id8-start--------- http://svn.php.net/viewvc/php/php-src/trunk/TSRM/tsrm_win32.c?view=markup 532 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2); 533 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command); 534 if (asuser) { 535 res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process); 536 CloseHandle(token_user); - -id8-end--------- - --- 2. PoC (realloc/malloc) --- This proof of concept was verified on NetBSD with php 5.3.7. 127# ulimit -m 100000 127# ulimit -v 100000 127# cat /www/strtotime.php <?php $strx=str_repeat("A",$argv[1]); var_dump(strtotime($strx)); ?>127# 127# /cxib/5371/build/bin/php /www/strtotime.php 33388888 Memory fault (core dumped) 127# gdb -q /cxib/5371/build/bin/php (gdb) r /www/strtotime.php 33388888 Starting program: /cxib/5371/build/bin/php /www/strtotime.php 33388888 Program received signal SIGSEGV, Segmentation fault. 0x0806e8bd in add_error (s=0xbfbfcf90, error=0x83ea7d8 "Double timezone specification") at /cxib/5371/ext/date/lib/parse_date.c:355 355 s->errors->error_messages[s->errors->error_count - 1].position = s->tok ? s->tok - s->str : 0; (gdb) print s->errors->error_messages $1 = (struct timelib_error_message *) 0x0 (gdb) print s->errors->error_count $2 = 1835009 - --- 3. Fix --- Use PHP 5.3.7 - --- 4. Greets --- PHP Team for fixes and discussions. sp3x infospec - --- 5. Contact --- Author: Maksymilian Arciemowicz Email: - - cxib {a\./t] securityreason [d=t} com GPG: - - http://securityreason.com/key/Arciemowicz.Maksymilian.gpg http://securityreason.com/ http://securityreason.net/ http://cxib.net/
Following commits to the 5.3 branch would resolve the issue: r313903 | pajoye | 2011-07-29 02:46:51 +0530 (Fri, 29 Jul 2011) | 1 line - Fix #55301 (sybase part, take #2) check if malloc succeded ------------------------------------------------------------------------ r313835 | pajoye | 2011-07-28 16:31:04 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (mssql part) check if malloc succeded ------------------------------------------------------------------------ r313833 | pajoye | 2011-07-28 16:27:31 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (sybase part) check if malloc succeded ------------------------------------------------------------------------ r313832 | pajoye | 2011-07-28 16:22:45 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (url scanner part) check if malloc succeded ------------------------------------------------------------------------ r313831 | pajoye | 2011-07-28 16:12:45 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (readline part) check if malloc succeded ------------------------------------------------------------------------ r313830 | pajoye | 2011-07-28 16:09:19 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (interbase part) check if malloc succeded ------------------------------------------------------------------------ r313828 | pajoye | 2011-07-28 16:07:04 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (pdo_odbc part) check if malloc succeded ------------------------------------------------------------------------ r313827 | pajoye | 2011-07-28 16:04:16 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (com_dotnet part) check if malloc succeded ------------------------------------------------------------------------ r313826 | pajoye | 2011-07-28 16:01:34 +0530 (Thu, 28 Jul 2011) | 1 line - Fix #55301 (curl part) check if malloc succeded ------------------------------------------------------------------------ r313782 | pajoye | 2011-07-27 19:53:06 +0530 (Wed, 27 Jul 2011) | 1 line - Fix #55295, check if malloc failed
php upstream bug: https://bugs.php.net/bug.php?id=55301
Statement: Red Hat does not consider this flaw to be a security issue. It is improbable that a script would accept untrusted user input or unvalidated script input data and use it to malloc memory, without filtering/sanitizing it, therefore the value used to malloc memory is under the the full control of the script author and no trust boundary is crossed.