Bug #72970 [Opn->Csd]: Buffer overflow at match_at through mb_ereg_search_pos

From: Date: Thu, 26 Nov 2020 15:35:54 +0000
Subject: Bug #72970 [Opn->Csd]: Buffer overflow at match_at through mb_ereg_search_pos
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-230650@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=72970&edit=1 ID: 72970 Updated by: cmb@php.net Reported by: fernando at null-life dot com Summary: Buffer overflow at match_at through mb_ereg_search_pos -Status: Open +Status: Closed Type: Bug Package: mbstring related Operating System: * PHP Version: 5.6.25 -Assigned To: +Assigned To: cmb Block user comment: N Private report: N New Comment: This issue has been fixed in the meantime (at least for PHP 7.3; oniguruma is unbundled as of PHP 7.4.0). The script outputs now: Warning: mb_ereg_search_pos(): mbregex compile err: too many captures in %s on line %d Previous Comments: ------------------------------------------------------------------------ [2016-09-04 15:12:09] cmb@php.net Related To: Bug #72777 ------------------------------------------------------------------------ [2016-08-29 23:41:44] fernando at null-life dot com Description: ------------ "match_at" function uses "alloca" to reserve memory, big patterns at "mb_ereg_search_pos" cause buffer overflow, and ilegal access memory. Source code https://github.com/php/php-src/blob/PHP-5.6.25/ext/mbstring/oniguruma/regexec.c#L1237 static int match_at(regex_t* reg, const UChar* str, const UChar* end, #ifdef USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE const UChar* right_range, #endif const UChar* sstart, UChar* sprev, OnigMatchArg* msa) { static UChar FinishCode[] = { OP_FINISH }; int i, n, num_mem, best_len, pop_level; ... STACK_INIT(alloca_base, n, INIT_MATCH_STACK_SIZE); pop_level = reg->stack_pop_level; num_mem = reg->num_mem; repeat_stk = (OnigStackIndex* )alloca_base; mem_start_stk = (OnigStackIndex* )(repeat_stk + reg->num_repeat); mem_end_stk = mem_start_stk + num_mem; mem_start_stk--; /* for index start from 1, mem_start_stk[1]..mem_start_stk[num_mem] */ mem_end_stk--; /* for index start from 1, mem_end_stk[1]..mem_end_stk[num_mem] */ for (i = 1; i <= num_mem; i++) { mem_start_stk[i] = mem_end_stk[i] = INVALID_STACK_INDEX; } ... https://github.com/php/php-src/blob/PHP-5.6.25/ext/mbstring/oniguruma/regexec.c#L1237 #define STACK_INIT(alloc_addr, ptr_num, stack_num) do {\ if (msa->stack_p) {\ alloc_addr = (char* )xalloca(sizeof(char*) * (ptr_num));\ stk_alloc = (OnigStackType* )(msa->stack_p);\ stk_base = stk_alloc;\ stk = stk_base;\ stk_end = stk_base + msa->stack_n;\ }\ else {\ alloc_addr = (char* )xalloca(sizeof(char*) * (ptr_num)\ + sizeof(OnigStackType) * (stack_num));\ stk_alloc = (OnigStackType* )(alloc_addr + sizeof(char*) * (ptr_num));\ stk_base = stk_alloc;\ stk = stk_base;\ stk_end = stk_base + (stack_num);\ }\ } while(0) GDB output: gdb -q --args /home/operac/build3/bin/php poc.php No symbol table is loaded. Use the "file" command. Breakpoint 1 (__asan_report_error) pending. Reading symbols from /home/operac/build3/bin/php...done. gdb-peda$ r Starting program: /home/operac/build3/bin/php test.php [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x7 RBX: 0x1 RCX: 0x7ffffeff81a0 RDX: 0xc ('\x0c') RSI: 0xffffe RDI: 0x7fffff7f8190 RBP: 0x7fffffff9ea0 --> 0x7fffffffa0d0 --> 0x7fffffffa390 --> 0x7fffffffa430 --> 0x7fffffffa480 --> 0x7fffffffa6b0 (--> ...) RSP: 0x7ffffeff81a0 RIP: 0xc3ab1e (<match_at+1470>: mov QWORD PTR [rdi],0xffffffffffffffff) R8 : 0xc280000128e --> 0x0 R9 : 0xfffffeff032 --> 0x0 R10: 0x0 R11: 0x7ffffeff81a0 R12: 0x7fffffff9e70 --> 0x7fffffff9eb0 --> 0x7fffffffa020 --> 0x0 R13: 0x7fffff7f8188 R14: 0x7fffed22f800 --> 0x230000134000130 R15: 0x7ffffeff8198 EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0xc3ab0c <match_at+1452>: shr r9,0x3 0xc3ab10 <match_at+1456>: cmp BYTE PTR [r9+0x7fff8000],0x0 0xc3ab18 <match_at+1464>: jne 0xc57978 <match_at+119832> => 0xc3ab1e <match_at+1470>: mov QWORD PTR [rdi],0xffffffffffffffff 0xc3ab25 <match_at+1477>: mov rdi,r11 0xc3ab28 <match_at+1480>: shr rdi,0x3 0xc3ab2c <match_at+1484>: cmp BYTE PTR [rdi+0x7fff8000],0x0 0xc3ab33 <match_at+1491>: jne 0xc57935 <match_at+119765> [------------------------------------stack-------------------------------------] Invalid $SP address: 0x7ffffeff81a0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0000000000c3ab1e in match_at (reg=reg@entry=0x614000009440, str=str@entry=0x7fffef02f3a8 "Peter is a boy.", end=end@entry=0x7fffef02f3b7 "", right_range=right_range@entry=0x7fffef02f3b7 "", sstart=sstart@entry=0x7fffef02f3a8 "Peter is a boy.", sprev=<optimized out>, msa=0x7fffffffa020) at /home/operac/php-src-56/php-src/ext/mbstring/oniguruma/regexec.c:1280 1280 mem_start_stk[i] = mem_end_stk[i] = INVALID_STACK_INDEX; gdb-peda$ p mem_start_stk[i] Cannot access memory at address 0x7ffffeff81a0 // Invalid memory access gdb-peda$ p mem_end_stk[i] Cannot access memory at address 0x7fffff7f8190 // Invalid memory acess gdb-peda$ p *reg $1 = { p = 0x7fffed22f800 "0\001", used = 0x5ffff5, alloc = 0x7ffff0, state = 0x0, num_mem = 0xffffe, // Num of () num_repeat = 0x0, num_null_check = 0x0, num_comb_exp_check = 0x0, num_call = 0x0, capture_history = 0x0, bt_mem_start = 0x0, bt_mem_end = 0x0, stack_pop_level = 0x0, repeat_range_alloc = 0x0, repeat_range = 0x0, enc = 0x27bf9a0 <OnigEncodingUTF8>, options = 0xc, syntax = 0x27b9500 <OnigSyntaxRuby>, case_fold_flag = 0x40000000, name_table = 0x0, optimize = 0x0, threshold_len = 0x0, anchor = 0x0, anchor_dmin = 0x0, anchor_dmax = 0x0, sub_anchor = 0x0, exact = 0x0, exact_end = 0x0, map = '\276' <repeats 256 times>, int_map = 0x0, int_map_backward = 0x0, dmin = 0xbebebebe, dmax = 0xbebebebe, chain = 0x0 } Test script: --------------- <?php mb_ereg_search_init("Peter is a boy."); $v1=str_repeat("()", 0xffffe); mb_ereg_search_pos($v1); Expected result: ---------------- No crash Actual result: -------------- ================================================================= ==12511==ERROR: AddressSanitizer: SEGV on unknown address 0x7ffdbf0500e0 (pc 0x000000c3ab1e bp 0x7ffdbf851df0 sp 0x7ffdbe8500f0 T0) #0 0xc3ab1d in match_at /home/operac/php-src-56/php-src/ext/mbstring/oniguruma/regexec.c:1280 #1 0xc5e954 in onig_search /home/operac/php-src-56/php-src/ext/mbstring/oniguruma/regexec.c:3634 #2 0xdf983d in _php_mb_regex_ereg_search_exec /home/operac/php-src-56/php-src/ext/mbstring/php_mbregex.c:1228 #3 0xdf983d in zif_mb_ereg_search_pos /home/operac/php-src-56/php-src/ext/mbstring/php_mbregex.c:1290 #4 0x1d6bc67 in zend_do_fcall_common_helper_SPEC /home/operac/php-src-56/php-src/Zend/zend_vm_execute.h:558 #5 0x1c1773c in execute_ex /home/operac/php-src-56/php-src/Zend/zend_vm_execute.h:363 #6 0x195afda in zend_execute_scripts /home/operac/php-src-56/php-src/Zend/zend.c:1341 #7 0x16a889f in php_execute_script /home/operac/php-src-56/php-src/main/main.c:2613 #8 0x1d749ef in do_cli /home/operac/php-src-56/php-src/sapi/cli/php_cli.c:994 #9 0x4551b0 in main /home/operac/php-src-56/php-src/sapi/cli/php_cli.c:1378 #10 0x7f4aa5fb482f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) #11 0x455838 in _start (/home/operac/build3/bin/php+0x455838) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /home/operac/php-src-56/php-src/ext/mbstring/oniguruma/regexec.c:1280 match_at ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=72970&edit=1

« previous php.bugs (#230650) next »