From ad5c5cfc1182a739a84a511ec033c81b4bfedafb Mon Sep 17 00:00:00 2001 From: Anthony Steinhauser Date: Mon, 3 Jun 2024 14:57:40 -0700 Subject: [PATCH] Complete reads and writes in ProcessVMTransfer. process_vm_readv/writev should not split accross iovec elements, but Linux has a limit of 0x7ffff000 on any read/write and the size of any single iovec is capped at that number. Therefore try to read or write in a loop instead of aborting when process_vm_readv/process_vm_writev returns a partial success. PiperOrigin-RevId: 639921713 Change-Id: I853095874222a88bea10a9d9b074a7240a919b94 --- sandboxed_api/sandbox2/util.cc | 39 ++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/sandboxed_api/sandbox2/util.cc b/sandboxed_api/sandbox2/util.cc index d85c938b..e42a70c3 100644 --- a/sandboxed_api/sandbox2/util.cc +++ b/sandboxed_api/sandbox2/util.cc @@ -423,20 +423,33 @@ absl::StatusOr ProcessVmTransfer(bool is_read, pid_t pid, uintptr_t ptr, return 0; } - iovec local_iov = {data.data(), data.size()}; - iovec remote_iov = {reinterpret_cast(ptr), data.size()}; - ssize_t bytes_transferred = - is_read ? process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) - : process_vm_writev(pid, &local_iov, 1, &remote_iov, 1, 0); - if (bytes_transferred == 0) { - return absl::NotFoundError(absl::StrFormat( - "Transfer was unsuccessful for PID: %d at address: %#x", pid, ptr)); - } else if (bytes_transferred < 0) { - return absl::ErrnoToStatus( - errno, absl::StrFormat("transfer() failed for PID: %d at address: %#x", - pid, ptr)); + size_t total_bytes_transferred = 0; + while (!data.empty()) { + iovec local_iov = {data.data(), data.size()}; + iovec remote_iov = {reinterpret_cast(ptr), data.size()}; + ssize_t bytes_transferred = + is_read ? process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) + : process_vm_writev(pid, &local_iov, 1, &remote_iov, 1, 0); + if (bytes_transferred == 0) { + if (total_bytes_transferred > 0) { + return total_bytes_transferred; + } + return absl::NotFoundError(absl::StrFormat( + "Transfer was unsuccessful for PID: %d at address: %#x", pid, ptr)); + } else if (bytes_transferred < 0) { + if (total_bytes_transferred > 0) { + return total_bytes_transferred; + } + return absl::ErrnoToStatus( + errno, + absl::StrFormat("transfer() failed for PID: %d at address: %#x", pid, + ptr)); + } + ptr += bytes_transferred; + data = data.subspan(bytes_transferred, data.size() - bytes_transferred); + total_bytes_transferred += bytes_transferred; } - return bytes_transferred; + return total_bytes_transferred; } // Transfer memory via process_vm_readv.