Skip to content

Commit

Permalink
Complete reads and writes in ProcessVMTransfer.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
asteinha authored and copybara-github committed Jun 3, 2024
1 parent af41311 commit ad5c5cf
Showing 1 changed file with 26 additions and 13 deletions.
39 changes: 26 additions & 13 deletions sandboxed_api/sandbox2/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -423,20 +423,33 @@ absl::StatusOr<size_t> ProcessVmTransfer(bool is_read, pid_t pid, uintptr_t ptr,
return 0;
}

iovec local_iov = {data.data(), data.size()};
iovec remote_iov = {reinterpret_cast<void*>(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<void*>(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.
Expand Down

0 comments on commit ad5c5cf

Please sign in to comment.