Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RecursionError: maximum recursion depth exceeded while calling a Python object #2162

Open
PlatyPew opened this issue May 10, 2024 · 5 comments
Labels

Comments

@PlatyPew
Copy link

Description

When using qiling with the gdb flag, attaching to the process with target remote :9999 causes a maximum recursion depth exceeded error. Works fine with vanilla gdb.

Set whether to print a full stacktrace for exceptions raised in Pwndbg commands to 'on'.
Traceback (most recent call last):
...
...
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/vmmap.py", line 204, in explore
    flags |= 1 if not pwndbg.gdblib.stack.is_executable() else 0
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/stack.py", line 71, in is_executable
    ehdr = pwndbg.gdblib.elf.exe()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/proc.py", line 149, in wrapper
    return func(*a, **kw)
           ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/elf.py", line 224, in exe
    return load(e)
           ^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/elf.py", line 262, in load
    return get_ehdr(pointer)[1]
           ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/elf.py", line 292, in get_ehdr
    vmmap = pwndbg.gdblib.vmmap.find(pointer)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/vmmap.py", line 171, in find
    for page in get():
                ^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/vmmap.py", line 105, in get
    proc_maps = proc_tid_maps()
                ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/vmmap.py", line 451, in proc_tid_maps
    data = pwndbg.gdblib.file.get(location).decode()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/file.py", line 117, in get
    local_path = get_file(path)
                 ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/file.py", line 69, in get_file
    qemu_root = pwndbg.gdblib.qemu.root()
                ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/gdblib/qemu.py", line 75, in root
    if not is_qemu_usermode():
           ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/pwndbg/lib/cache.py", line 132, in decorator
    key: Tuple[Any] = (a, _KWARGS_SEPARATOR, *kw.items())
                                              ^^^^^^^^^^
RecursionError: maximum recursion depth exceeded while calling a Python object

Steps to reproduce

Install qiling and the rootfs.

Compile a simple binary (in this case, it's just a simple hello world) with gcc -o main main.c

#include <stdio.h>
void main() {
    puts("Hello World");
}

Place the binary in rootfs/x8664_linux/bin and using qltool to run the binary.

$ qltool run --gdb --rootfs rootfs/x8664_linux rootfs/x8664_linux/bin/main
...
[=]     gdb> stopped at entry point: 0x5555555550a0
[=]     gdb> listening on 127.0.0.1:9999

Attach to the process in gdb with target remote :9999

My setup

Gdb: 14.2
Python: 3.11.8 (main, Mar 6 2024, 04:55:17) [GCC 12.1.0]
Pwndbg: 2024.02.14
Capstone: 5.0.1280
Unicorn: 2.0.1

Related

Related to #2132 and possibly #2110

@PlatyPew PlatyPew added the bug label May 10, 2024
@disconnect3d
Copy link
Member

Does this setup provide vmmap information in pure GDB that u can fetch via info proc mappings?

If so, it should probably just work 🤔

@PlatyPew
Copy link
Author

PlatyPew commented May 22, 2024

After attaching to the process, info proc mappings work fine, but vmmap does not work.

0x00000000004005b0 in _start ()
Exception occurred: Error: maximum recursion depth exceeded (<class 'RecursionError'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'RecursionError'>: maximum recursion depth exceeded
Exception occurred: Error: maximum recursion depth exceeded (<class 'RecursionError'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'RecursionError'>: maximum recursion depth exceeded
pwndbg> info proc mappings 
process 42000
Mapped address spaces:

          Start Addr           End Addr       Size     Offset  Perms  objfile
             0x30000            0x31000     0x1000        0x0  rwxp   [GDT]
            0x400000           0x401000     0x1000        0x0  r-xp   /home/pwnpad/x8664_linux/bin/ret2win
            0x600000           0x601000     0x1000        0x0  r--p   /home/pwnpad/x8664_linux/bin/ret2win
            0x601000           0x602000     0x1000        0x0  rw-p   /home/pwnpad/x8664_linux/bin/ret2win
            0x602000           0x604000     0x2000        0x0  rwxp   [hook_mem]
      0x7fffb7dd6000     0x7fffb7fbd000   0x1e7000        0x0  r-xp   [mmap] libc.so.6
      0x7fffb7fbd000     0x7fffb81bd000   0x200000        0x0  ---p   [mmap] libc.so.6
      0x7fffb81bd000     0x7fffb81c1000     0x4000        0x0  r--p   [mmap] libc.so.6
      0x7fffb81c1000     0x7fffb81c3000     0x2000        0x0  rw-p   [mmap] libc.so.6
      0x7fffb81c3000     0x7fffb81c7000     0x4000        0x0  rw-p   [mmap anonymous]
      0x7fffb81c7000     0x7fffb81c9000     0x2000        0x0  rw-p   [mmap anonymous]
      0x7ffff7dd5000     0x7ffff7dfc000    0x27000        0x0  r-xp   /home/pwnpad/x8664_linux/lib64/ld-linux-x86-64.so.2
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000        0x0  r--p   /home/pwnpad/x8664_linux/lib64/ld-linux-x86-64.so.2
      0x7ffff7ffd000     0x7ffff7fff000     0x2000        0x0  rw-p   /home/pwnpad/x8664_linux/lib64/ld-linux-x86-64.so.2
      0x7ffffffd0000     0x800000000000    0x30000        0x0  rwxp   [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0  rwxp   [vsyscall]
Exception occurred: Error: maximum recursion depth exceeded (<class 'RecursionError'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'RecursionError'>: maximum recursion depth exceeded
pwndbg> vmmap
There are no mappings for specified address or module.
Exception occurred: Error: maximum recursion depth exceeded (<class 'RecursionError'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'RecursionError'>: maximum recursion depth exceeded

Here are the error messages, the only difference is that I've upgrade from Python 3.11 to Python 3.12

  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/vmmap.py", line 204, in explore
    flags |= 1 if not pwndbg.gdblib.stack.is_executable() else 0
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/stack.py", line 71, in is_executable
    ehdr = pwndbg.gdblib.elf.exe()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/proc.py", line 149, in wrapper
    return func(*a, **kw)
           ^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/elf.py", line 224, in exe
    return load(e)
           ^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/elf.py", line 262, in load
    return get_ehdr(pointer)[1]
           ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/elf.py", line 292, in get_ehdr
    vmmap = pwndbg.gdblib.vmmap.find(pointer)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/lib/cache.py", line 141, in decorator
    value = func(*a, **kw)
            ^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/vmmap.py", line 175, in find
    return explore(address)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/pwndbg/gdblib/abi.py", line 64, in caller
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^

@disconnect3d
Copy link
Member

disconnect3d commented May 22, 2024 via email

@PlatyPew
Copy link
Author

I do have a really scuffed fix for this where set vmmap to return None if the recursion levels go beyond 200.

--- pwndbg/gdblib/elf.py.bak    2024-05-23 13:25:43.549416010 +0800
+++ pwndbg/gdblib/elf.py        2024-05-23 13:27:54.612273001 +0800
@@ -10,6 +10,7 @@

 import ctypes
 import importlib
+import inspect
 import sys
 from collections import namedtuple
 from typing import List
@@ -289,7 +290,10 @@
         else:
             return None, None
     else:
-        vmmap = pwndbg.gdblib.vmmap.find(pointer)
+        if len(inspect.stack()) < 200:
+            vmmap = pwndbg.gdblib.vmmap.find(pointer)
+        else:
+            vmmap = None

         # If there is no vmmap for the requested address, we can't do much
         # (e.g. it could have been unmapped for whatever reason)

What I do notice is that there are many repeats of the same section. The higher the recursion limit I set, the more copies of the <explored> regions I see.

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
             Start                End Perm     Size Offset File
          0x400000           0x401000 r-xp     1000      0 x8664_linux/bin/ret2win
          0x400000           0x401000 rw-p     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x400000           0x401000 rwxp     1000      0 <explored>
          0x401000           0x600000 ---p   1ff000      0 x8664_linux/bin/ret2win
          0x600000           0x601000 r--p     1000      0 x8664_linux/bin/ret2win
          0x601000           0x602000 rw-p     1000   1000 x8664_linux/bin/ret2win
    0x7fffb7dd6000     0x7fffb7fbd000 r-xp   1e7000      0 target:/lib/libc.so.6
    0x7fffb7dd6000     0x7fffb81c9000 rwxp   3f3000      0 <explored>
    0x7fffb7fbd000     0x7fffb81bd000 ---p   200000 1e7000 target:/lib/libc.so.6
    0x7fffb81bd000     0x7fffb81c1000 r--p     4000 1e7000 target:/lib/libc.so.6
    0x7fffb81c1000     0x7fffb81c7000 rw-p     6000 1eb000 target:/lib/libc.so.6
    0x7ffff7dd5000     0x7ffff7dfc000 r-xp    27000      0 [linker]
    0x7ffff7dd5000     0x7ffff7dfc000 r-xp    27000      0 target:/lib64/ld-linux-x86-64.so.2
    0x7ffff7dd5000     0x7ffff7dfc000 rwxp    27000      0 <explored>
    0x7ffff7dfc000     0x7ffff7ffc000 ---p   200000  27000 [linker]
    0x7ffff7dfc000     0x7ffff7ffc000 ---p   200000  27000 target:/lib64/ld-linux-x86-64.so.2
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000  27000 [linker]
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000  27000 target:/lib64/ld-linux-x86-64.so.2
    0x7ffff7ffd000     0x7ffff7fff000 rw-p     2000  28000 [linker]
    0x7ffff7ffd000     0x7ffff7fff000 rw-p     2000  28000 target:/lib64/ld-linux-x86-64.so.2
    0x7ffffffd0000     0x800000000000 rwxp    30000      0 <explored>
    0x7ffffffd0000     0x800000000000 rwxp    30000      0 <explored>

@PlatyPew
Copy link
Author

Alternatively, if I remove the qemu check, it will attempt to call info_proc_maps() first. It's just a wild guess but I think the underlying issue is that Qiling does not respond to maintenance packet Qqemu.sstepbits, therefore it calls proc_tid_maps() which causes the recursion issue.

I haven't tested this extensively, but removing the if statement seems to have solved the issue. But who knows what it will break :/

--- pwndbg/gdblib/vmmap.py.bak  2024-05-23 22:00:55.436500006 +0800
+++ pwndbg/gdblib/vmmap.py      2024-05-23 21:56:38.087046012 +0800
@@ -96,10 +96,7 @@
     if is_corefile():
         return tuple(coredump_maps())

-    proc_maps = None
-    if pwndbg.gdblib.qemu.is_qemu_usermode():
-        # On Qemu < 8.1 info proc maps are not supported. In that case we callback on proc_tid_maps
-        proc_maps = info_proc_maps()
+    proc_maps = info_proc_maps()

     if not proc_maps:
         proc_maps = proc_tid_maps()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants