[3.14] gh-134876: Add fallback for when process_vm_readv fails with ENOSYS (GH-134878) (#135240)

gh-134876: Add fallback for when process_vm_readv fails with ENOSYS (GH-134878)
(cherry picked from commit ac9c3431cc)

Co-authored-by: Daniel Golding <goldingd89@gmail.com>
This commit is contained in:
Miss Islington (bot) 2025-06-07 20:56:38 +02:00 committed by GitHub
parent 3faf00e003
commit ef539654e6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 112 additions and 0 deletions

View file

@ -24,6 +24,39 @@ read_memory(proc_handle_t *handle, uint64_t remote_address, size_t len, void* ds
return _Py_RemoteDebug_ReadRemoteMemory(handle, remote_address, len, dst);
}
// Why is pwritev not guarded? Except on Android API level 23 (no longer
// supported), HAVE_PROCESS_VM_READV is sufficient.
#if defined(__linux__) && HAVE_PROCESS_VM_READV
static int
write_memory_fallback(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src)
{
if (handle->memfd == -1) {
if (open_proc_mem_fd(handle) < 0) {
return -1;
}
}
struct iovec local[1];
Py_ssize_t result = 0;
Py_ssize_t written = 0;
do {
local[0].iov_base = (char*)src + result;
local[0].iov_len = len - result;
off_t offset = remote_address + result;
written = pwritev(handle->memfd, local, 1, offset);
if (written < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
result += written;
} while ((size_t)written != local[0].iov_len);
return 0;
}
#endif // __linux__
static int
write_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const void* src)
{
@ -39,6 +72,9 @@ write_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const
} while (result < len);
return 0;
#elif defined(__linux__) && HAVE_PROCESS_VM_READV
if (handle->memfd != -1) {
return write_memory_fallback(handle, remote_address, len, src);
}
struct iovec local[1];
struct iovec remote[1];
Py_ssize_t result = 0;
@ -52,6 +88,9 @@ write_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const
written = process_vm_writev(handle->pid, local, 1, remote, 1, 0);
if (written < 0) {
if (errno == ENOSYS) {
return write_memory_fallback(handle, remote_address, len, src);
}
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}