PEP 768: Add some minor changes to the APIs and some clarifications (#4162)
This commit is contained in:
parent
e4f3216938
commit
749797171e
|
@ -143,6 +143,12 @@ are **never accessed during normal execution**. The ``debugger_pending_call`` fi
|
||||||
indicates when a debugger has requested execution, while ``debugger_script``
|
indicates when a debugger has requested execution, while ``debugger_script``
|
||||||
provides Python code to be executed when the interpreter reaches a safe point.
|
provides Python code to be executed when the interpreter reaches a safe point.
|
||||||
|
|
||||||
|
The value for ``MAX_SCRIPT_SIZE`` will be a trade-off between binary size and
|
||||||
|
how big debugging scripts can be. As most of the logic should be in libraries
|
||||||
|
and arbitrary code can be executed with very short ammount of Python we are
|
||||||
|
proposing to start with 4kb initially. This value can be extended in the future
|
||||||
|
if we ever need to.
|
||||||
|
|
||||||
|
|
||||||
Debug Offsets Table
|
Debug Offsets Table
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -191,7 +197,8 @@ When a debugger wants to attach to a Python process, it follows these steps:
|
||||||
|
|
||||||
5. Write control information:
|
5. Write control information:
|
||||||
|
|
||||||
- Write python code to be executed into the ``debugger_script`` field in ``_PyRemoteDebuggerSupport``
|
- Write a string of Python code to be executed into the ``debugger_script``
|
||||||
|
field in ``_PyRemoteDebuggerSupport``.
|
||||||
- Set ``debugger_pending_call`` flag in ``_PyRemoteDebuggerSupport``
|
- Set ``debugger_pending_call`` flag in ``_PyRemoteDebuggerSupport``
|
||||||
- Set ``_PY_EVAL_PLEASE_STOP_BIT`` in the ``eval_breaker`` field
|
- Set ``_PY_EVAL_PLEASE_STOP_BIT`` in the ``eval_breaker`` field
|
||||||
|
|
||||||
|
@ -232,6 +239,11 @@ is checked.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
If the code being executed raises any Python exception it will be processed as
|
||||||
|
an `unraisable exception
|
||||||
|
<https://docs.python.org/3/c-api/exceptions.html#c.PyErr_WriteUnraisable>`__ in
|
||||||
|
the thread where the code was executed.
|
||||||
|
|
||||||
Python API
|
Python API
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -242,13 +254,16 @@ arbitrary Python code within the context of a specified Python process:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
def remote_exec(pid: int, code: str) -> None:
|
def remote_exec(pid: int, code: str, timeout: int = 0) -> None:
|
||||||
"""
|
"""
|
||||||
Executes a block of Python code in a given remote Python process.
|
Executes a block of Python code in a given remote Python process.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
pid (int): The process ID of the target Python process.
|
pid (int): The process ID of the target Python process.
|
||||||
code (str): A string containing the Python code to be executed.
|
code (str): A string containing the Python code to be executed.
|
||||||
|
timeout (int): An optional timeout for waiting for the remote
|
||||||
|
process to execute the code. If the timeout is exceeded a
|
||||||
|
``TimeoutError`` will be raised.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
An example usage of the API would look like:
|
An example usage of the API would look like:
|
||||||
|
@ -258,7 +273,9 @@ An example usage of the API would look like:
|
||||||
import sys
|
import sys
|
||||||
# Execute a print statement in a remote Python process with PID 12345
|
# Execute a print statement in a remote Python process with PID 12345
|
||||||
try:
|
try:
|
||||||
sys.remote_exec(12345, "print('Hello from remote execution!')")
|
sys.remote_exec(12345, "print('Hello from remote execution!')", timeout=3)
|
||||||
|
except TimeoutError:
|
||||||
|
print(f"The remote process took too long to execute the code")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to execute code: {e}")
|
print(f"Failed to execute code: {e}")
|
||||||
|
|
||||||
|
@ -270,7 +287,6 @@ This change has no impact on existing Python code or interpreter performance.
|
||||||
The added fields are only accessed during debugger attachment, and the checking
|
The added fields are only accessed during debugger attachment, and the checking
|
||||||
mechanism piggybacks on existing interpreter safe points.
|
mechanism piggybacks on existing interpreter safe points.
|
||||||
|
|
||||||
|
|
||||||
Security Implications
|
Security Implications
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
@ -280,23 +296,26 @@ the PEP doesn't specify how memory should be written to the target process, in p
|
||||||
this will be done using standard system calls that are already being used by other
|
this will be done using standard system calls that are already being used by other
|
||||||
debuggers and tools. Some examples are:
|
debuggers and tools. Some examples are:
|
||||||
|
|
||||||
* On Linux, the ``process_vm_readv()`` and ``process_vm_writev()`` system calls
|
* On Linux, the `process_vm_readv() <https://man7.org/linux/man-pages/man2/process_vm_readv.2.html>`__
|
||||||
|
and `process_vm_writev() <https://man7.org/linux/man-pages/man2/process_vm_writev.2.html>`__ system calls
|
||||||
are used to read and write memory from another process. These operations are
|
are used to read and write memory from another process. These operations are
|
||||||
controlled by ptrace access mode checks - the same ones that govern debugger
|
controlled by `ptrace <https://man7.org/linux/man-pages/man2/ptrace.2.html>`__ access mode
|
||||||
attachment. A process can only read from or write to another process's memory
|
checks - the same ones that govern debugger attachment. A process can only read from
|
||||||
if it has the appropriate permissions (typically requiring either root or the
|
or write to another process's memory if it has the appropriate permissions (typically
|
||||||
``CAP_SYS_PTRACE`` capability, though less security minded distributions may
|
requiring either root or the `CAP_SYS_PTRACE <https://man7.org/linux/man-pages/man7/capabilities.7.html>`__
|
||||||
allow any process running as the same uid to attach).
|
capability, though less security minded distributions may allow any process running as the same uid to attach).
|
||||||
|
|
||||||
* On macOS, the interface would leverage ``mach_vm_read_overwrite()`` and
|
* On macOS, the interface would leverage `mach_vm_read_overwrite() <https://developer.apple.com/documentation/kernel/1402127-mach_vm_read_overwrite>`__ and
|
||||||
``mach_vm_write()`` through the Mach task system. These operations require
|
`mach_vm_write() <https://developer.apple.com/documentation/kernel/1402070-mach_vm_write>`__ through the Mach task system. These operations require
|
||||||
``task_for_pid()`` access, which is strictly controlled by the operating
|
``task_for_pid()`` access, which is strictly controlled by the operating
|
||||||
system. By default, access is limited to processes running as root or those
|
system. By default, access is limited to processes running as root or those
|
||||||
with specific entitlements granted by Apple's security framework.
|
with specific entitlements granted by Apple's security framework.
|
||||||
|
|
||||||
* On Windows, the ``ReadProcessMemory()`` and ``WriteProcessMemory()`` functions
|
* On Windows, the `ReadProcessMemory() <https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory>`__
|
||||||
|
and `WriteProcessMemory() <https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory>`__ functions
|
||||||
provide similar functionality. Access is controlled through the Windows
|
provide similar functionality. Access is controlled through the Windows
|
||||||
security model - a process needs ``PROCESS_VM_READ`` and ``PROCESS_VM_WRITE``
|
security model - a process needs `PROCESS_VM_READ <https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights>`__
|
||||||
|
and `PROCESS_VM_WRITE <https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights>`__
|
||||||
permissions, which typically require the same user context or appropriate
|
permissions, which typically require the same user context or appropriate
|
||||||
privileges. These are the same permissions required by debuggers, ensuring
|
privileges. These are the same permissions required by debuggers, ensuring
|
||||||
consistent security semantics across platforms.
|
consistent security semantics across platforms.
|
||||||
|
@ -310,7 +329,7 @@ All mechanisms ensure that:
|
||||||
The memory operations themselves are well-established and have been used safely
|
The memory operations themselves are well-established and have been used safely
|
||||||
for decades in tools like GDB, LLDB, and various system profilers.
|
for decades in tools like GDB, LLDB, and various system profilers.
|
||||||
|
|
||||||
It’s important to note that any attempt to attach to a Python process via this
|
It's important to note that any attempt to attach to a Python process via this
|
||||||
mechanism would be detectable by system-level monitoring tools. This
|
mechanism would be detectable by system-level monitoring tools. This
|
||||||
transparency provides an additional layer of accountability, allowing
|
transparency provides an additional layer of accountability, allowing
|
||||||
administrators to audit debugging operations in sensitive environments.
|
administrators to audit debugging operations in sensitive environments.
|
||||||
|
@ -319,12 +338,12 @@ Further, the strict reliance on OS-level security controls ensures that existing
|
||||||
system policies remain effective. For enterprise environments, this means
|
system policies remain effective. For enterprise environments, this means
|
||||||
administrators can continue to enforce debugging restrictions using standard
|
administrators can continue to enforce debugging restrictions using standard
|
||||||
tools and policies without requiring additional configuration. For instance,
|
tools and policies without requiring additional configuration. For instance,
|
||||||
leveraging Linux’s ``ptrace_scope`` or macOS’s ``taskgated`` to restrict
|
leveraging Linux's `ptrace_scope <https://www.kernel.org/doc/Documentation/security/Yama.txt>`__
|
||||||
debugger access will equally govern the proposed interface.
|
or macOS's ``taskgated`` to restrict debugger access will equally govern the
|
||||||
|
proposed interface.
|
||||||
|
|
||||||
By maintaining compatibility with existing security frameworks, this design
|
By maintaining compatibility with existing security frameworks, this design
|
||||||
ensures that adopting the new interface requires no changes to established
|
ensures that adopting the new interface requires no changes to established
|
||||||
security practices, thereby minimizing barriers to adoption.
|
|
||||||
|
|
||||||
How to Teach This
|
How to Teach This
|
||||||
=================
|
=================
|
||||||
|
@ -341,7 +360,30 @@ debugging tool stability and reliability.
|
||||||
Reference Implementation
|
Reference Implementation
|
||||||
========================
|
========================
|
||||||
|
|
||||||
https://github.com/pablogsal/cpython/commits/remote_pdb/
|
A reference implementation with a prototype adding remote support for ``pdb``
|
||||||
|
can be found `here
|
||||||
|
<https://github.com/pablogsal/cpython/compare/60ff67d010078eca15a74b1429caf779ac4f9c74...remote_pdb>`__.
|
||||||
|
|
||||||
|
Rejected Ideas
|
||||||
|
==============
|
||||||
|
|
||||||
|
Using a path as the debugger input
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
We have selected that the mechanism for executing remote code is that tools
|
||||||
|
write the code directly in the remote process to eliminate a possible security
|
||||||
|
vulnerability in which the file to be executed can be altered by parties other
|
||||||
|
than the debugger process if permissions are not set correctly or filesystem
|
||||||
|
configurations allow for this to happen. It is also trivial to write code that
|
||||||
|
executes the contents of a file so the current mechanism doesn't disallow tools
|
||||||
|
that want to just execute files to just do so if they are ok with the security
|
||||||
|
profile of such operation.
|
||||||
|
|
||||||
|
Thanks
|
||||||
|
======
|
||||||
|
|
||||||
|
We would like to thank Carl Friedrich Bolz-Tereick for his insightful comments and suggestions
|
||||||
|
when discussing this proposal.
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
|
|
Loading…
Reference in New Issue