Bug #72405 [Com]: mb_ereg_replace - mbc_to_code (oniguruma) - oob read access

From: Date: Mon, 20 Jun 2016 18:06:27 +0000
Subject: Bug #72405 [Com]: mb_ereg_replace - mbc_to_code (oniguruma) - oob read access
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-201764@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=72405&edit=1

 ID:                 72405
 Comment by:         shm@php.net
 Reported by:        shm@php.net
 Summary:            mb_ereg_replace - mbc_to_code (oniguruma) - oob read
                     access
 Status:             Feedback
 Type:               Bug
 Package:            mbstring related
 Operating System:   Linux
 PHP Version:        7.0Git-2016-06-14 (Git)
 Block user comment: N
 Private report:     N

 New Comment:

Are you going to report it upstream?


Previous Comments:
------------------------------------------------------------------------
[2016-06-15 15:49:21] laruence@php.net

hmm, this one seems really like a bug in oniguruma's bug..

------------------------------------------------------------------------
[2016-06-15 09:54:26] shm@php.net

For provided case it works perfectly, but we've got another case if user provided string
shorter than 6 chars, like this one:

<?php mb_ereg_replace("\xfc",$_,$_);

Function reads oob (but it's not using pat_buf).

105           c = *p++;
gdb-peda$ print p
$7 = (const OnigUChar *) 0x60060004ffdc ""
gdb-peda$ bt
#0  mbc_to_code (p=0x60060004ffdc "", end=0x60060004ffd9 "") at
/home/shm/src/php-src/ext/mbstring/oniguruma/enc/utf8.c:105

------------------------------------------------------------------------
[2016-06-15 07:00:29] laruence@php.net

According to https://github.com/php/php-src/blob/master/ext/mbstring/oniguruma/enc/utf8.c#L291
 the max bytes are 6

so...I made a attempt to fix it here: https://github.com/php/php-src/commit/999a3553d58c537b4919821855b2cc8fb62b0b2f

thanks

------------------------------------------------------------------------
[2016-06-14 14:05:04] shm@php.net

Description:
------------
mbc_to_code which is part of oniguruma library performs oob access if pattern is shorter than 6
characters. I'm not sure if it's PHP bug (due to misuse of oniugurma API or oniguruma
internals bug, if so then please consider sending it upstream).

DEBUGGER SESSION:

Breakpoint 3, mbc_to_code (p=0x7fffffffa040 <incomplete sequence \374>, end=0x7fffffffa041
"") at /home/shm/src/php-src/ext/mbstring/oniguruma/enc/utf8.c:99
99        len = enclen(ONIG_ENCODING_UTF8, p);
gdb-peda$ 

at the beginning we pushed to function following pattern "0xfc00"

gdb-peda$ x/x p
0x7fffffffa040: 0x00000000000000fc

gdb-peda$ c
Program received signal SIGABRT, Aborted.

gdb-peda$ 
#7  0x0000000000a08355 in mbc_to_code (p=0x7fffffffa045 "", end=0x7fffffffa041
"") at /home/shm/src/php-src/ext/mbstring/oniguruma/enc/utf8.c:105
105           c = *p++;
gdb-peda$ print p
$35 = (const OnigUChar *) 0x7fffffffa045 ""

p is greater than end (which is unused in mbc_to_token). Pattern which is used in this function
comes from _php_mb_regex_ereg_replace_exec Where pat_buf is declared as follows:

810             char pat_buf[4];

then gets initialized here:

857                     /* FIXME: this code is not multibyte aware! */
858                     convert_to_long_ex(arg_pattern_zval);
859                     pat_buf[0] = (char)Z_LVAL_P(arg_pattern_zval);
860                     pat_buf[1] = '\0';
861                     pat_buf[2] = '\0';
862                     pat_buf[3] = '\0';
863     
864                     arg_pattern = pat_buf;
865                     arg_pattern_len = 1;


Note the FIXME comment. Then it's used here:

868             re = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, options,
MBREX(current_mbctype), syntax);

which internally calls mbc_to_code

ASAN REPORT:
==20738==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff5c361494 at pc 0xa0b97d bp
0x7fff5c360790 sp 0x7fff5c360788
READ of size 1 at 0x7fff5c361494 thread T0
    #0 0xa0b97c in mbc_to_code /home/shm/src/php-7.0.2/ext/mbstring/oniguruma/enc/utf8.c:105
    #1 0x9f0420 in fetch_token /home/shm/src/php-7.0.2/ext/mbstring/oniguruma/regparse.c:3146
    #2 0x9ff729 in parse_regexp /home/shm/src/php-7.0.2/ext/mbstring/oniguruma/regparse.c:5514
    #3 0x9ffba6 in onig_parse_make_tree
/home/shm/src/php-7.0.2/ext/mbstring/oniguruma/regparse.c:5543
    #4 0x9c3b15 in onig_compile /home/shm/src/php-7.0.2/ext/mbstring/oniguruma/regcomp.c:5300
    #5 0x9c4b8d in onig_new /home/shm/src/php-7.0.2/ext/mbstring/oniguruma/regcomp.c:5545
    #6 0xaa051a in php_mbregex_compile_pattern
/home/shm/src/php-7.0.2/ext/mbstring/php_mbregex.c:456
    #7 0xaa26c8 in _php_mb_regex_ereg_replace_exec
/home/shm/src/php-7.0.2/ext/mbstring/php_mbregex.c:868
    #8 0xaa3a82 in zif_mb_ereg_replace /home/shm/src/php-7.0.2/ext/mbstring/php_mbregex.c:1029
    #9 0x10eaac9 in ZEND_DO_ICALL_SPEC_HANDLER /home/shm/src/php-7.0.2/Zend/zend_vm_execute.h:586
    #10 0x10e9b22 in execute_ex /home/shm/src/php-7.0.2/Zend/zend_vm_execute.h:414
    #11 0x10e9da1 in zend_execute /home/shm/src/php-7.0.2/Zend/zend_vm_execute.h:458
    #12 0xfc7b37 in zend_eval_stringl /home/shm/src/php-7.0.2/Zend/zend_execute_API.c:1129
    #13 0xb82b53 in readline_shell_run /home/shm/src/php-7.0.2/ext/readline/readline_cli.c:669
    #14 0x1223447 in do_cli /home/shm/src/php-7.0.2/sapi/cli/php_cli.c:972
    #15 0x1225daa in main /home/shm/src/php-7.0.2/sapi/cli/php_cli.c:1345
    #16 0x7fd94f301ec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)
    #17 0x42e208 (/home/shm/src/php-7.0.2/sapi/cli/php+0x42e208)

Address 0x7fff5c361494 is located in stack of thread T0 at offset 1156 in frame
    #0 0xaa1e67 in _php_mb_regex_ereg_replace_exec
/home/shm/src/php-7.0.2/ext/mbstring/php_mbregex.c:784

  This frame has 18 object(s):
    [32, 36) 'eval'
    [96, 104) 'arg_pattern_zval'
    [160, 168) 'replace'
    [224, 232) 'replace_len'
    [288, 296) 'string'
    [352, 360) 'string_len'
    [416, 424) 'syntax'
    [480, 488) 'option_str'
    [544, 552) 'option_str_len'
    [608, 624) 'out_buf'
    [672, 688) 'eval_buf'
    [736, 752) 'args'
    [800, 816) 'subpats'
    [864, 880) 'retval'
    [928, 968) 'arg_replace_fci_cache'
    [1024, 1096) 'arg_replace_fci'
    [1152, 1156) 'pat_buf' <== Memory access at offset 1156 overflows this variable
    [1216, 1306) 'err_str'


Test script:
---------------
<?php
mb_ereg_replace(0xfc,$_,$_);


Expected result:
----------------
No oob access

Actual result:
--------------
Oob access in mbc_to_code


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=72405&edit=1


Thread (10 messages)

« previous php.bugs (#201764) next »