unicorn
unicorn copied to clipboard
Segmentation fault in uc_mem_unmap with Unicorn 2
The following code snippet causes a segmentation fault on Ubuntu 18.04 LTS (Python 3.8.10):
[1] 23351 segmentation fault (core dumped) python test_min.py
import unicorn as uc
class example_class:
def __init__(self):
a = 0
b = 0
c = 0
self.emu = uc.Uc(uc.UC_ARCH_ARM, uc.UC_MODE_THUMB | uc.UC_MODE_MCLASS)
assert not self.emu.mem_map(0x50060800, 0x50060BFF - 0x50060800 + 1)
self.emu.hook_add(
uc.UC_HOOK_MEM_READ,
self.hook_mem_read,
begin=0x50060800 + 0x4,
end=0x50060800 + 0x4,
)
def __del__(self):
for start, end, _ in self.emu.mem_regions():
print(hex(start), hex(end), end - start + 1)
self.emu.mem_unmap(start, end - start + 1)
def hook_mem_read(self, _uci, _access, address, _size, _value, _user_data):
pass
emu = example_class()
del emu
If the line a = 0 is removed, it prints:
0x1f72000000 0x7e900000021 8562252185634
Exception ignored in: <function example_class.__del__ at 0x7f70b81773a0>
Traceback (most recent call last):
File "test_min.py", line 19, in __del__
self.emu.mem_unmap(start, end - start + 1)
File "/home/aiooss/git/venv/lib/python3.8/site-packages/unicorn/unicorn.py", line 634, in mem_unmap
raise UcError(status)
unicorn.unicorn.UcError: Invalid argument (UC_ERR_ARG)
This looks like an use after free. This code works fine with latest version of Unicorn 1.
GDB backtrace:
#0 0x00007fb4a2a17eb9 in uc_mem_regions () from /home/aiooss/git/venv/lib/python3.8/site-packages/unicorn/lib/libunicorn.so.2
#1 0x00007fb4a4d8eff5 in ?? () from /lib/x86_64-linux-gnu/libffi.so.7
#2 0x00007fb4a4d8e40a in ?? () from /lib/x86_64-linux-gnu/libffi.so.7
#3 0x00007fb4a42f5306 in _ctypes_callproc () from /usr/lib/python3.8/lib-dynload/_ctypes.cpython-38-x86_64-linux-gnu.so
#4 0x00007fb4a42f5ae7 in ?? () from /usr/lib/python3.8/lib-dynload/_ctypes.cpython-38-x86_64-linux-gnu.so
#5 0x00000000005f3e1e in _PyObject_MakeTpCall ()
#6 0x0000000000570674 in _PyEval_EvalFrameDefault ()
#7 0x0000000000500773 in ?? ()
#8 0x000000000056b47b in _PyEval_EvalFrameDefault ()
#9 0x00000000005f6836 in _PyFunction_Vectorcall ()
#10 0x00000000005a7b41 in ?? ()
#11 0x000000000069e7eb in ?? ()
#12 0x00000000004f00e8 in ?? ()
#13 0x00000000005fc867 in ?? ()
#14 0x0000000000672fac in PyGC_Collect ()
#15 0x000000000067f8aa in Py_FinalizeEx ()
#16 0x00000000006b70fd in Py_RunMain ()
#17 0x00000000006b736d in Py_BytesMain ()
#18 0x00007fb4a4ba6083 in __libc_start_main (main=0x4eead0 <main>, argc=2, argv=0x7ffe3c8021e8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffe3c8021d8) at ../csu/libc-start.c:308
#19 0x00000000005fa5ce in _start ()
GDB disassembly:
Dump of assembler code for function uc_mem_regions:
0x00007f380574ae40 <+0>: push %r12
0x00007f380574ae42 <+2>: mov %rdi,%r12
0x00007f380574ae45 <+5>: push %rbp
0x00007f380574ae46 <+6>: mov %rsi,%rbp
0x00007f380574ae49 <+9>: push %rbx
0x00007f380574ae4a <+10>: cmpb $0x0,0x76b(%rdi)
0x00007f380574ae51 <+17>: mov %rdx,%rbx
0x00007f380574ae54 <+20>: je 0x7f380574aee0 <uc_mem_regions+160>
0x00007f380574ae5a <+26>: mov 0x730(%r12),%eax
0x00007f380574ae62 <+34>: xor %edi,%edi
0x00007f380574ae64 <+36>: mov %eax,(%rbx)
0x00007f380574ae66 <+38>: test %eax,%eax
0x00007f380574ae68 <+40>: jne 0x7f380574ae78 <uc_mem_regions+56>
0x00007f380574ae6a <+42>: mov %rdi,0x0(%rbp)
0x00007f380574ae6e <+46>: xor %eax,%eax
0x00007f380574ae70 <+48>: pop %rbx
0x00007f380574ae71 <+49>: pop %rbp
0x00007f380574ae72 <+50>: pop %r12
0x00007f380574ae74 <+52>: retq
0x00007f380574ae75 <+53>: nopl (%rax)
0x00007f380574ae78 <+56>: lea (%rax,%rax,2),%rdi
0x00007f380574ae7c <+60>: shl $0x3,%rdi
0x00007f380574ae80 <+64>: callq 0x7f3805741380 <g_malloc0@plt>
0x00007f380574ae85 <+69>: mov %rax,%rdi
0x00007f380574ae88 <+72>: test %rax,%rax
0x00007f380574ae8b <+75>: je 0x7f380574afc5 <uc_mem_regions+389>
0x00007f380574ae91 <+81>: mov (%rbx),%eax
0x00007f380574ae93 <+83>: test %eax,%eax
0x00007f380574ae95 <+85>: je 0x7f380574ae6a <uc_mem_regions+42>
0x00007f380574ae97 <+87>: mov 0x728(%r12),%r8
0x00007f380574ae9f <+95>: xor %eax,%eax
0x00007f380574aea1 <+97>: nopl 0x0(%rax)
0x00007f380574aea8 <+104>: mov %eax,%edx
0x00007f380574aeaa <+106>: add $0x1,%eax
0x00007f380574aead <+109>: mov (%r8,%rdx,8),%rcx
0x00007f380574aeb1 <+113>: lea (%rdx,%rdx,2),%rdx
0x00007f380574aeb5 <+117>: lea (%rdi,%rdx,8),%rdx
=> 0x00007f380574aeb9 <+121>: mov 0x40(%rcx),%rsi
0x00007f380574aebd <+125>: mov %rsi,(%rdx)
0x00007f380574aec0 <+128>: mov 0x90(%rcx),%rsi
0x00007f380574aec7 <+135>: mov 0x88(%rcx),%ecx
0x00007f380574aecd <+141>: sub $0x1,%rsi
0x00007f380574aed1 <+145>: mov %rsi,0x8(%rdx)
0x00007f380574aed5 <+149>: mov %ecx,0x10(%rdx)
0x00007f380574aed8 <+152>: cmp %eax,(%rbx)
0x00007f380574aeda <+154>: ja 0x7f380574aea8 <uc_mem_regions+104>
0x00007f380574aedc <+156>: jmp 0x7f380574ae6a <uc_mem_regions+42>
0x00007f380574aede <+158>: xchg %ax,%ax
0x00007f380574aee0 <+160>: lea -0x33b7(%rip),%rax # 0x7f3805747b30 <hook_delete>
0x00007f380574aee7 <+167>: mov 0x1098ca2(%rip),%rdx # 0x7f38067e3b90
0x00007f380574aeee <+174>: xor %ecx,%ecx
0x00007f380574aef0 <+176>: xor %esi,%esi
0x00007f380574aef2 <+178>: mov %rax,0x480(%rdi)
0x00007f380574aef9 <+185>: mov %rax,0x2e8(%rdi)
0x00007f380574af00 <+192>: mov %rax,0x300(%rdi)
0x00007f380574af07 <+199>: mov %rax,0x318(%rdi)
0x00007f380574af0e <+206>: mov %rax,0x330(%rdi)
0x00007f380574af15 <+213>: mov %rax,0x348(%rdi)
0x00007f380574af1c <+220>: mov %rax,0x360(%rdi)
0x00007f380574af23 <+227>: mov %rax,0x378(%rdi)
0x00007f380574af2a <+234>: mov %rax,0x390(%rdi)
0x00007f380574af31 <+241>: mov %rax,0x3a8(%rdi)
0x00007f380574af38 <+248>: mov %rax,0x3c0(%rdi)
0x00007f380574af3f <+255>: mov %rax,0x3d8(%rdi)
0x00007f380574af46 <+262>: mov %rax,0x3f0(%rdi)
0x00007f380574af4d <+269>: mov %rax,0x408(%rdi)
0x00007f380574af54 <+276>: mov %rax,0x420(%rdi)
0x00007f380574af5b <+283>: mov %rax,0x438(%rdi)
0x00007f380574af62 <+290>: mov %rax,0x450(%rdi)
0x00007f380574af69 <+297>: mov %rax,0x468(%rdi)
0x00007f380574af70 <+304>: lea -0x3487(%rip),%rdi # 0x7f3805747af0 <uc_exits_cmp>
0x00007f380574af77 <+311>: callq 0x7f380572f910 <g_tree_new_full@plt>
0x00007f380574af7c <+316>: mov %r12,%rdi
0x00007f380574af7f <+319>: mov %rax,0x718(%r12)
0x00007f380574af87 <+327>: callq 0x7f380573c6a0 <machine_initialize@plt>
0x00007f380574af8c <+332>: mov %eax,%r8d
0x00007f380574af8f <+335>: mov $0x14,%eax
0x00007f380574af94 <+340>: test %r8d,%r8d
0x00007f380574af97 <+343>: jne 0x7f380574ae70 <uc_mem_regions+48>
0x00007f380574af9d <+349>: callq *0x130(%r12)
0x00007f380574afa5 <+357>: mov 0x98(%r12),%rax
0x00007f380574afad <+365>: test %rax,%rax
0x00007f380574afb0 <+368>: je 0x7f380574afb7 <uc_mem_regions+375>
0x00007f380574afb2 <+370>: mov %r12,%rdi
0x00007f380574afb5 <+373>: callq *%rax
0x00007f380574afb7 <+375>: movb $0x1,0x76b(%r12)
0x00007f380574afc0 <+384>: jmpq 0x7f380574ae5a <uc_mem_regions+26>
0x00007f380574afc5 <+389>: mov $0x1,%eax
0x00007f380574afca <+394>: jmpq 0x7f380574ae70 <uc_mem_regions+48>
End of assembler dump.
It looks weird. Thanks for your PoC and I will have a look.
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 15 days.
@wtdcode I think this still isn't fixed. Specifically calling uc.mem_unmap() in __del__ seems to do weird stuff including crashing (segfault) the Python interpreter.
(Correct me if I'm wrong since I didn't test the dev and master has been waaaaaaay behind.)