unicorn icon indicating copy to clipboard operation
unicorn copied to clipboard

Segmentation fault in uc_mem_unmap with Unicorn 2

Open aiooss-ledger opened this issue 3 years ago • 3 comments

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.

aiooss-ledger avatar Jul 08 '22 08:07 aiooss-ledger

It looks weird. Thanks for your PoC and I will have a look.

wtdcode avatar Jul 08 '22 15:07 wtdcode

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.

github-actions[bot] avatar Sep 07 '22 06:09 github-actions[bot]

@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.)

dogtopus avatar Feb 12 '24 02:02 dogtopus