php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62515 apc.filters segfaults with PHP 5.1.6
Submitted: 2012-07-09 12:35 UTC Modified: 2016-11-18 21:31 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:0 (0.0%)
From: jani dot ollikainen at mmd dot net Assigned:
Status: Wont fix Package: APC (PECL)
PHP Version: Irrelevant OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: jani dot ollikainen at mmd dot net
New email:
PHP Version: OS:

 

 [2012-07-09 12:35 UTC] jani dot ollikainen at mmd dot net
Description:
------------
PHP version is not irrelevant, but as on the page:
http://pecl.php.net/package/APC
says "Release 3.1.10: PHP Version: PHP 5.1.0 or newer"
so also I think that reporting bug with older PHP is acceptable, or
they should at least change that to PHP 5.3.0 or newer.

Put anything to apc.filters and run php-cgi.

PHP 5.1.6 (cli) (built: Jun 27 2012 12:21:13)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies


Test script:
---------------
<?php phpinfo(); ?>

Expected result:
----------------
No segfault as situation is with PHP 5.3

Actual result:
--------------
Segmentation fault.

Program received signal SIGSEGV, Segmentation fault.
pcre_get_compiled_regex_ex (
    regex=0x1696078 "/((.*liteconf\\.php|.*datafiles\\/config\\/.*))/",
    extra=0x0, preg_options=0x0, compile_options=0x7fffffffbbe4)
    at /usr/src/debug/php-5.1.6/ext/pcre/php_pcre.c:253
253             *preg_options = 0;
(gdb) backtrace
#0  pcre_get_compiled_regex_ex (
    regex=0x1696078 "/((.*liteconf\\.php|.*datafiles\\/config\\/.*))/",
    extra=0x0, preg_options=0x0, compile_options=0x7fffffffbbe4)
    at /usr/src/debug/php-5.1.6/ext/pcre/php_pcre.c:253
#1  0x000000000044260e in pcre_get_compiled_regex (regex=0x166bab3 "",
    extra=0x16960a4, preg_options=0x16960a5)
    at /usr/src/debug/php-5.1.6/ext/pcre/php_pcre.c:134
#2  0x00002aaab1923150 in apc_regex_compile_array (
    patterns=<value optimized out>)
    at /usr/src/debug/php-pecl-apc-3.1.10/APC-3.1.10/apc.c:456
#3  0x00002aaab192cd00 in apc_request_init ()
    at /usr/src/debug/php-pecl-apc-3.1.10/APC-3.1.10/apc_main.c:972
#4  0x00002aaab1923ae5 in zm_activate_apc (type=23509683,
    module_number=23683236)
    at /usr/src/debug/php-pecl-apc-3.1.10/APC-3.1.10/php_apc.c:393
#5  0x000000000057fbd9 in module_registry_request_startup (module=0x929e80)
    at /usr/src/debug/php-5.1.6/Zend/zend_API.c:1835
#6  0x000000000058575f in zend_hash_apply (ht=0x8b7260,
    apply_func=0x57fbc0 <module_registry_request_startup>)
    at /usr/src/debug/php-5.1.6/Zend/zend_hash.c:670
#7  0x00000000005408bc in php_request_startup ()
    at /usr/src/debug/php-5.1.6/main/main.c:1122
#8  0x00000000005f699c in main (argc=1, argv=0x7fffffffea08)
    at /usr/src/debug/php-5.1.6/sapi/cgi/cgi_main.c:1595

Program received signal SIGSEGV, Segmentation fault.
pcre_get_compiled_regex_ex (regex=0x16960b8 "/(liteconf\\.php)/", extra=0x0,
    preg_options=0x0, compile_options=0x7fffffffbbe4)
    at /usr/src/debug/php-5.1.6/ext/pcre/php_pcre.c:253
253             *preg_options = 0;

Program received signal SIGSEGV, Segmentation fault.
pcre_get_compiled_regex_ex (regex=0x1696078 "/(a)/", extra=0x0,
    preg_options=0x0, compile_options=0x7fffffffbbe4)
    at /usr/src/debug/php-5.1.6/ext/pcre/php_pcre.c:253
253             *preg_options = 0;

Patches

apc-3.1.12-regex-no-pefree.patch (last revision 2012-08-29 19:53 UTC by bof at bof dot de)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-07-19 21:54 UTC] rasmus@php.net
Just to clarify you are saying that you can't reproduce this with PHP 5.3.x, 
right?
 [2012-07-19 21:54 UTC] rasmus@php.net
-Status: Open +Status: Feedback
 [2012-07-19 22:05 UTC] jani dot ollikainen at mmd dot net
I am.

Tested with:
# php-cgi --version
PHP 5.3.3 (cgi-fcgi) (built: May  7 2012 19:57:05)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
# echo '<?php echo phpversion("apc")."\n";?>'|php-cgi -q
3.1.9

And no segfault with apc.filters="a":

# php-cgi -i |grep apc.filters
<tr><td class="e">apc.filters</td><td class="v">a</td><td class="v">a</td></tr>
 [2012-07-27 18:46 UTC] jani dot ollikainen at mmd dot net
-Status: Feedback +Status: Open
 [2012-07-27 18:46 UTC] jani dot ollikainen at mmd dot net
"You must provide a comment". Well, Feedback was given, so maybe I'll change this to "Open" again.
 [2012-08-29 20:00 UTC] bof at bof dot de
I encounter this problem with APC-3.1.12 on openSUSE 11.4 64bit, PHP 5.3.15 from 
OBS. Apache 2.2.17 from openSUSE 11.4 base, prefork.

As soon as I activate apc.filters and run some requests - requesing apc.php 
itself suffices, I see segfauls, and regularly glibc double-free reports as 
shown below (abbreviated).

APC-3.1.11 worked fine when trying, so I compared, and found the added pefree 
calls in apc.c apc_regex_destroy_array() to be the cause of the problem.

The attached patch reverts that function to the APC-3.1.11 state.

If I'm not mistaken, the problem stems from the fact that the PHP pcre library 
internally caches all compiled regexpen, returning the cached regexp whenever 
the same string is requested again.

APC compiles the same regexp source anew for each request. But PHP pcre returns 
the internally cached compiled regex. When it is destroyed at request exit time,  
by these pefree calls (really direct free()), the PHP pcre cache does not take 
notice. At the next request in the same process APC receives the already freed 
compiled regex pointer, which is already a problem with arbitrary consequences, 
but then at second-request-exit frees it again -> double free from glibc.

[Wed Aug 29 21:00:52 2012] [notice] child pid 24852 exit signal Aborted (6)
*** glibc detected *** /usr/sbin/httpd2-prefork: double free or corruption 
(!prev): 0x00007f75673324f0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x733b6)[0x7f7565e1a3b6]
/lib64/libc.so.6(cfree+0x6c)[0x7f7565e1f2dc]
/usr/lib64/apache2/mod_php5.so(+0x4666b1)[0x7f7561c826b1]
/usr/lib64/apache2/mod_php5.so(zend_hash_clean+0x73)[0x7f7561de07e3]
/usr/lib64/apache2/mod_php5.so(pcre_get_compiled_regex_cache+0x4c6)
[0x7f7561c83126]
/usr/lib64/apache2/mod_php5.so(pcre_get_compiled_regex+0x2b)[0x7f7561c831eb]
/usr/lib64/php5/extensions/apc.so(apc_regex_compile_array+0x6ab)[0x7f755dbac17b]
/usr/lib64/php5/extensions/apc.so(apc_request_init+0xa2)[0x7f755dbb6be2]
/usr/lib64/php5/extensions/apc.so(+0xb8c5)[0x7f755dbac8c5]
 [2012-08-29 20:53 UTC] bof at bof dot de
Sorry, upon rereading the original problem description, noticing it's reporting 
against APC-3.1.10 which does not have the problem I encountered, I see that my 
comment is not applicable.

I opened a new bug #62972 for my problem.

However from reading the code I think I can shed a light on the original problem 
here. The call in apc.c to pcre_get_compiled_regex() passes NULL, NULL as the 
second and third, pointer, arguments. If some old source browser on the net does 
not lie to me, older PHP versions implementation of pcre_get_compiled_regex() do 
not guard against these NULL values, happily trying to write to them - at the 
*preg_options place noted in the original description.

PHP 5.3.15, which I examined, does guard against being passed NULL for both 
arguments, so that problem won't happen there.

Changing APC to provide dummy pointers in these places, would fix that problem, 
too, I think. The patch would look roughly like this (completely untested):


--- APC-3.1.12/apc.c	2012-08-16 17:56:11.000000000 +0200
+++ APC-3.1.12-bof/apc.c	2012-08-29 22:52:30.504702842 +0200
@@ -465,7 +465,9 @@
 
 #define APC_COMPILE_PATTERN(re, match) do {\
     if(match.len > 2) { /* more than just "//" */\
-        if (((re) = pcre_get_compiled_regex(match.c, NULL, NULL TSRMLS_CC)) == 
NULL) {\
+	void *dummy_extra; \
+	int *dummy_options; \
+        if (((re) = pcre_get_compiled_regex(match.c, &dummy_extra, 
&dummy_options TSRMLS_CC)) == NULL) {\
             apc_warning("apc_regex_compile_array: invalid expression '%s'" 
TSRMLS_CC, match.c); \
             smart_str_free(&match);\
             return NULL;\
 [2016-11-18 21:31 UTC] kalle@php.net
-Status: Open +Status: Wont fix
 [2016-11-18 21:31 UTC] kalle@php.net
APC is no longer supported in favor of opcache that comes bundled with PHP, if you wish to use the user cache, then look at PECL/APCu.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Oct 16 05:01:27 2024 UTC