From 3cbd871454dd9d22376c91162952e51dedbf9896 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Fri, 22 Nov 2019 06:59:37 -0800 Subject: [PATCH] Allow sandboxee c-strings to be read as std::string PiperOrigin-RevId: 281960106 Change-Id: I54256dda2b6b0374d0f2ce3f762370478b912683 --- .../examples/stringop/main_stringop.cc | 14 +++++++ sandboxed_api/sandbox.cc | 37 +++++++++++++++++++ sandboxed_api/sandbox.h | 4 ++ 3 files changed, 55 insertions(+) diff --git a/sandboxed_api/examples/stringop/main_stringop.cc b/sandboxed_api/examples/stringop/main_stringop.cc index 27728e1..bf4348d 100644 --- a/sandboxed_api/examples/stringop/main_stringop.cc +++ b/sandboxed_api/examples/stringop/main_stringop.cc @@ -140,4 +140,18 @@ TEST(StringopTest, RawStringLength) { EXPECT_THAT(len, Eq(10)); } +TEST(StringopTest, RawStringReading) { + StringopSapiSandbox sandbox; + ASSERT_THAT(sandbox.Init(), IsOk()); + StringopApi api(&sandbox); + SAPI_ASSERT_OK_AND_ASSIGN(void* target_mem_ptr, api.get_raw_c_string()); + SAPI_ASSERT_OK_AND_ASSIGN(uint64_t len, + sandbox.GetRpcChannel()->Strlen(target_mem_ptr)); + EXPECT_THAT(len, Eq(10)); + + SAPI_ASSERT_OK_AND_ASSIGN(std::string data, + sandbox.GetCString(sapi::v::RemotePtr(target_mem_ptr))); + EXPECT_THAT(data, StrEq("Ten chars.")); +} + } // namespace diff --git a/sandboxed_api/sandbox.cc b/sandboxed_api/sandbox.cc index 2eaab90..6485d7f 100644 --- a/sandboxed_api/sandbox.cc +++ b/sandboxed_api/sandbox.cc @@ -391,6 +391,43 @@ sapi::Status Sandbox::TransferFromSandboxee(v::Var* var) { return var->TransferFromSandboxee(GetRpcChannel(), GetPid()); } +sapi::StatusOr Sandbox::GetCString(const v::RemotePtr& str, + uint64_t max_length) { + if (!IsActive()) { + return sapi::UnavailableError("Sandbox not active"); + } + + SAPI_ASSIGN_OR_RETURN(auto len, GetRpcChannel()->Strlen(str.GetValue())); + if (len > max_length) { + return sapi::InvalidArgumentError( + absl::StrCat("Target string too large: ", len, " > ", max_length)); + } + std::string buffer(len, '\0'); + struct iovec local = { + .iov_base = &buffer[0], + .iov_len = len, + }; + struct iovec remote = { + .iov_base = str.GetValue(), + .iov_len = len, + }; + + ssize_t ret = process_vm_readv(pid_, &local, 1, &remote, 1, 0); + if (ret == -1) { + PLOG(WARNING) << "reading c-string failed: process_vm_readv(pid: " << pid_ + << " raddr: " << str.GetValue() << " size: " << len << ")"; + return sapi::UnavailableError("process_vm_readv failed"); + } + if (ret != len) { + LOG(WARNING) << "partial read when reading c-string: process_vm_readv(pid: " + << pid_ << " raddr: " << str.GetValue() << " size: " << len + << ") transferred " << ret << " bytes"; + return sapi::UnavailableError("process_vm_readv succeeded partially"); + } + + return buffer; +} + const sandbox2::Result& Sandbox::AwaitResult() { if (s2_) { result_ = s2_->AwaitResult(); diff --git a/sandboxed_api/sandbox.h b/sandboxed_api/sandbox.h index 70ed2f5..b068e87 100644 --- a/sandboxed_api/sandbox.h +++ b/sandboxed_api/sandbox.h @@ -95,6 +95,10 @@ class Sandbox { sapi::Status TransferToSandboxee(v::Var* var); sapi::Status TransferFromSandboxee(v::Var* var); + sapi::StatusOr GetCString(const v::RemotePtr& str, + uint64_t max_length = 10 * 1024 * + 1024); + // Waits until the sandbox terminated and returns the result. const sandbox2::Result& AwaitResult(); const sandbox2::Result& result() const { return result_; }