Bug 866520 - pcre_exec() segfaults when back-tracking Unicode properties in non-UTF-8 mode
pcre_exec() segfaults when back-tracking Unicode properties in non-UTF-8 mode
Status: CLOSED ERRATA
Product: Red Hat Enterprise Linux 5
Classification: Red Hat
Component: pcre (Show other bugs)
5.8
Unspecified Linux
unspecified Severity high
: rc
: ---
Assigned To: Petr Pisar
Jan Kepler
: Patch
Depends On:
Blocks: 921048
  Show dependency treegraph
 
Reported: 2012-10-15 10:41 EDT by Tomasz Ostrowski
Modified: 2013-09-30 17:58 EDT (History)
2 users (show)

See Also:
Fixed In Version: pcre-6.6-9.el5
Doc Type: Bug Fix
Doc Text:
Previously, matching a regular expression with Unicode properties in a non-UTF-8 mode against a string with non-ASCII characters, caused an unexpected termination with a segmentation fault in the PCRE library. This update fixes back-tracking in non-UTF-8 mode, and the PCRE library no longer crashes in the aforementioned scenario.
Story Points: ---
Clone Of:
Environment:
Last Closed: 2013-09-30 17:58:44 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:


Attachments (Terms of Use)
This file crashes php (216 bytes, application/x-php)
2012-10-15 10:41 EDT, Tomasz Ostrowski
no flags Details
preg.c (2.00 KB, text/plain)
2012-10-17 10:00 EDT, Remi Collet
no flags Details
API/ABI compatibility report (20.03 KB, text/html)
2012-10-18 06:58 EDT, Tomasz Ostrowski
no flags Details
Upstream fix ported to pcre-6.6 (2.34 KB, patch)
2012-10-19 08:28 EDT, Petr Pisar
no flags Details | Diff

  None (edit)
Description Tomasz Ostrowski 2012-10-15 10:41:05 EDT
Created attachment 627475 [details]
This file crashes php

Description of problem:
php53 crashes on attached file - in preg_replace function

Version-Release number of selected component (if applicable):
php53-5.3.3-13.el5_8
pcre-6.6-6.el5_6.1

How reproducible:
Always

Steps to Reproduce:
1. php preg_replace_crash.php
  
Actual results:
Segmentation fault

Expected results:
<span class="search-everything-highlight-color" style="background-color:#FFF984">foobar</span> &#8211; a &#8211; 00 aaźaaier

Additional info:
This is really on CentOS, but I think you might be interested, as it can be security related. I stumbled on this bug when Wordpress page was crashing httpd.


$ valgrind php preg_replace_crash.php
==26413== Memcheck, a memory error detector
==26413== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==26413== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==26413== Command: php preg_replace_crash.php
==26413== 
==26413== Invalid read of size 1
==26413==    at 0x4A08880: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8bf is 1 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== Invalid read of size 1
==26413==    at 0x4A08887: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8be is 2 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== Invalid read of size 1
==26413==    at 0x4A08870: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8bd is 3 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== Invalid read of size 1
==26413==    at 0x4A08879: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8bc is 4 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== Invalid write of size 1
==26413==    at 0x4A0888F: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8bf is 1 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== Invalid write of size 1
==26413==    at 0x4A08877: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8be is 2 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== Invalid write of size 1
==26413==    at 0x4A0887D: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8bd is 3 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== Invalid write of size 1
==26413==    at 0x4A08884: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  Address 0x4f7e8bc is 4 bytes before a block of size 262,144 alloc'd
==26413==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==26413==    by 0x57CB2D: _zend_mm_alloc_int (zend_alloc.c:1898)
==26413==    by 0x57D184: zend_mm_shutdown (zend_alloc.c:1657)
==26413==    by 0x5494A6: php_module_startup (main.c:2094)
==26413==    by 0x62189C: php_cli_startup (php_cli.c:401)
==26413==    by 0x6220E4: main (php_cli.c:775)
==26413== 
==26413== 
==26413== Process terminating with default action of signal 11 (SIGSEGV)
==26413==  Access not within mapped region at address 0x4C13FFF
==26413==    at 0x4A08880: memcpy (mc_replace_strmem.c:587)
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==    by 0x599F44: zend_execute_scripts (zend.c:1194)
==26413==    by 0x54AD47: php_execute_script (main.c:2261)
==26413==    by 0x622CDD: main (php_cli.c:1192)
==26413==  If you believe this happened as a result of a stack
==26413==  overflow in your program's main thread (unlikely but
==26413==  possible), you can try to increase the size of the
==26413==  main thread stack using the --main-stacksize= flag.
==26413==  The main thread stack size used in this run was 10485760.
==26413== Invalid read of size 8
==26413==    at 0x396EA08E15: do_lookup_x (do-lookup.h:47)
==26413==    by 0x396EA092B1: _dl_lookup_symbol_x (dl-lookup.c:280)
==26413==    by 0x396EA0CF64: _dl_fixup (dl-runtime.c:108)
==26413==    by 0x396EA129E1: _dl_runtime_resolve (in /lib64/ld-2.5.so)
==26413==    by 0x48024E8: _vgnU_freeres (vg_preloaded.c:62)
==26413==    by 0x4F9777E: ???
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==  Address 0x28 is not stack'd, malloc'd or (recently) free'd
==26413== 
==26413== 
==26413== Process terminating with default action of signal 11 (SIGSEGV)
==26413==  Access not within mapped region at address 0x28
==26413==    at 0x396EA08E15: do_lookup_x (do-lookup.h:47)
==26413==    by 0x396EA092B1: _dl_lookup_symbol_x (dl-lookup.c:280)
==26413==    by 0x396EA0CF64: _dl_fixup (dl-runtime.c:108)
==26413==    by 0x396EA129E1: _dl_runtime_resolve (in /lib64/ld-2.5.so)
==26413==    by 0x48024E8: _vgnU_freeres (vg_preloaded.c:62)
==26413==    by 0x4F9777E: ???
==26413==    by 0x4612E2: php_pcre_replace_impl (string3.h:51)
==26413==    by 0x461F9C: php_replace_in_subject (php_pcre.c:1267)
==26413==    by 0x462593: preg_replace_impl (php_pcre.c:1365)
==26413==    by 0x462AC2: zif_preg_replace (php_pcre.c:1385)
==26413==    by 0x5E78E8: zend_do_fcall_common_helper_SPEC (zend_vm_execute.h:316)
==26413==    by 0x5BD9AA: execute (zend_vm_execute.h:107)
==26413==  If you believe this happened as a result of a stack
==26413==  overflow in your program's main thread (unlikely but
==26413==  possible), you can try to increase the size of the
==26413==  main thread stack using the --main-stacksize= flag.
==26413==  The main thread stack size used in this run was 10485760.
==26413== 
==26413== HEAP SUMMARY:
==26413==     in use at exit: 2,714,420 bytes in 16,247 blocks
==26413==   total heap usage: 17,374 allocs, 1,127 frees, 3,110,948 bytes allocated
==26413== 
==26413== LEAK SUMMARY:
==26413==    definitely lost: 1,497,751 bytes in 15,954 blocks
==26413==    indirectly lost: 599 bytes in 11 blocks
==26413==      possibly lost: 786,473 bytes in 4 blocks
==26413==    still reachable: 429,597 bytes in 278 blocks
==26413==         suppressed: 0 bytes in 0 blocks
==26413== Rerun with --leak-check=full to see details of leaked memory
==26413== 
==26413== For counts of detected and suppressed errors, rerun with: -v
==26413== ERROR SUMMARY: 3238500 errors from 9 contexts (suppressed: 78 from 7)
Segmentation fault
Comment 1 Remi Collet 2012-10-17 09:57:31 EDT
Crash reproduced on rhel5 with php53 5.3.3 and pcre 6.6.6
Not reproduced on rhel6 with php 5.3.3 and pcre 7.8

After investigation on this issue, It seems to be a "pcre" issue.

In some case, pcre_exec returns a count value > 0 when it should be -1 (PCRE_ERROR_NOMATCH), and the offset vector contains dummy data.
Comment 2 Remi Collet 2012-10-17 10:00:59 EDT
Created attachment 628829 [details]
preg.c

Expected output:

start:0, count:2
offsets[0]=0
offsets[1]=6
offsets[2]=0
offsets[3]=6
start:6, count:-1

Actual output: 

start:0, count:2
offsets[0]=0
offsets[1]=6
offsets[2]=0
offsets[3]=6
start:6, count:2
offsets[0]=31
offsets[1]=6
offsets[2]=31
offsets[3]=6

start offset should never be > than end
Comment 3 Petr Pisar 2012-10-17 11:55:13 EDT
It's a bug in PCRE. The reproducer can be rewritten for pcretest this way:

$ printf '%s\n%s\n' \
  '/(?<!\<)(?<!\w)(\pL*foobar\pL*)(?!\w|[^<>]*>)/' \
  ' &#8211; a &#8211; 00 aaźaaier' | pcretest
PCRE version 6.6 06-Feb-2006

  re> Segmentation fault
Comment 4 Petr Pisar 2012-10-17 12:07:34 EDT
Minimal test case:

$ printf '%s\n%s\n' '/\pL*a\pL/' 'źa' | pcretest
PCRE version 6.6 06-Feb-2006

  re> Segmentation fault

There seems to be problem when using Unicode properties in ASCII mode on string with some non-ASCII characters.
Comment 5 Tomasz Ostrowski 2012-10-18 05:55:34 EDT
I've bisected fix for this bug using minimal test case to revision 207 in pcre svn:
http://vcs.pcre.org/viewvc?view=revision&revision=207

But a diff for this revision does not apply cleanly to revision 6.6. I tried to port it, but failed - it was still crashing. The fix has to be dependent on earlier code changes.
Comment 6 Tomasz Ostrowski 2012-10-18 06:58:20 EDT
Created attachment 629315 [details]
API/ABI compatibility report

Maybe a simplest solution would be to just upgrade pcre to version 7.3 - the same which RHEL6 uses.

I've compared this 2 version of library using ABI Compliance Checker 1.98.4 (http://ispras.linuxbase.org/index.php/ABI_compliance_checker) and I'm attaching a compatibility report. It looks like these 2 versions are compatible, so a new version should just work.
Comment 7 Tomasz Ostrowski 2012-10-18 10:22:10 EDT
(In reply to comment #6)
> Maybe a simplest solution would be to just upgrade pcre to version 7.3 - the
> same which RHEL6 uses.

Correction - RHEL6 uses 7.8, which is binary compatible with 6.6, but isn't source compatible - it lacks a global no_arg variable in namespace pcrecpp. Latest pcre version which is binary and source compatible with 6.6 is 7.5.
Comment 8 Petr Pisar 2012-10-19 08:27:58 EDT
Thank you for finding the fix. Actually, it was quite easy to back-port it.
Comment 9 Petr Pisar 2012-10-19 08:28:42 EDT
Created attachment 630005 [details]
Upstream fix ported to pcre-6.6
Comment 10 RHEL Product and Program Management 2012-10-19 08:29:11 EDT
This request was evaluated by Red Hat Product Management for
inclusion in the current release of Red Hat Enterprise Linux.
Because the affected component is not scheduled to be updated
in the current release, Red Hat is unable to address this
request at this time.

Red Hat invites you to ask your support representative to
propose this request, if appropriate, in the next release of
Red Hat Enterprise Linux.
Comment 13 RHEL Product and Program Management 2013-04-04 08:32:39 EDT
This request was evaluated by Red Hat Product Management for inclusion
in a Red Hat Enterprise Linux release.  Product Management has
requested further review of this request by Red Hat Engineering, for
potential inclusion in a Red Hat Enterprise Linux release for currently
deployed products.  This request is not yet committed for inclusion in
a release.
Comment 20 errata-xmlrpc 2013-09-30 17:58:44 EDT
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

http://rhn.redhat.com/errata/RHBA-2013-1298.html

Note You need to log in before you can comment on or make changes to this bug.