Skip to content

Commit 419441a

Browse files
Improve permission error messages in pdb and asyncio.tools (#134290)
1 parent adb4140 commit 419441a

File tree

4 files changed

+109
-1
lines changed

4 files changed

+109
-1
lines changed

Doc/howto/remote_debugging.rst

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,78 @@
33
Remote debugging attachment protocol
44
====================================
55

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+
678
This section describes the low-level protocol that enables external tools to
779
inject and execute a Python script within a running CPython process.
880

Lib/asyncio/tools.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,20 @@ def _print_cycle_exception(exception: CycleFoundException):
222222
print(f"cycle: {inames}", file=sys.stderr)
223223

224224

225+
def exit_with_permission_help_text():
226+
"""
227+
Prints a message pointing to platform-specific permission help text and exits the program.
228+
This function is called when a PermissionError is encountered while trying
229+
to attach to a process.
230+
"""
231+
print(
232+
"Error: The specified process cannot be attached to due to insufficient permissions.\n"
233+
"See the Python documentation for details on required privileges and troubleshooting:\n"
234+
"https://docs.python.org/3.14/howto/remote_debugging.html#permission-requirements\n"
235+
)
236+
sys.exit(1)
237+
238+
225239
def _get_awaited_by_tasks(pid: int) -> list:
226240
try:
227241
return get_all_awaited_by(pid)
@@ -230,6 +244,8 @@ def _get_awaited_by_tasks(pid: int) -> list:
230244
e = e.__context__
231245
print(f"Error retrieving tasks: {e}")
232246
sys.exit(1)
247+
except PermissionError as e:
248+
exit_with_permission_help_text()
233249

234250

235251
def display_awaited_by_tasks_table(pid: int) -> None:

Lib/pdb.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3504,6 +3504,20 @@ def help():
35043504
"-c 'until X'"."""
35053505

35063506

3507+
def exit_with_permission_help_text():
3508+
"""
3509+
Prints a message pointing to platform-specific permission help text and exits the program.
3510+
This function is called when a PermissionError is encountered while trying
3511+
to attach to a process.
3512+
"""
3513+
print(
3514+
"Error: The specified process cannot be attached to due to insufficient permissions.\n"
3515+
"See the Python documentation for details on required privileges and troubleshooting:\n"
3516+
"https://docs.python.org/3.14/howto/remote_debugging.html#permission-requirements\n"
3517+
)
3518+
sys.exit(1)
3519+
3520+
35073521
def main():
35083522
import argparse
35093523

@@ -3537,7 +3551,10 @@ def main():
35373551
opts = parser.parse_args()
35383552
if opts.module:
35393553
parser.error("argument -m: not allowed with argument --pid")
3540-
attach(opts.pid, opts.commands)
3554+
try:
3555+
attach(opts.pid, opts.commands)
3556+
except PermissionError as e:
3557+
exit_with_permission_help_text()
35413558
return
35423559
elif opts.module:
35433560
# If a module is being debugged, we consider the arguments after "-m module" to

Lib/test/test_remote_pdb.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,9 @@ def do_integration_test(self, client_stdin):
15391539
redirect_stdout(client_stdout),
15401540
redirect_stderr(client_stderr),
15411541
unittest.mock.patch("sys.argv", ["pdb", "-p", str(process.pid)]),
1542+
unittest.mock.patch(
1543+
"pdb.exit_with_permission_help_text", side_effect=PermissionError
1544+
),
15421545
):
15431546
try:
15441547
pdb.main()

0 commit comments

Comments
 (0)