oneafter · GitHub

Description

We discovered a Heap-buffer-overflow vulnerability in mruby. The crash occurs in the main VM loop (mrb_vm_exec) when executing bytecode generated from a specifically malformed Ruby source string.

The ASAN report indicates a READ memory access violation 140 bytes beyond a small allocated region. The region was allocated during code generation (scope_finish), but the VM attempts to access registers beyond this scope.

Environment

  • OS: Linux x86_64
  • Complier: Clang
  • Build Configuration: Release mode with ASan enabled.

Vulnerability Details

  • Target: mruby
  • Vulnerability Type: Heap-buffer-overflow (READ)
  • Function: mrb_vm_exec
  • Location: src/vm.c:1953
  • Root Cause Analysis: The vulnerability stems from a discrepancy between the parser/compiler and the VM:
  1. The parser accepts the malformed source R=>^ą;0 containing non-ASCII characters and operators without raising a SyntaxError.
  2. The code generator (codegen.c, scope_finish) calculates the required stack size for this scope and allocates a small region (12 bytes).
  3. However, the generated bytecode contains instructions that access register indices far beyond this allocated size (offset 140).
  4. When mrb_vm_exec executes these instructions, it reads from unmapped heap memory.

Reproduce

  1. Build mruby with Release optimization and ASAN enabled.
  2. Run with the crashing file:
poc
R=>^ą;0
./bin/mruby poc

ASAN report

==2323==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000002a68 at pc 0x561029ce08be bp 0x7fffc668f610 sp 0x7fffc668f608
READ of size 4 at 0x502000002a68 thread T0
    #0 0x561029ce08bd in mrb_vm_exec /src/mruby/src/vm.c:1953:43
    #1 0x561029d0f489 in mrb_load_exec /src/mruby/mrbgems/mruby-compiler/core/parse.y:7786:7
    #2 0x561029d105f7 in mrb_load_detect_file_cxt /src/mruby/mrbgems/mruby-compiler/core/parse.y:7829:12
    #3 0x561029bb504e in main /src/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c:355:11
    #4 0x7f812d33e1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #5 0x7f812d33e28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
    #6 0x561029acf894 in _start (/src/mruby/build/host/bin/mruby+0xb9894) (BuildId: 4a1aaec9cda2051f49b103ec09909d7efb47b987)
0x502000002a68 is located 86 bytes after 2-byte region [0x502000002a10,0x502000002a12)
allocated by thread T0 here:
    #0 0x561029b6fae0 in realloc (/src/mruby/build/host/bin/mruby+0x159ae0) (BuildId: 4a1aaec9cda2051f49b103ec09909d7efb47b987)
    #1 0x561029bff7bd in mrb_realloc_simple /src/mruby/src/gc.c:202:8
    #2 0x561029bff7bd in mrb_realloc /src/mruby/src/gc.c:216:8
    #3 0x561029bff7bd in mrb_malloc /src/mruby/src/gc.c:232:10
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/mruby/src/vm.c:1953:43 in mrb_vm_exec
Shadow bytes around the buggy address:
  0x502000002780: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x502000002800: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
  0x502000002880: fa fa 00 00 fa fa 00 fa fa fa 00 fa fa fa 03 fa
  0x502000002900: fa fa fd fa fa fa 04 fa fa fa fd fa fa fa fd fa
  0x502000002980: fa fa 00 00 fa fa 00 00 fa fa 00 04 fa fa 00 fa
=>0x502000002a00: fa fa 02 fa fa fa fa fa fa fa fa fa fa[fa]fa fa
  0x502000002a80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000002b00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000002b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000002c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000002c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==2323==ABORTING

Read the original on github.com ↗