mupen64plus / mupen64plus-core

Core module of the Mupen64Plus project
1.32k stars 258 forks source link

Out-of-bounds read in multiple functions and NULL pointer dereference #1050

Open 269261 opened 1 year ago

269261 commented 1 year ago

Sample files were attached to this issue in a ZIP file (s2.zip).

Issue 1 - OOB read past the end of itype array

Crash is reproducible only if mupen64plus-core lib was compiled with AddressSanitizer.

Loading and executing attached bug1.z64 file results in the following crash:

$ ./BinAsan/Release/RMG /tmp/bug1.z64
=================================================================
==185744==ERROR: AddressSanitizer: global-buffer-overflow on address 0x7fb32e8d0b60 at pc 0x7fb32ad7ce36 bp 0x7fb300a9cab0 sp 0x7fb300a9caa0
READ of size 1 at 0x7fb32e8d0b60 thread T13 (Thread::Emulati)
    #0 0x7fb32ad7ce35 in address_generation /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:4379
    #1 0x7fb32add0dc2 in new_recompile_block /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:11539
    #2 0x7fb32ad6d338 in get_addr /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:2677
    #3 0x7fb32ad6d5ea in get_addr_ht /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:2693
    #4 0x7fb32add7f12  (/tmp/RMG/BinAsan/Release/Core/libmupen64plus.so+0x1d7f12) (BuildId: b6a0b16a4fee2ce372193dff1a7b713543d87145)

0x7fb32e8d0b60 is located 32 bytes before global variable 'opcode' defined in '/tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:247:15' (0x7fb32e8d0b80) of size 4096
0x7fb32e8d0b60 is located 0 bytes after global variable 'itype' defined in '/tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:246:15' (0x7fb32e8cfb60) of size 4096
SUMMARY: AddressSanitizer: global-buffer-overflow /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:4379 in address_generation
...

Crash happens in:

https://github.com/mupen64plus/mupen64plus-core/blob/f500eb58f76e636e231c3cc2b3d904210f0677c9/src/device/r4300/new_dynarec/new_dynarec.c#L4379

In presented case itype array index is 4096 (i+1=4096), but array size is only 4096 (so highest valid index is 4095). This leads to out-of-bounds read past the end of the itype array.

Issue 2 - OOB read past the end of LUT_r and LUT_w arrays

Loading and executing attached bug2a.z64 and bug2b.z64 files results in the following crashes:

$ gdb -ex run --args Bin/Release/RMG /tmp/bug2a.z64
GNU gdb (Ubuntu 13.1-2ubuntu2) 13.1
...

Thread 14 "Thread::Emulati" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffa63fd6c0 (LWP 186033)]
0x00007fffcc08ed4a in invalidate_block (block=3466518528) at /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:2816
2816      if(page>262143&&g_dev.r4300.cp0.tlb.LUT_r[block]) page=(g_dev.r4300.cp0.tlb.LUT_r[block]^0x80000000)>>12;
(gdb) print block
$1 = 3466518528
...

$ gdb -ex run --args Bin/Release/RMG /tmp/bug2b.z64
GNU gdb (Ubuntu 13.1-2ubuntu2) 13.1
...

Thread 14 "Thread::Emulati" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffd23fd6c0 (LWP 186077)]
0x00007fffc808efac in invalidate_block (block=2433696) at /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:2874
2874      if(g_dev.r4300.cp0.tlb.LUT_w[block]) {
(gdb) print block
$1 = 2433696

Crash happens in one of these places:

https://github.com/mupen64plus/mupen64plus-core/blob/f500eb58f76e636e231c3cc2b3d904210f0677c9/src/device/r4300/new_dynarec/new_dynarec.c#L2816 https://github.com/mupen64plus/mupen64plus-core/blob/f500eb58f76e636e231c3cc2b3d904210f0677c9/src/device/r4300/new_dynarec/new_dynarec.c#L2874

In presented cases LUT_r and LUT_w arrays index (block) equals 3,466,518,528 or 2,433,696, but array size is only 1,048,576. This leads to out-of-bounds read past the end of the arrays and crash due to memory access violation.

Note: not sure, but it looks like g_dev.r4300.cached_interp.invalid_code access also leads to OOB read, though app doesn't crash there:

https://github.com/mupen64plus/mupen64plus-core/blob/f500eb58f76e636e231c3cc2b3d904210f0677c9/src/device/r4300/new_dynarec/new_dynarec.c#L2872

Issue 3 - OOB read of bytes placed before invalidate_block_reg array

Crash is reproducible only if mupen64plus-core lib was compiled with AddressSanitizer.

Loading and executing attached bug3.z64 file results in the following crash:

$ ./BinAsan/Release/RMG /tmp/bug3.z64
=================================================================
==186182==ERROR: AddressSanitizer: global-buffer-overflow on address 0x7f03fe614cb8 at pc 0x7f03fe560f6c bp 0x7f03d438eb60 sp 0x7f03d438eb50
READ of size 8 at 0x7f03fe614cb8 thread T13 (Thread::Emulati)
    #0 0x7f03fe560f6b in do_invstub /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/x64/assem_x64.c:3032
    #1 0x7f03fe5d36c6 in new_recompile_block /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:11693
    #2 0x7f03fe5d7f72  (/tmp/RMG/BinAsan/Release/Core/libmupen64plus.so+0x1d7f72) (BuildId: b6a0b16a4fee2ce372193dff1a7b713543d87145)

...
0x7f03fe614cb8 is located 8 bytes before global variable 'invalidate_block_reg' defined in '/tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/x64/assem_x64.c:58:24' (0x7f03fe614cc0) of size 64
SUMMARY: AddressSanitizer: global-buffer-overflow /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/x64/assem_x64.c:3032 in do_invstub
Shadow bytes around the buggy address:
  0x7f03fe614a00: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f03fe614a80: 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 00 00 00 00
  0x7f03fe614b00: 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9
  0x7f03fe614b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f9
  0x7f03fe614c00: f9 f9 f9 f9 00 00 00 00 f9 f9 f9 f9 00 00 00 00
=>0x7f03fe614c80: 00 00 00 00 f9 f9 f9[f9]00 00 00 00 00 00 00 00
  0x7f03fe614d00: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f03fe614d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f03fe614e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f03fe614e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7f03fe614f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
...

Crash happens in:

https://github.com/mupen64plus/mupen64plus-core/blob/f500eb58f76e636e231c3cc2b3d904210f0677c9/src/device/r4300/new_dynarec/x64/assem_x64.c#L3032

In presented case invalidate_block_reg array index is -1. This leads to out-of-bounds read of bytes placed before invalidate_block_reg array.

Please note that the similar issue may exist in related files too (e.g. assem_x86.c).

Issue 4 - NULL pointer dereference in set_jump_taget function

Loading and executing attached bug4.z64 file results in the following crash:

$ gdb -ex run --args Bin/Release/RMG /tmp/bug4.z64
GNU gdb (Ubuntu 13.1-2ubuntu2) 13.1
...

Thread 14 "Thread::Emulati" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffd23fd6c0 (LWP 186544)]
0x00007fffc8080a13 in set_jump_target (addr=0, target=140736559244610) at /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/x64/assem_x64.c:73
73    if(*ptr==0x0f)
(gdb) print ptr
$1 = (u_char *) 0x0
(gdb) bt
#0  0x00007fffc8080a13 in set_jump_target (addr=0, target=140736559244610) at /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/x64/assem_x64.c:73
#1  0x00007fffc80a3f14 in sjump_assemble (i=743, i_regs=0x7fffcbc2cbf8 <regs+101048>) at /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:7939
#2  0x00007fffc80bd03d in new_recompile_block (addr=-1543503808) at /tmp/RMG/Source/3rdParty/mupen64plus-core/src/device/r4300/new_dynarec/new_dynarec.c:11612
#3  0x00007fffc80bf7f3 in new_dyna_start () at /tmp/RMG/Bin/Release/Core/libmupen64plus.so
#4  0x0000000000000000 in  ()

Crash happens in:

https://github.com/mupen64plus/mupen64plus-core/blob/f500eb58f76e636e231c3cc2b3d904210f0677c9/src/device/r4300/new_dynarec/x64/assem_x64.c#L73

In presented case ptr value is NULL, leading to NULL pointer dereference and crash. This issue does not seem to lead to any security issues.

Please note that the similar issue may exist in related files too (e.g. assem_x86.c).

Test platform