Skip to content

_remote_debugging: incorrect error for process_vm_readv() w/ EPERM when detecting the cookie #149619

@maurycy

Description

@maurycy

Bug report

Bug description:

Note Failed to find the PyRuntime section in process 175853 on Linux platform here:

2026-05-09T21:00:48.747402752+0000 ubuntu@f4-metal-medium-lon-1 /home/ubuntu/cpython (main 7241f27) % sudo sysctl -w kernel.yama.ptrace_scope=1
kernel.yama.ptrace_scope = 1
2026-05-09T21:00:49.153189782+0000 ubuntu@f4-metal-medium-lon-1 /home/ubuntu/cpython (main 7241f27) % ./python -c "import time; time.sleep(60)" &
[1] 175853
2026-05-09T21:00:51.504230609+0000 ubuntu@f4-metal-medium-lon-1 /home/ubuntu/cpython (main 7241f27) % ./python -m profiling.sampling attach $!
Failed to find the PyRuntime section in process 175853 on Linux platform
[1] 2026-05-09T21:00:54.515838389+0000 ubuntu@f4-metal-medium-lon-1 /home/ubuntu/cpython (main 7241f27) % sudo sysctl -w kernel.yama.ptrace_scope=0
kernel.yama.ptrace_scope = 0
2026-05-09T21:00:57.313995182+0000 ubuntu@f4-metal-medium-lon-1 /home/ubuntu/cpython (main 7241f27) % ./python -c "import time; time.sleep(60)" &
[2] 175951
2026-05-09T21:00:59.679641859+0000 ubuntu@f4-metal-medium-lon-1 /home/ubuntu/cpython (main 7241f27) % ./python -m profiling.sampling attach $!
[1]  - done       ./python -c "import time; time.sleep(60)"
Captured 57,731 samples in 57.73 seconds
Sample rate: 1,000.00 samples/sec
Error rate: 0.00
[2]  + done       ./python -c "import time; time.sleep(60)"
Profile Stats:
       nsamples   sample%   tottime (s)    cumul%   cumtime (s)  filename:lineno(function)
    57729/57729     100.0        57.729     100.0        57.729  <string>:1(<module>)

Legend:
  nsamples: Direct/Cumulative samples (direct executing / on call stack)
  sample%: Percentage of total samples this function was directly executing
  tottime: Estimated total time spent directly in this function
  cumul%: Percentage of total samples when this function was on the call stack
  cumtime: Estimated cumulative time (including time in called functions)
  filename:lineno(function): Function location and name

Summary of Interesting Functions:

Functions with Highest Direct/Cumulative Ratio (Hot Spots):
  1.000 direct/cumulative ratio, 100.0% direct samples: <string>:(<module>)

Functions with Highest Call Frequency (Indirect Calls):

Functions with Highest Call Magnification (Cumulative/Direct):
2026-05-09T21:01:59.697134414+0000 ubuntu@f4-metal-medium-lon-1 /home/ubuntu/cpython (main 7241f27) % 

The wrapper handles PermissionError well:

if __name__ == '__main__':
try:
main()
except PermissionError:
handle_permission_error()

def handle_permission_error():
"""Handle PermissionError by displaying appropriate error message."""
if sys.platform == "darwin":
print(MACOS_PERMISSION_ERROR, file=sys.stderr)
elif sys.platform.startswith("linux"):
print(LINUX_PERMISSION_ERROR, file=sys.stderr)
elif sys.platform.startswith("win"):
print(WINDOWS_PERMISSION_ERROR, file=sys.stderr)
else:
print(GENERIC_PERMISSION_ERROR, file=sys.stderr)
sys.exit(1)

LINUX_PERMISSION_ERROR = """
🔒 Tachyon was unable to access process memory. This could be because tachyon
has insufficient privileges (the required capability is CAP_SYS_PTRACE).
Unprivileged processes cannot trace processes that they cannot send signals
to or those running set-user-ID/set-group-ID programs, for security reasons.
If your uid matches the uid of the target process you want to analyze, you
can do one of the following to get 'ptrace' scope permissions:
* If you are running inside a Docker container, you need to make sure you
start the container using the '--cap-add=SYS_PTRACE' or '--privileged'
command line arguments. Notice that this may not be enough if you are not
running as 'root' inside the Docker container as you may need to disable
hardening (see next points).
* Try running again with elevated permissions by running 'sudo -E !!'.
* You can disable kernel hardening for the current session temporarily (until
a reboot happens) by running 'echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope'.
"""

but it's swallowed as RuntimeError:

#elif defined(__linux__) && HAVE_PROCESS_VM_READV
// On Linux, search for 'python' in executable or DLL
address = search_linux_map_for_section(handle, "PyRuntime", "python",
_Py_RemoteDebug_ValidatePyRuntimeCookie);
if (address == 0) {
// Error out: 'python' substring covers both executable and DLL
PyObject *exc = PyErr_GetRaisedException();
PyErr_Format(PyExc_RuntimeError,
"Failed to find the PyRuntime section in process %d on Linux platform",
handle->pid);
_PyErr_ChainExceptions1(exc);
}

The error bubbles out of

static int
_Py_RemoteDebug_ValidatePyRuntimeCookie(proc_handle_t *handle, uintptr_t address)
{
if (address == 0) {
return 0;
}
char buf[sizeof(_Py_Debug_Cookie) - 1];
if (_Py_RemoteDebug_ReadRemoteMemory(handle, address, sizeof(buf), buf) != 0) {
PyErr_Clear();
return 0;
}
return memcmp(buf, _Py_Debug_Cookie, sizeof(buf)) == 0;
}

hence such a cookie panic

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Metadata

Metadata

Labels

interpreter-core(Objects, Python, Grammar, and Parser dirs)topic-profilingtype-bugAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions