php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78927 Crash in pcre2_code_free_8, zend_hash_destroy
Submitted: 2019-12-08 13:49 UTC Modified: 2019-12-12 08:51 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: xnoreq at gmail dot com Assigned:
Status: Wont fix Package: Reproducible crash
PHP Version: 7.4.0 OS: Linux 5.3.11
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2019-12-08 13:49 UTC] xnoreq at gmail dot com
Description:
------------
Since upgrade to 7.4 I keep getting crashes e.g. with tiny tiny rss.
I have pcre.jit=1 and opcache.enable=1 in php.ini and use php-fpm.

systemd-coredump[736717]: Process 736708 (php) of user 1001 dumped core.

                                                Stack trace of thread 736708:
                                                #0  0x00007fa2cfd92b5b n/a (libpcre2-8.so.0 + 0x1db5b)
                                                #1  0x00007fa2cfdbfba3 n/a (libpcre2-8.so.0 + 0x4aba3)
                                                #2  0x00007fa2cfd80c6b pcre2_code_free_8 (libpcre2-8.so.0 + 0xbc6b)
                                                #3  0x000055ba3fdfc233 n/a (php + 0x27e233)
                                                #4  0x000055ba4001110d zend_hash_destroy (php + 0x49310d)
                                                #5  0x000055ba3fdfc111 n/a (php + 0x27e111)
                                                #6  0x000055ba400065d4 zend_deactivate_modules (php + 0x4885d4)
                                                #7  0x000055ba3ffa02b6 php_request_shutdown (php + 0x4222b6)
                                                #8  0x000055ba40088d13 n/a (php + 0x50ad13)
                                                #9  0x000055ba3fdb92f7 n/a (php + 0x23b2f7)
                                                #10 0x00007fa2cfb2b153 __libc_start_main (libc.so.6 + 0x27153)
                                                #11 0x000055ba3fdb9a1e _start (php + 0x23ba1e)



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-12-09 08:44 UTC] nikic@php.net
It looks to me like for some reason the per-request PCRE cache gets shut down, even though FPM shouldn't be using it.
 [2019-12-09 08:52 UTC] nikic@php.net
Based on code inspection alone, I don't see what the issue could be.
 [2019-12-09 20:59 UTC] xnoreq at gmail dot com
This is tiny tiny rss's update script (update_daemon2.php) which is a cli executable. That's why the process name is also php (and not php-cgi or php-fpm).

It forks off do to multiple updates in parallel and I guess that leads to the invalid frees.
 [2019-12-09 21:16 UTC] nikic@php.net
Thanks, the trace makes much more sense with this being a cli executable.

fork() in most cases shouldn't matter, but here there might be a possible interference with the JIT mapped memory used by PCRE.

Which Linux distro are you using and do you know how they build their PCRE binaries? If they are using --enable-sealloc, then this may indeed be incompatible with fork().

Which PHP version did you use before the upgrade? PHP 7.3 or something older?
 [2019-12-09 23:39 UTC] xnoreq at gmail dot com
I was using 7.3.12 before.

You can find the build files and patches here:
https://git.archlinux.org/svntogit/packages.git/tree/repos/extra-x86_64?h=packages/php

There's no --enable-sealloc option.
 [2019-12-09 23:47 UTC] xnoreq at gmail dot com
Here's a simple test-case to reproduce the issue:

$ php -f test.php

test.php:
<?php
function regex() {
        preg_match('/(foo)(bar)(baz)/', 'foobarbaz', $matches, PREG_OFFSET_CAPTURE);
}

regex();

$pid = pcntl_fork();
if ($pid == -1) {
        die('error.');
}
else if ($pid) {
        echo 'parent... ';
        pcntl_wait($pid);
        echo 'wait done';
}
else {
        echo 'child.';
}
?>
 [2019-12-10 08:22 UTC] nikic@php.net
The --enable-sealloc flag is passed when building libpcre2 rather than PHP. Looking through the repository you linked, it seems that they indeed use this flag: https://git.archlinux.org/svntogit/packages.git/tree/trunk/PKGBUILD?h=packages/pcre2#n31

This compilation option is known to be incompatible with fork(), causes a range of other issues, and its use is discouraged by PCRE upstream. If you can, please petition ArchLinux to remove this flag and instead properly grant JIT permissions (W+X mmap) to programs that use PCRE JIT.

Some references for issues this has caused:
https://bugs.php.net/bug.php?id=78630 (tmp mounted noexec)
https://bugs.exim.org/show_bug.cgi?id=1749 (the fork issue is mentioned here)
https://bugs.exim.org/show_bug.cgi?id=2445 (breaks under low disk conditions)

What isn't clear to me is why you're seeing this issue only on PHP 7.4, as it principally should affect PHP 7.3 (also using PCRE2) as well.

For now, you can work around this issue by setting pcre.jit=0 for the script that uses forking.
 [2019-12-10 20:13 UTC] xnoreq at gmail dot com
Thanks, I have recompiled pcre2 without --enable-sealloc and now there are no more crashes.

I have also created a bug report in Arch Linux's bug tracker:
https://bugs.archlinux.org/task/64799

It looks like the change was made to fix the incompatibility with the new MemoryDenyWriteExecute=true in the php-fpm.service.

As I wrote, this does not seem like the right solution to me. Instead, Arch should either change php.ini to disable pcre.jit by default or patch the service file to disable MemoryDenyWriteExecute by default.
 [2019-12-10 20:19 UTC] nikic@php.net
> It looks like the change was made to fix the incompatibility with the new MemoryDenyWriteExecute=true in the php-fpm.service.
>
> As I wrote, this does not seem like the right solution to me. Instead, Arch should either change php.ini to disable pcre.jit by default or patch the service file to disable MemoryDenyWriteExecute by default.

If this was just done to satisfy the php-fpm.service definition: MemoryDenyWriteExecute=true was enabled by mistake there, and this has been reverted by https://github.com/php/php-src/commit/67cd4271e922ee3082b416a7563598274d13a1e5 in the meantime (part of 7.4.1).
 [2019-12-12 08:51 UTC] nikic@php.net
-Status: Open +Status: Wont fix
 [2019-12-12 08:51 UTC] nikic@php.net
I'm closing this bug as I don't think there is anything actionable here on the PHP side. The MemoryDenyWriteExecute=true flag has already been removed from the service definition, and we can't do anything about fork() limitations when PCRE is built with --enable-sealloc.
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Sat Jan 18 14:01:23 2020 UTC