unicorn-engine / unicorn

Unicorn CPU emulator framework (ARM, AArch64, M68K, Mips, Sparc, PowerPC, RiscV, S390x, TriCore, X86)
http://www.unicorn-engine.org
GNU General Public License v2.0
7.33k stars 1.31k forks source link

Segfault on tb_target_set_jmp_target_x86_64 #1923

Open racerxdl opened 4 months ago

racerxdl commented 4 months ago

I was doing some emulation reverse engineering work with Unicorn Engine (emulating x86 realmode bootloader) and after a long time running the session I got this nullptr dereference (segfault). Sadly the payload I'm running is private (I can't share), but I might be able to fix, but I didnt find any reason why that would be null.

It seens that TranslationBlock got the tc.ptr as null, and that gave the dereference. I'm not sure what could be causing it. I was using the upstream version of unicorn with python bindings, but when I got the segfault (is consistenly, I will try run a session saving each code block it tries to execute to have a rough idea where it crashed), I got the latest dev branch and build in debug mode.

Backtrace:

Program received signal SIGSEGV, Segmentation fault.
tb_target_set_jmp_target_x86_64 (tc_ptr=0, jmp_addr=0, addr=140736214069504) at /home/lucas/Works/unicorn/unicorn/qemu/tcg/i386/tcg-target.h:215
215         *(int32_t *)jmp_addr = addr - (jmp_addr + 4);
(gdb) 
(gdb) 
(gdb) bt
#0  tb_target_set_jmp_target_x86_64 (tc_ptr=0, jmp_addr=0, addr=140736214069504) at /home/lucas/Works/unicorn/unicorn/qemu/tcg/i386/tcg-target.h:215
#1  0x00007ffff55f9776 in tb_set_jmp_target_x86_64 (tb=0x7fffb44c7180, n=0, addr=140736214069504) at /home/lucas/Works/unicorn/unicorn/qemu/accel/tcg/cpu-exec.c:207
#2  0x00007ffff55f9848 in tb_add_jump (tb=0x7fffb44c7180, n=0, tb_next=0x7fffb40bf040) at /home/lucas/Works/unicorn/unicorn/qemu/accel/tcg/cpu-exec.c:235
#3  0x00007ffff55f9ac0 in tb_find (cpu=0x55555611f320, last_tb=0x7fffb44c7180, tb_exit=0, cf_mask=0) at /home/lucas/Works/unicorn/unicorn/qemu/accel/tcg/cpu-exec.c:291
#4  0x00007ffff55fa21e in cpu_exec_x86_64 (uc=0x555556031720, cpu=0x55555611f320) at /home/lucas/Works/unicorn/unicorn/qemu/accel/tcg/cpu-exec.c:603
#5  0x00007ffff55bbf97 in tcg_cpu_exec (uc=0x555556031720) at /home/lucas/Works/unicorn/unicorn/qemu/softmmu/cpus.c:96
#6  0x00007ffff55bc262 in resume_all_vcpus_x86_64 (uc=0x555556031720) at /home/lucas/Works/unicorn/unicorn/qemu/softmmu/cpus.c:215
#7  0x00007ffff55bc2fa in vm_start_x86_64 (uc=0x555556031720) at /home/lucas/Works/unicorn/unicorn/qemu/softmmu/cpus.c:234
#8  0x00007ffff55a1e91 in uc_emu_start (uc=0x555556031720, begin=580120, until=18446744073709551615, timeout=0, count=0) at /home/lucas/Works/unicorn/unicorn/uc.c:1033
#9  0x00007ffff72d8e2e in ?? () from /lib/x86_64-linux-gnu/libffi.so.8
#10 0x00007ffff72d5493 in ?? () from /lib/x86_64-linux-gnu/libffi.so.8
#11 0x00007ffff74623e9 in ?? () from /usr/lib/python3.10/lib-dynload/_ctypes.cpython-310-x86_64-linux-gnu.so
#12 0x00007ffff746b302 in ?? () from /usr/lib/python3.10/lib-dynload/_ctypes.cpython-310-x86_64-linux-gnu.so
#13 0x00005555556a4a7b in _PyObject_MakeTpCall ()
#14 0x000055555569d629 in _PyEval_EvalFrameDefault ()
#15 0x00005555556ae9fc in _PyFunction_Vectorcall ()
#16 0x000055555569745c in _PyEval_EvalFrameDefault ()
#17 0x00005555556ae9fc in _PyFunction_Vectorcall ()
#18 0x000055555569745c in _PyEval_EvalFrameDefault ()
#19 0x00005555556939c6 in ?? ()
#20 0x0000555555789256 in PyEval_EvalCode ()
#21 0x00005555557b4108 in ?? ()
#22 0x00005555557ad9cb in ?? ()
#23 0x00005555557b3e55 in ?? ()
#24 0x00005555557b3338 in _PyRun_SimpleFileObject ()
#25 0x00005555557b2f83 in _PyRun_AnyFileObject ()
#26 0x00005555557a5a5e in Py_RunMain ()
#27 0x000055555577c02d in Py_BytesMain ()
#28 0x00007ffff7c5ad90 in __libc_start_call_main (main=main@entry=0x55555577bff0, argc=argc@entry=2, argv=argv@entry=0x7fffffffdbc8) at ../sysdeps/nptl/libc_start_call_main.h:58
#29 0x00007ffff7c5ae40 in __libc_start_main_impl (main=0x55555577bff0, argc=2, argv=0x7fffffffdbc8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdbb8) at ../csu/libc-start.c:392
wtdcode commented 4 months ago

My wild guess is running out of memory or some internal buffers causing this null pointer.

racerxdl commented 4 months ago

Just checked memory usage, its suspicously high. The application crashed with almost 2GB of reserved memory, and my mapped memory is only about 256MB. Still, the host has plently of room (64GB).

sadeli413 commented 1 month ago

I am encountering the same segfault in tb_set_jmp_target_arm. I do notice that my memory usage also rises to about 2GB but I have about 32GB of ram on my host. I don't quite have a minimal reproduction code yet.

sadeli413 commented 1 month ago

I encountered the segfault because I'm running emu_start in a loop, and unicorn segfaults after the loop runs a few million times.

For what it's worth, my workaround is once every million times in the loop, save the context, destroy the emulator, create a new emulator, and restore the context. This seems to limit the memory usage and resolve whatever is causing the segfault.

racerxdl commented 3 weeks ago

I encountered the segfault because I'm running emu_start in a loop, and unicorn segfaults after the loop runs a few million times.

For what it's worth, my workaround is once every million times in the loop, save the context, destroy the emulator, create a new emulator, and restore the context. This seems to limit the memory usage and resolve whatever is causing the segfault.

That's a clever way of avoiding the crash. I will use it :P - Thanks!