]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] Improve permission error messages in pdb and asyncio.tools (GH-134290) (#138826)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 12 Sep 2025 12:20:20 +0000 (14:20 +0200)
committerGitHub <noreply@github.com>
Fri, 12 Sep 2025 12:20:20 +0000 (12:20 +0000)
Improve permission error messages in pdb and asyncio.tools (GH-134290)
(cherry picked from commit 419441a6e14aa9e0ebd2484ee8e76d3c544a3c09)

Co-authored-by: ivonastojanovic <80911834+ivonastojanovic@users.noreply.github.com>
Doc/howto/remote_debugging.rst
Lib/asyncio/tools.py
Lib/pdb.py
Lib/test/test_remote_pdb.py

index b7323803654628e99369722f589d8852f73bece7..78b40bcdf7127b21a8300313c3f7599ba82b4a0f 100644 (file)
@@ -3,6 +3,78 @@
 Remote debugging attachment protocol
 ====================================
 
+This protocol enables external tools to attach to a running CPython process and
+execute Python code remotely.
+
+Most platforms require elevated privileges to attach to another Python process.
+
+.. _permission-requirements:
+
+Permission requirements
+=======================
+
+Attaching to a running Python process for remote debugging requires elevated
+privileges on most platforms. The specific requirements and troubleshooting
+steps depend on your operating system:
+
+.. rubric:: Linux
+
+The tracer process must have the ``CAP_SYS_PTRACE`` capability or equivalent
+privileges. You can only trace processes you own and can signal. Tracing may
+fail if the process is already being traced, or if it is running with
+set-user-ID or set-group-ID. Security modules like Yama may further restrict
+tracing.
+
+To temporarily relax ptrace restrictions (until reboot), run:
+
+  ``echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope``
+
+.. note::
+
+   Disabling ``ptrace_scope`` reduces system hardening and should only be done
+   in trusted environments.
+
+If running inside a container, use ``--cap-add=SYS_PTRACE`` or
+``--privileged``, and run as root if needed.
+
+Try re-running the command with elevated privileges:
+
+  ``sudo -E !!``
+
+
+.. rubric:: macOS
+
+To attach to another process, you typically need to run your debugging tool
+with elevated privileges. This can be done by using ``sudo`` or running as
+root.
+
+Even when attaching to processes you own, macOS may block debugging unless
+the debugger is run with root privileges due to system security restrictions.
+
+
+.. rubric:: Windows
+
+To attach to another process, you usually need to run your debugging tool
+with administrative privileges. Start the command prompt or terminal as
+Administrator.
+
+Some processes may still be inaccessible even with Administrator rights,
+unless you have the ``SeDebugPrivilege`` privilege enabled.
+
+To resolve file or folder access issues, adjust the security permissions:
+
+  1. Right-click the file or folder and select **Properties**.
+  2. Go to the **Security** tab to view users and groups with access.
+  3. Click **Edit** to modify permissions.
+  4. Select your user account.
+  5. In **Permissions**, check **Read** or **Full control** as needed.
+  6. Click **Apply**, then **OK** to confirm.
+
+
+.. note::
+
+   Ensure you've satisfied all :ref:`permission-requirements` before proceeding.
+
 This section describes the low-level protocol that enables external tools to
 inject and execute a Python script within a running CPython process.
 
index 2683f34cc7113b573286b43280e4cd52df5a01bf..f39e11fdd513b4d61c3b9cec0f8728310c414766 100644 (file)
@@ -222,6 +222,20 @@ def _print_cycle_exception(exception: CycleFoundException):
         print(f"cycle: {inames}", file=sys.stderr)
 
 
+def exit_with_permission_help_text():
+    """
+    Prints a message pointing to platform-specific permission help text and exits the program.
+    This function is called when a PermissionError is encountered while trying
+    to attach to a process.
+    """
+    print(
+        "Error: The specified process cannot be attached to due to insufficient permissions.\n"
+        "See the Python documentation for details on required privileges and troubleshooting:\n"
+        "https://docs.python.org/3.14/howto/remote_debugging.html#permission-requirements\n"
+    )
+    sys.exit(1)
+
+
 def _get_awaited_by_tasks(pid: int) -> list:
     try:
         return get_all_awaited_by(pid)
@@ -230,6 +244,8 @@ def _get_awaited_by_tasks(pid: int) -> list:
             e = e.__context__
         print(f"Error retrieving tasks: {e}")
         sys.exit(1)
+    except PermissionError as e:
+        exit_with_permission_help_text()
 
 
 def display_awaited_by_tasks_table(pid: int) -> None:
index c8c3134d3eb72136f0a440a986cc50a6663dcad7..2d7da2f82bea813bafe31b0969d5f06530aec766 100644 (file)
@@ -3505,6 +3505,20 @@ To let the script run up to a given line X in the debugged file, use
 "-c 'until X'"."""
 
 
+def exit_with_permission_help_text():
+    """
+    Prints a message pointing to platform-specific permission help text and exits the program.
+    This function is called when a PermissionError is encountered while trying
+    to attach to a process.
+    """
+    print(
+        "Error: The specified process cannot be attached to due to insufficient permissions.\n"
+        "See the Python documentation for details on required privileges and troubleshooting:\n"
+        "https://docs.python.org/3.14/howto/remote_debugging.html#permission-requirements\n"
+    )
+    sys.exit(1)
+
+
 def main():
     import argparse
 
@@ -3538,7 +3552,10 @@ def main():
         opts = parser.parse_args()
         if opts.module:
             parser.error("argument -m: not allowed with argument --pid")
-        attach(opts.pid, opts.commands)
+        try:
+            attach(opts.pid, opts.commands)
+        except PermissionError as e:
+            exit_with_permission_help_text()
         return
     elif opts.module:
         # If a module is being debugged, we consider the arguments after "-m module" to
index 280e2444ef7d34b2fd307bd95772b6a4d4a1cf79..ec11e41678849bcfd44b25494d4dd272401c9a90 100644 (file)
@@ -1539,6 +1539,9 @@ class PdbAttachTestCase(unittest.TestCase):
             redirect_stdout(client_stdout),
             redirect_stderr(client_stderr),
             unittest.mock.patch("sys.argv", ["pdb", "-p", str(process.pid)]),
+            unittest.mock.patch(
+                "pdb.exit_with_permission_help_text", side_effect=PermissionError
+            ),
         ):
             try:
                 pdb.main()