Issue #12423 has been reported by David Moore.

----------------------------------------
Bug #12423: Regexp: Heap Buffer Overflow in regparse.c : next_state_value()
https://bugs.ruby-lang.org/issues/12423

* Author: David Moore
* Status: Open
* Priority: Normal
* Assignee: 
* ruby -v: ruby 2.3.1p112 (2016-04-26 revision 54768) [i686-linux]
* Backport: 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN
----------------------------------------
A crafted regular expression will cause a heap buffer overflow leading to invalid 4 byte reads/writes on 32-bit Ubuntu 14.04. The regular expression fails to close a character class and has an octal zero as the first character in the character class. 

Despite the buffer overflow, ruby does not crash. This bug may have the same root cause as #12420.

~~~
grajagandev# cat load-re.rb 
File.open(ARGV[0]) do |f|  
  @re = Regexp.new("/" + File.read(f) + "/")
end  
grajagandev# xxd overflow-next_state_value
0000000: 5b5c 3630 3030 3030 3030 3030 3030 0a    [\600000000000.
grajagandev# ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [i686-linux]
grajagandev# uname -a
Linux x-Acer 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:18:00 UTC 2015 i686 i686 i686 GNU/Linux
grajagandev# ruby load-re.rb overflow-next_state_value
=================================================================
==11873== ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb470cd88 at pc 0xb730f9fd bp 0xbfc4d458 sp 0xbfc4d44c
READ of size 4 at 0xb470cd88 thread T0
    #0 0xb730f9fc (/usr/local/bin/ruby+0x1cb9fc)
    #1 0xb73116c9 (/usr/local/bin/ruby+0x1cd6c9)
    #2 0xb731a6fb (/usr/local/bin/ruby+0x1d66fb)
    #3 0xb731b856 (/usr/local/bin/ruby+0x1d7856)
    #4 0xb731baee (/usr/local/bin/ruby+0x1d7aee)
    #5 0xb731bdd9 (/usr/local/bin/ruby+0x1d7dd9)
    #6 0xb731c376 (/usr/local/bin/ruby+0x1d8376)
    #7 0xb72ccf09 (/usr/local/bin/ruby+0x188f09)
    #8 0xb729a77f (/usr/local/bin/ruby+0x15677f)
    #9 0xb729a8b6 (/usr/local/bin/ruby+0x1568b6)
    #10 0xb72a586e (/usr/local/bin/ruby+0x16186e)
    #11 0xb72a5bc1 (/usr/local/bin/ruby+0x161bc1)
    #12 0xb72a943c (/usr/local/bin/ruby+0x16543c)
    #13 0xb7450da4 (/usr/local/bin/ruby+0x30cda4)
    #14 0xb74844a6 (/usr/local/bin/ruby+0x3404a6)
    #15 0xb74845fc (/usr/local/bin/ruby+0x3405fc)
    #16 0xb7484be3 (/usr/local/bin/ruby+0x340be3)
    #17 0xb7483fbd (/usr/local/bin/ruby+0x33ffbd)
    #18 0xb74860ed (/usr/local/bin/ruby+0x3420ed)
    #19 0xb748763d (/usr/local/bin/ruby+0x34363d)
    #20 0xb74884cd (/usr/local/bin/ruby+0x3444cd)
    #21 0xb718477e (/usr/local/bin/ruby+0x4077e)
    #22 0xb72549ed (/usr/local/bin/ruby+0x1109ed)
    #23 0xb7450da4 (/usr/local/bin/ruby+0x30cda4)
    #24 0xb745342d (/usr/local/bin/ruby+0x30f42d)
    #25 0xb745368d (/usr/local/bin/ruby+0x30f68d)
    #26 0xb7456088 (/usr/local/bin/ruby+0x312088)
    #27 0xb74574da (/usr/local/bin/ruby+0x3134da)
    #28 0xb74578b2 (/usr/local/bin/ruby+0x3138b2)
    #29 0xb7465a0b (/usr/local/bin/ruby+0x321a0b)
    #30 0xb749718c (/usr/local/bin/ruby+0x35318c)
    #31 0xb7492c08 (/usr/local/bin/ruby+0x34ec08)
    #32 0xb74935db (/usr/local/bin/ruby+0x34f5db)
    #33 0xb7493686 (/usr/local/bin/ruby+0x34f686)
    #34 0xb7493882 (/usr/local/bin/ruby+0x34f882)
    #35 0xb7488eae (/usr/local/bin/ruby+0x344eae)
    #36 0xb7488ecd (/usr/local/bin/ruby+0x344ecd)
    #37 0xb7488efc (/usr/local/bin/ruby+0x344efc)
    #38 0xb718289f (/usr/local/bin/ruby+0x3e89f)
    #39 0xb7203f64 (/usr/local/bin/ruby+0xbff64)
    #40 0xb7450da4 (/usr/local/bin/ruby+0x30cda4)
    #41 0xb745342d (/usr/local/bin/ruby+0x30f42d)
    #42 0xb745368d (/usr/local/bin/ruby+0x30f68d)
    #43 0xb7456088 (/usr/local/bin/ruby+0x312088)
    #44 0xb74574da (/usr/local/bin/ruby+0x3134da)
    #45 0xb74578b2 (/usr/local/bin/ruby+0x3138b2)
    #46 0xb746510f (/usr/local/bin/ruby+0x32110f)
    #47 0xb749718c (/usr/local/bin/ruby+0x35318c)
    #48 0xb74997a5 (/usr/local/bin/ruby+0x3557a5)
    #49 0xb717f669 (/usr/local/bin/ruby+0x3b669)
    #50 0xb717f8cd (/usr/local/bin/ruby+0x3b8cd)
    #51 0xb717f882 (/usr/local/bin/ruby+0x3b882)
    #52 0xb717a1a3 (/usr/local/bin/ruby+0x361a3)
    #53 0xb58f6a82 (/lib/i386-linux-gnu/libc-2.19.so+0x19a82)
    #54 0xb7179fd0 (/usr/local/bin/ruby+0x35fd0)
0xb470cd88 is located 8 bytes to the left of 44-byte region [0xb470cd90,0xb470cdbc)
allocated by thread T0 here:
    #0 0xb5b3a854 (/usr/lib/i386-linux-gnu/libasan.so.0.0.0+0x16854)
    #1 0xb72f61f2 (/usr/local/bin/ruby+0x1b21f2)
    #2 0xb72f7d84 (/usr/local/bin/ruby+0x1b3d84)
    #3 0xb731b245 (/usr/local/bin/ruby+0x1d7245)
    #4 0xb731b75d (/usr/local/bin/ruby+0x1d775d)
    #5 0xb731baee (/usr/local/bin/ruby+0x1d7aee)
    #6 0xb7315d4c (/usr/local/bin/ruby+0x1d1d4c)
    #7 0xb7318dc0 (/usr/local/bin/ruby+0x1d4dc0)
    #8 0xb731b856 (/usr/local/bin/ruby+0x1d7856)
    #9 0xb731baee (/usr/local/bin/ruby+0x1d7aee)
    #10 0xb731bdd9 (/usr/local/bin/ruby+0x1d7dd9)
    #11 0xb731c376 (/usr/local/bin/ruby+0x1d8376)
    #12 0xb72ccf09 (/usr/local/bin/ruby+0x188f09)
    #13 0xb729a77f (/usr/local/bin/ruby+0x15677f)
    #14 0xb729a8b6 (/usr/local/bin/ruby+0x1568b6)
    #15 0xb72a586e (/usr/local/bin/ruby+0x16186e)
    #16 0xb72a5bc1 (/usr/local/bin/ruby+0x161bc1)
    #17 0xb72a62cf (/usr/local/bin/ruby+0x1622cf)
    #18 0xb75afcb2 (/usr/local/bin/ruby+0x46bcb2)
    #19 0xb75afcef (/usr/local/bin/ruby+0x46bcef)
    #20 0xb757ff6a (/usr/local/bin/ruby+0x43bf6a)
    #21 0xb758a473 (/usr/local/bin/ruby+0x446473)
    #22 0xb74acc2c (/usr/local/bin/ruby+0x368c2c)
    #23 0xb758aa46 (/usr/local/bin/ruby+0x446a46)
    #24 0xb758b64c (/usr/local/bin/ruby+0x44764c)
    #25 0xb7326787 (/usr/local/bin/ruby+0x1e2787)
    #26 0xb718289f (/usr/local/bin/ruby+0x3e89f)
    #27 0xb7327029 (/usr/local/bin/ruby+0x1e3029)
    #28 0xb73270f2 (/usr/local/bin/ruby+0x1e30f2)
    #29 0xb7189871 (/usr/local/bin/ruby+0x45871)
Shadow bytes around the buggy address:
  0x368e1960: fa fa 00 00 00 00 00 fa fa fa fd fd fd fd fd fa
  0x368e1970: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 04
  0x368e1980: fa fa 00 00 00 00 00 04 fa fa 00 00 00 00 00 04
  0x368e1990: fa fa 00 00 00 00 00 04 fa fa 00 00 00 00 00 04
  0x368e19a0: fa fa 00 00 00 00 00 04 fa fa 00 00 00 00 00 04
=>0x368e19b0: fa[fa]00 00 00 00 00 04 fa fa 00 00 00 00 00 04
  0x368e19c0: fa fa 00 00 00 00 00 04 fa fa 00 00 00 00 00 04
  0x368e19d0: fa fa 00 00 00 00 00 04 fa fa 00 00 00 00 00 fa
  0x368e19e0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x368e19f0: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x368e1a00: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa
  Heap righ redzone:     fb
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack partial redzone: f4
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  ASan internal:         fe
==11873== ABORTING
grajagandev#
grajagandev# valgrind --max-stackframe=90000000 ruby load-re.rb overflow-next_state_value
==23692== Memcheck, a memory error detector
==23692== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==23692== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==23692== Command: ruby load-re.rb overflow-next_state_value
==23692== 
==23692== Invalid read of size 4
==23692==    at 0x1C9588: next_state_val (regparse.c:4478)
==23692==    by 0x1CA0D7: parse_char_class (regparse.c:4725)
==23692==    by 0x1CD36D: parse_exp (regparse.c:6187)
==23692==    by 0x1CD8F5: parse_branch (regparse.c:6365)
==23692==    by 0x1CD9BD: parse_subexp (regparse.c:6395)
==23692==    by 0x1CDB5D: parse_regexp (regparse.c:6443)
==23692==    by 0x1CDC80: onig_parse_make_tree (regparse.c:6485)
==23692==    by 0x1B27C6: onig_compile (regcomp.c:5739)
==23692==    by 0x1A0C20: onig_new_with_source (re.c:849)
==23692==    by 0x1A0CA8: make_regexp (re.c:873)
==23692==    by 0x1A479D: rb_reg_initialize (re.c:2546)
==23692==    by 0x1A4905: rb_reg_initialize_str (re.c:2571)
==23692==  Address 0x4cb6180 is 12 bytes after a block of size 44 alloc'd
==23692==    at 0x482A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==23692==    by 0x1C14CD: node_new (regparse.c:1151)
==23692==    by 0x1C17D0: node_new_list (regparse.c:1291)
==23692==    by 0x1CD953: parse_branch (regparse.c:6377)
==23692==    by 0x1CD9BD: parse_subexp (regparse.c:6395)
==23692==    by 0x1CDB5D: parse_regexp (regparse.c:6443)
==23692==    by 0x1CDC80: onig_parse_make_tree (regparse.c:6485)
==23692==    by 0x1B27C6: onig_compile (regcomp.c:5739)
==23692==    by 0x1A0C20: onig_new_with_source (re.c:849)
==23692==    by 0x1A0CA8: make_regexp (re.c:873)
==23692==    by 0x1A479D: rb_reg_initialize (re.c:2546)
==23692==    by 0x1A4905: rb_reg_initialize_str (re.c:2571)
==23692== 
==23692== Invalid read of size 4
==23692==    at 0x1C95CB: next_state_val (regparse.c:4478)
==23692==    by 0x1CA0D7: parse_char_class (regparse.c:4725)
==23692==    by 0x1CD36D: parse_exp (regparse.c:6187)
==23692==    by 0x1CD8F5: parse_branch (regparse.c:6365)
==23692==    by 0x1CD9BD: parse_subexp (regparse.c:6395)
==23692==    by 0x1CDB5D: parse_regexp (regparse.c:6443)
==23692==    by 0x1CDC80: onig_parse_make_tree (regparse.c:6485)
==23692==    by 0x1B27C6: onig_compile (regcomp.c:5739)
==23692==    by 0x1A0C20: onig_new_with_source (re.c:849)
==23692==    by 0x1A0CA8: make_regexp (re.c:873)
==23692==    by 0x1A479D: rb_reg_initialize (re.c:2546)
==23692==    by 0x1A4905: rb_reg_initialize_str (re.c:2571)
==23692==  Address 0x4cb6180 is 12 bytes after a block of size 44 alloc'd
==23692==    at 0x482A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==23692==    by 0x1C14CD: node_new (regparse.c:1151)
==23692==    by 0x1C17D0: node_new_list (regparse.c:1291)
==23692==    by 0x1CD953: parse_branch (regparse.c:6377)
==23692==    by 0x1CD9BD: parse_subexp (regparse.c:6395)
==23692==    by 0x1CDB5D: parse_regexp (regparse.c:6443)
==23692==    by 0x1CDC80: onig_parse_make_tree (regparse.c:6485)
==23692==    by 0x1B27C6: onig_compile (regcomp.c:5739)
==23692==    by 0x1A0C20: onig_new_with_source (re.c:849)
==23692==    by 0x1A0CA8: make_regexp (re.c:873)
==23692==    by 0x1A479D: rb_reg_initialize (re.c:2546)
==23692==    by 0x1A4905: rb_reg_initialize_str (re.c:2571)
==23692== 
==23692== Invalid write of size 4
==23692==    at 0x1C95F5: next_state_val (regparse.c:4478)
==23692==    by 0x1CA0D7: parse_char_class (regparse.c:4725)
==23692==    by 0x1CD36D: parse_exp (regparse.c:6187)
==23692==    by 0x1CD8F5: parse_branch (regparse.c:6365)
==23692==    by 0x1CD9BD: parse_subexp (regparse.c:6395)
==23692==    by 0x1CDB5D: parse_regexp (regparse.c:6443)
==23692==    by 0x1CDC80: onig_parse_make_tree (regparse.c:6485)
==23692==    by 0x1B27C6: onig_compile (regcomp.c:5739)
==23692==    by 0x1A0C20: onig_new_with_source (re.c:849)
==23692==    by 0x1A0CA8: make_regexp (re.c:873)
==23692==    by 0x1A479D: rb_reg_initialize (re.c:2546)
==23692==    by 0x1A4905: rb_reg_initialize_str (re.c:2571)
==23692==  Address 0x4cb6180 is 12 bytes after a block of size 44 alloc'd
==23692==    at 0x482A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==23692==    by 0x1C14CD: node_new (regparse.c:1151)
==23692==    by 0x1C17D0: node_new_list (regparse.c:1291)
==23692==    by 0x1CD953: parse_branch (regparse.c:6377)
==23692==    by 0x1CD9BD: parse_subexp (regparse.c:6395)
==23692==    by 0x1CDB5D: parse_regexp (regparse.c:6443)
==23692==    by 0x1CDC80: onig_parse_make_tree (regparse.c:6485)
==23692==    by 0x1B27C6: onig_compile (regcomp.c:5739)
==23692==    by 0x1A0C20: onig_new_with_source (re.c:849)
==23692==    by 0x1A0CA8: make_regexp (re.c:873)
==23692==    by 0x1A479D: rb_reg_initialize (re.c:2546)
==23692==    by 0x1A4905: rb_reg_initialize_str (re.c:2571)
==23692== 
load-re.rb:2:in `initialize': premature end of char-class: /\/[\600000000000 (RegexpError)
\//
	from load-re.rb:2:in `new'
	from load-re.rb:2:in `block in <main>'
	from load-re.rb:1:in `open'
	from load-re.rb:1:in `<main>'
==23692== 
==23692== HEAP SUMMARY:
==23692==     in use at exit: 1,796,552 bytes in 27,452 blocks
==23692==   total heap usage: 52,413 allocs, 24,961 frees, 6,176,416 bytes allocated
==23692== 
==23692== LEAK SUMMARY:
==23692==    definitely lost: 289,615 bytes in 6,018 blocks
==23692==    indirectly lost: 341,542 bytes in 7,685 blocks
==23692==      possibly lost: 994,526 bytes in 9,609 blocks
==23692==    still reachable: 170,869 bytes in 4,140 blocks
==23692==         suppressed: 0 bytes in 0 blocks
==23692== Rerun with --leak-check=full to see details of leaked memory
==23692== 
==23692== For counts of detected and suppressed errors, rerun with: -v
==23692== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

~~~

---Files--------------------------------
load-re.rb (79 Bytes)
overflow-next_state_value (15 Bytes)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>