|
3 | 3 | Remote debugging attachment protocol
|
4 | 4 | ====================================
|
5 | 5 |
|
| 6 | +This protocol enables external tools to attach to a running CPython process and |
| 7 | +execute Python code remotely. |
| 8 | + |
| 9 | +Most platforms require elevated privileges to attach to another Python process. |
| 10 | + |
| 11 | +.. _permission-requirements: |
| 12 | + |
| 13 | +Permission requirements |
| 14 | +======================= |
| 15 | + |
| 16 | +Attaching to a running Python process for remote debugging requires elevated |
| 17 | +privileges on most platforms. The specific requirements and troubleshooting |
| 18 | +steps depend on your operating system: |
| 19 | + |
| 20 | +..rubric::Linux |
| 21 | + |
| 22 | +The tracer process must have the ``CAP_SYS_PTRACE`` capability or equivalent |
| 23 | +privileges. You can only trace processes you own and can signal. Tracing may |
| 24 | +fail if the process is already being traced, or if it is running with |
| 25 | +set-user-ID or set-group-ID. Security modules like Yama may further restrict |
| 26 | +tracing. |
| 27 | + |
| 28 | +To temporarily relax ptrace restrictions (until reboot), run: |
| 29 | + |
| 30 | + ``echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope`` |
| 31 | + |
| 32 | +..note:: |
| 33 | + |
| 34 | + Disabling ``ptrace_scope`` reduces system hardening and should only be done |
| 35 | + in trusted environments. |
| 36 | + |
| 37 | +If running inside a container, use ``--cap-add=SYS_PTRACE`` or |
| 38 | +``--privileged``, and run as root if needed. |
| 39 | + |
| 40 | +Try re-running the command with elevated privileges: |
| 41 | + |
| 42 | + ``sudo -E !!`` |
| 43 | + |
| 44 | + |
| 45 | +..rubric::macOS |
| 46 | + |
| 47 | +To attach to another process, you typically need to run your debugging tool |
| 48 | +with elevated privileges. This can be done by using ``sudo`` or running as |
| 49 | +root. |
| 50 | + |
| 51 | +Even when attaching to processes you own, macOS may block debugging unless |
| 52 | +the debugger is run with root privileges due to system security restrictions. |
| 53 | + |
| 54 | + |
| 55 | +..rubric::Windows |
| 56 | + |
| 57 | +To attach to another process, you usually need to run your debugging tool |
| 58 | +with administrative privileges. Start the command prompt or terminal as |
| 59 | +Administrator. |
| 60 | + |
| 61 | +Some processes may still be inaccessible even with Administrator rights, |
| 62 | +unless you have the ``SeDebugPrivilege`` privilege enabled. |
| 63 | + |
| 64 | +To resolve file or folder access issues, adjust the security permissions: |
| 65 | + |
| 66 | + 1. Right-click the file or folder and select **Properties**. |
| 67 | + 2. Go to the **Security** tab to view users and groups with access. |
| 68 | + 3. Click **Edit** to modify permissions. |
| 69 | + 4. Select your user account. |
| 70 | + 5. In **Permissions**, check **Read** or **Full control** as needed. |
| 71 | + 6. Click **Apply**, then **OK** to confirm. |
| 72 | + |
| 73 | + |
| 74 | +..note:: |
| 75 | + |
| 76 | + Ensure you've satisfied all:ref:`permission-requirements` before proceeding. |
| 77 | + |
6 | 78 | This section describes the low-level protocol that enables external tools to
|
7 | 79 | inject and execute a Python script within a running CPython process.
|
8 | 80 |
|
@@ -374,13 +446,13 @@ To locate a thread:
|
374 | 446 | reliable thread to target.
|
375 | 447 |
|
376 | 448 | 3. Optionally, use the offset ``interpreter_state.threads_head`` to iterate
|
377 |
| -through the linked list of all thread states. Each ``PyThreadState`` structure |
378 |
| -contains a ``native_thread_id`` field, which may be compared to a target thread |
379 |
| -ID to find a specific thread. |
| 449 | +through the linked list of all thread states. Each ``PyThreadState`` |
| 450 | + structurecontains a ``native_thread_id`` field, which may be compared to |
| 451 | + a target threadID to find a specific thread. |
380 | 452 |
|
381 |
| -1. Once a valid ``PyThreadState`` has been found, its address can be used in |
382 |
| -later steps of the protocol, such as writing debugger control fields and |
383 |
| -scheduling execution. |
| 453 | +4. Once a valid ``PyThreadState`` has been found, its address can be used in |
| 454 | +later steps of the protocol, such as writing debugger control fields and |
| 455 | +scheduling execution. |
384 | 456 |
|
385 | 457 | The following is an example implementation that locates the main thread state::
|
386 | 458 |
|
@@ -454,15 +526,15 @@ its fields are defined by the ``_Py_DebugOffsets`` structure and include the
|
454 | 526 | following:
|
455 | 527 |
|
456 | 528 | - ``debugger_script_path``: A fixed-size buffer that holds the full path to a
|
457 |
| -Python source file (``.py``). This file must be accessible and readable by |
458 |
| -the target process when execution is triggered. |
| 529 | + Python source file (``.py``). This file must be accessible and readable by |
| 530 | + the target process when execution is triggered. |
459 | 531 |
|
460 | 532 | - ``debugger_pending_call``: An integer flag. Setting this to ``1`` tells the
|
461 |
| -interpreter that a script is ready to be executed. |
| 533 | + interpreter that a script is ready to be executed. |
462 | 534 |
|
463 | 535 | - ``eval_breaker``: A field checked by the interpreter during execution.
|
464 |
| -Setting bit 5 (``_PY_EVAL_PLEASE_STOP_BIT``, value ``1U << 5``) in this |
465 |
| -field causes the interpreter to pause and check for debugger activity. |
| 536 | + Setting bit 5 (``_PY_EVAL_PLEASE_STOP_BIT``, value ``1U << 5``) in this |
| 537 | + field causes the interpreter to pause and check for debugger activity. |
466 | 538 |
|
467 | 539 | To complete the injection, the debugger must perform the following steps:
|
468 | 540 |
|
|