Package: php5 Version: 5.2.0-8 Severity: important Tags: security Hello,
while developing my PHP application, I stumbled across PCRE usage which crashes the PHP binary. After some trial and error, I was able to reduce the problem to the attached piece of PHP code. I was able to reproduce the segfault on 3 different machines running Debian, under php 5.2.0-8 (testing, 2 machines) and 4.3.10-18 (stable). I also compiled versions of libpcre3 and php5-cli with debugging information to get a stack trace. The topmost frames of the stack backtrace follow at the end of this message. Inside libpcre3, the code recurses through pcre_exec.c lines 677 and 1190 until the stack overflows. Next, I tried to find out whether the crash is reproducible with a C program. But while AFAICT the attached C program does the same as the code in php-5.2.0/ext/pcre/php_pcre.c, no segfault happens. So maybe PHP corrupts memory between compiling and executing the regex? I don't know! :-/ Running "valgrind php5 php-5.2.0-8-segfault.php" doesn't output anything which looks like a PCRE-related bug. One more thing: I also tried to trim down the example further by reducing the length of the subject string. This gives weird results: When some parts of the input are removed, the crash becomes "unreliable" in that executing "php5 php-5.2.0-8-segfault.php" will crash sometimes and sometimes it will not. I've "anonymized" my code by replacing alphabetic characters with "x", that's why it looks so weird. :) I'm tagging this "security" as this MAY potentially be a nasty bug which might allow more than just segfaults. If you disagree, feel free to remove the tag. Cheers, Richard -- __ _ |_) /| Richard Atterer | \/¯| http://geht.net.gibts.bei.atterer.net ¯ '` ¯ #8146 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9319a4, flags=<value optimized out>, rdepth=31) at ./pcre_exec.c:677 #8147 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9321a4, flags=<value optimized out>, rdepth=30) at ./pcre_exec.c:1190 #8148 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9321a4, flags=<value optimized out>, rdepth=29) at ./pcre_exec.c:677 #8149 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9329a4, flags=<value optimized out>, rdepth=28) at ./pcre_exec.c:1190 #8150 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9329a4, flags=<value optimized out>, rdepth=27) at ./pcre_exec.c:677 #8151 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9331a4, flags=<value optimized out>, rdepth=26) at ./pcre_exec.c:1190 #8152 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9331a4, flags=<value optimized out>, rdepth=25) at ./pcre_exec.c:677 #8153 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9339a4, ---Type <return> to continue, or q <return> to quit--- flags=<value optimized out>, rdepth=24) at ./pcre_exec.c:1190 #8154 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9339a4, flags=<value optimized out>, rdepth=23) at ./pcre_exec.c:677 #8155 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9341a4, flags=<value optimized out>, rdepth=22) at ./pcre_exec.c:1190 #8156 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9341a4, flags=<value optimized out>, rdepth=21) at ./pcre_exec.c:677 #8157 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9349a4, flags=<value optimized out>, rdepth=20) at ./pcre_exec.c:1190 #8158 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9349a4, flags=<value optimized out>, rdepth=19) at ./pcre_exec.c:677 #8159 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9351a4, flags=<value optimized out>, rdepth=18) at ./pcre_exec.c:1190 #8160 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9351a4, flags=<value optimized out>, rdepth=17) at ./pcre_exec.c:677 #8161 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9359a4, flags=<value optimized out>, rdepth=16) at ./pcre_exec.c:1190 #8162 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9359a4, flags=<value optimized out>, rdepth=15) at ./pcre_exec.c:677 #8163 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9361a4, flags=<value optimized out>, rdepth=14) at ./pcre_exec.c:1190 #8164 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9361a4, flags=<value optimized out>, rdepth=13) at ./pcre_exec.c:677 #8165 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9369a4, flags=<value optimized out>, rdepth=12) at ./pcre_exec.c:1190 #8166 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9369a4, flags=<value optimized out>, rdepth=11) at ./pcre_exec.c:677 #8167 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9371a4, flags=<value optimized out>, rdepth=10) at ./pcre_exec.c:1190 #8168 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9371a4, flags=<value optimized out>, rdepth=9) at ./pcre_exec.c:677 #8169 0xb7e2a5a7 in match (eptr=0xb72ce7a4 ";\n", ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9379a4, flags=<value optimized out>, rdepth=8) at ./pcre_exec.c:1190 #8170 0xb7e29c04 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=6, md=0xbf939658, ims=0, eptrb=0xbf9379a4, flags=<value optimized out>, rdepth=7) at ./pcre_exec.c:677 #8171 0xb7e2b1d6 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=<value optimized out>, md=0xbf939658, ims=0, eptrb=0xbf937da4, flags=<value optimized out>, rdepth=6) at ./pcre_exec.c:1063 #8172 0xb7e2b1d6 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=<value optimized out>, md=0xbf939658, ims=0, eptrb=0xbf9381a4, flags=<value optimized out>, rdepth=5) at ./pcre_exec.c:1063 #8173 0xb7e2b1d6 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=<value optimized out>, md=0xbf939658, ims=0, eptrb=0xbf9385a4, flags=<value optimized out>, rdepth=4) at ./pcre_exec.c:1063 #8174 0xb7e2e004 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=<value optimized out>, md=0xbf939658, ims=0, eptrb=0xbf9395a4, flags=<value optimized out>, rdepth=3) at ./pcre_exec.c:629 #8175 0xb7e2f269 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=<value optimized out>, md=0xbf939658, ims=4, eptrb=0xbf938da4, flags=<value optimized out>, rdepth=2) at ./pcre_exec.c:2932 ---Type <return> to continue, or q <return> to quit--- #8176 0xb7e2e004 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=<value optimized out>, md=0xbf939658, ims=0, eptrb=0xbf9395a4, flags=<value optimized out>, rdepth=1) at ./pcre_exec.c:629 #8177 0xb7e2e004 in match (eptr=<value optimized out>, ecode=<value optimized out>, offset_top=<value optimized out>, md=0xbf939658, ims=0, eptrb=0xbf9395a4, flags=<value optimized out>, rdepth=0) at ./pcre_exec.c:629 #8178 0xb7e31af3 in pcre_exec (argument_re=0x8652bf8, extra_data=0xbf9397e4, subject=0xb72cd79c "<html>\n<head><?php // -*- php -*-\n/* Output sitemap info for directory at $path. Value is site-absolute and\n must start with a slash, so supply \"/\" to output sitemap for whole\n site. */\nfunction /"..., length=4106, start_offset=0, options=0, offsets=0xb72cb9d8, offsetcount=12) at ./pcre_exec.c:3851 #8179 0x0809be14 in php_pcre_match_impl (pce=0x8652ee8, subject=0xb72cd79c "<html>\n<head><?php // -*- php -*-\n/* Output sitemap info for directory at $path. Value is site-absolute and\n must start with a slash, so supply \"/\" to output sitemap for whole\n site. */\nfunction /"..., subject_len=4106, return_value=0xb72cb8fc, subpats=0xb72cb8e4, global=0, use_flags=0, flags=0, start_offset=0) at /home/richard/deb/php-5.2.0/ext/pcre/php_pcre.c:604 #8180 0x0809c94a in php_do_pcre_match (ht=3, return_value=0xb72cb8fc, return_value_ptr=0x6, this_ptr=0x0, return_value_used=0, global=0) at /home/richard/deb/php-5.2.0/ext/pcre/php_pcre.c:462 #8181 0x082cf83f in zend_do_fcall_common_helper_SPEC (execute_data=0xbf9399ec) at /home/richard/deb/php-5.2.0/Zend/zend_vm_execute.h:200 #8182 0x082bf238 in execute (op_array=0xb72cb104) at /home/richard/deb/php-5.2.0/Zend/zend_vm_execute.h:92 #8183 0x082a040c in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/richard/deb/php-5.2.0/Zend/zend.c:1097 #8184 0x0825b6e2 in php_execute_script (primary_file=0xbf93be20) at /home/richard/deb/php-5.2.0/main/main.c:1758 #8185 0x0832f5ae in main (argc=2, argv=0xbf93bef4) at /home/richard/deb/php-5.2.0/sapi/cli/php_cli.c:1108
php-5.2.0-8-segfault.php
Description: application/httpd-php
// gcc -lpcre -g -O2 -Wall -o pcre-segfault pcre-segfault.c && ./pcre-segfault // This does _not_ crash for me #include <pcre.h> #include <stdio.h> #include <string.h> #include <stdlib.h> static const char* subject = "<xxxx>\n" "<xxxx><?xxx // -*- xxx -*-\n" "/* xxxxxx xxxxxxx xxxx xxx xxxxxxxxx xx $xxxx. xxxxx xx xxxx-xxxxxxxx xxx\n" " xxxx xxxxx xxxx x xxxxx, xx xxxxxx \"/\" xx xxxxxx xxxxxxx xxx xxxxx\n" " xxxx. */\n" "xxxxxxxx /*xxxx*/ xxxxxxx(/*xxxxxx*/ $xxx, $xxxxxx = '') {\n" " xxxx \"<xx>xxxxxxxxx: $xxx</xx>\\x\";\n" " // xxxx xxxxxxxxx xxxxxxxx xx ($xxx == '/') $xxx = '';\n" " $xx = xxxxxxx(xxxxx . $xxx); xx (!$xx) xxxxxx;\n" " $xxxxxxxxx = xxxxx; $xxxxx = xxxxx();\n" " xxxxx ($xx && xxxxx !== ($x = xxxxxxx($xx))) {\n" " xx ($x{0} == '.' || xx_xxxx(xxxxx . \"$xxx/$x\")) xxxxxxxx;\n" " xx (xx_xxx(xxxxx . \"$xxx/$x\")) {\n" " $xxxxx[] = $x;\n" " xxxxxxxx;\n" " }\n" " xx (xxxxxx($x, -22) != '.xxxxx_xxxxxxx.xxxxxxx'\n" " && xxxxxx($x, -26) != '.xxxxx-xxx_xxxxxxx.xxxxxxx')\n" " xxxxxxxx;\n" " xx (xxxxxx($x, 0, 6) != 'xxxxx.') {\n" " $xxxxx[] = $x;\n" " xxxxxxxx;\n" " }\n" " // xxxxx xxxx xxxxxxx, xxxxxx x <xx> xxx xx\n" " xxxx $xxxxxx, '<xx>', xxxxxxxxxxx(\"$xxx/$x\", \"$xxx/\");\n" " $xxxxxxxxx = xxxx;\n" " }\n" " xxxxxxxx($xx);\n" "\n" " xx (xxxxx($xxxxx)) {\n" " xx ($xxxxxxxxx) xxxx \"</xx>\\x\";\n" " xxxxxx;\n" " }\n" " xx ($xxxxxxxxx) xxxx \"<xx/>\\x\";\n" "\n" " // xxx xxxxxxxxx xxxxxxxx xxxxxxx xxxxx, xxxxxx xxxxxxxxxxx xxx xxxx\n" " xxxx $xxxxxx, \"<xx xxxxx=\\\"xxxxxxx\\\">\\x\";\n" " xxxx($xxxxx);\n" " xxxxxxx ($xxxxx xx $x) {\n" " xx (xx_xxx(xxxxx . \"$xxx/$x\"))\n" " xxxxxxx(\"$xxx/$x\", \"$xxxxxx \");\n" " xxxx\n" " xxxx $xxxxxx, ' <xx>', xxxxxxxxxxx(\"$xxx/$x\"), \"</xx>\\x\";\n" " }\n" " xxxx $xxxxxx, \"</xx>\\x\";\n" " xx ($xxxxxxxxx) xxxx $xxxxxx, \"</xx>\\x\";\n" "}\n" "//______________________________________________________________________\n" "\n" "/* xxxxxx x xxxxxx xxxx xx xxxxxx xxx xxx $xxxxxxxx. $xxxxxxxx xxxx xx x\n" " _xxxxxxx.xxxxxxx xxxx. xx xxx xxxx xxxx xx xxx xxxxxx, xxxx xxx xxxxxxxx\n" " xx xxx xxxxx xxx xx xxx xxxxxxxxx xxxxxxxx xxxxxxxx. xxx xxxxxx xxxxxx\n" " xxxx xx $xxxxxxxx xxxx xxx \"_xxxxxxx.xxxxxxx\" xxxxxxx, xxxxxx xxxx xxx\n" " xxxxxxxx xxxx xx xxxxxxxxxx x $xxxx. */\n" "xxxxxxxx /*xxxxxx*/ xxxxxxxxxxx(/*xxxxxx*/ $xxxxxxxx, $xxxx = xxxxx) {\n" " $xxxx = xxxxxx($xxxxxxxx, 0, -16); // xxxxxx \"_xxxxxxx.xxxxxxx\" xxxx xxx\n" " xxxx(\"xxxxxxxxxxxxx $xxxx\");\n" " xx ($xxxx === xxxxx) {\n" " $xxxx = $xxxx;\n" " xx (xxxxxx($xxxx, -16) == '.xxxxx.xxxxx-xxx')\n" " $xxxx = xxxxxx($xxxx, 0, -10); // xxxxxx .xxxxx-xxx xx xxxxxxxx xx .xxxxx\n" " }\n" "\n" " /* xxxx .xxxxxxx xxxxxxxx. xx xxxx xxx xxxxxxxxx xxxxx xx xxxxx:\n" " xxxxxxx /xxx/xxxxx.xxxxx.xx.xxxxx\n" " xxxxxxxxx /xxx/xxxxx.xxxxx.xxxxx */\n" " xxxxxx $xxxxxxxxx = xxxx;\n" " xx ($xxxxxxxxx === xxxx) $xxxxxxxxx = xxxxx_xxxx(xxxxxxx(' ', xxxxxxxxx));\n" " $xxxxxxxx = '';\n" " $xxxxxxx = xxxxxxxxxxxx_xxxxxxxxxxx(xxxxx . $xxxxxxxx);\n" " xxxxxxx ($xxxxxxx xx $xxxx => $xxxxx) {\n" " xxxx(\"xx $xxxx => $xxxxx\");\n" " xx (xxxxxx($xxxx, 0, xxxxxx($xxxx)) != $xxxx) xxxxxxxx;\n" " $xxxxxxxxxx = xxxxxx($xxxx, xxxxxx($xxxx));\n" " xxxx(\"xx $xxxx => $xxxxx '$xxxxxxxxxx'\");\n" " xx ($xxxxx == 'xxxxxxxxx' && $xxxxxxxxxx == '.xxxx') {\n" " // xxxxxx-xxxxxxxx xxxx xx xxxxxx: xxxx xxxxx xxx <xxxxx> xxxxxxxx\n" " $xxxxxxxx = xxxxxxxxxxxx($xxxx);\n" " xxxxx;\n" " } xxxx xx ($xxxxx == 'xxxxxxx' && $xxxxxxxxxx{0} == '.'\n" " && xxxxxx($xxxxxxxxxx, -5) == '.xxxx') {\n" " /* xxxxx-xxxxxxxx: xxxxxxx xxx xxxxxxxxxx xxxxxxxxx' xxxx xxxx xxx\n" " xxxxxxxxx xxxxxxxx xxxxxxxx */\n" " $xxxx = xxxxxx($xxxxxxxxxx, 1, -5);\n" " xx (xxxxx_xxx_xxxxxx($xxxx, $xxxxxxxxx))\n" " $xxxxxxxx .= \"<$xxxx>\" . xxxxxxxxxxxx($xxxx) . \"</$xxxx>\";\n" " xxxx(\" xxxx='$xxxx' $xxxxxxxx\");\n" " }\n" " }\n" "\n" " $xxxxx = xxxxxxxxxxxxxxxx($xxxx);\n" " xx ($xxxxxxxx == '') $xxxxxxxx = $xxxxx;\n" " xxxxxx \"<x xxxx=\\\"/~xxxxxxx/xx$xxxxx\\\">$xxxxxxxx</x>\";\n" "\n" " // xxxxxx \"<x xxxx=\\\"/~xxxxxxx/xx$xxxxx\\\">$xxxxx</x>\";\n" "}\n" "//______________________________________________________________________\n" "\n" "xxxxxxxx xxxxxxxxxxxx(/*xxxxxx*/ $xxxxxxxx) {\n" " $xxxx = xxxx_xxx_xxxxxxxx(xxxxx . $xxxxxxxx);\n" " xx (xxxx_xxxxx('%<xxxxx>(.*)</xxxxx>%', $xxxx, $x) == 1)\n" " xxxxxx xxxxxxxxxxxxxxxx($xxxxxxxx);\n" " xxxxxx xxxxxxxxxxxxxxxx($xxxxxxxx);\n" "}\n" "//______________________________________________________________________\n" "\n" "xxxxxx_xxxxxxxxxxxxx($xxxx['xxxx'], '/xxxxx.xxxxxxx');\n" "xxxx \"<xx>\\x\";\n" "xxxxxxx('/');\n" "xxxx \"</xx>\\x\";\n"; static const char* pattern = "%^((?:<\\?(?:php)?\\s(?:[^?]|\\?(?!>))*\\?>\\n?)*)((?Us).*)((?:<\\?(?:php)?\\s(?:[^?]|\\?(?!>))*\\?>\\n?)*)$%"; int main() { const char* errPtr = 0; int errOff = 0; int ovector[100]; unsigned const char *tables = pcre_maketables(); pcre* re = pcre_compile(pattern, 0/*options*/, &errPtr, &errOff, tables); if (re == NULL) printf("compile failed: %s\n", errPtr); pcre_exec(re, NULL, subject, strlen(subject), 0/*off*/, 0/*opt*/, ovector, 100); printf("OK\n"); return 0; }