• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Implementation of sapi::v::Var
16 
17 #include "sandboxed_api/var_abstract.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <memory>
22 #include <utility>
23 
24 #include "absl/log/log.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/types/span.h"
28 #include "sandboxed_api/rpcchannel.h"
29 #include "sandboxed_api/sandbox2/util.h"
30 #include "sandboxed_api/util/status_macros.h"
31 #include "sandboxed_api/var_ptr.h"
32 
33 namespace sapi::v {
34 
operator =(Var && other)35 Var& Var::operator=(Var&& other) {
36   if (this != &other) {
37     using std::swap;
38     swap(local_, other.local_);
39     swap(remote_, other.remote_);
40     swap(free_rpc_channel_, other.free_rpc_channel_);
41     swap(ptr_none_, other.ptr_none_);
42     swap(ptr_both_, other.ptr_both_);
43     swap(ptr_before_, other.ptr_before_);
44     swap(ptr_after_, other.ptr_after_);
45   }
46   return *this;
47 }
48 
~Var()49 Var::~Var() {
50   if (free_rpc_channel_ && GetRemote()) {
51     this->Free(free_rpc_channel_).IgnoreError();
52   }
53 }
54 
operator ()(Ptr * p)55 void Var::PtrDeleter::operator()(Ptr* p) { delete p; }
56 
PtrNone()57 Ptr* Var::PtrNone() {
58   if (!ptr_none_) {
59     ptr_none_.reset(new Ptr(this, kSyncNone));
60   }
61   return ptr_none_.get();
62 }
63 
PtrBoth()64 Ptr* Var::PtrBoth() {
65   if (!ptr_both_) {
66     ptr_both_.reset(new Ptr(this, kSyncBoth));
67   }
68   return ptr_both_.get();
69 }
70 
PtrBefore()71 Ptr* Var::PtrBefore() {
72   if (!ptr_before_) {
73     ptr_before_.reset(new Ptr(this, kSyncBefore));
74   }
75   return ptr_before_.get();
76 }
77 
PtrAfter()78 Ptr* Var::PtrAfter() {
79   if (!ptr_after_) {
80     ptr_after_.reset(new Ptr(this, kSyncAfter));
81   }
82   return ptr_after_.get();
83 }
84 
Allocate(RPCChannel * rpc_channel,bool automatic_free)85 absl::Status Var::Allocate(RPCChannel* rpc_channel, bool automatic_free) {
86   void* addr;
87   SAPI_RETURN_IF_ERROR(rpc_channel->Allocate(GetSize(), &addr));
88 
89   if (!addr) {
90     LOG(ERROR) << "Allocate: returned nullptr";
91     return absl::UnavailableError("Allocating memory failed");
92   }
93 
94   SetRemote(addr);
95   if (automatic_free) {
96     SetFreeRPCChannel(rpc_channel);
97   }
98 
99   return absl::OkStatus();
100 }
101 
Free(RPCChannel * rpc_channel)102 absl::Status Var::Free(RPCChannel* rpc_channel) {
103   SAPI_RETURN_IF_ERROR(rpc_channel->Free(GetRemote()));
104 
105   SetRemote(nullptr);
106   return absl::OkStatus();
107 }
108 
TransferToSandboxee(RPCChannel * rpc_channel,pid_t pid)109 absl::Status Var::TransferToSandboxee(RPCChannel* rpc_channel, pid_t pid) {
110   VLOG(3) << "TransferToSandboxee for: " << ToString()
111           << ", local: " << GetLocal() << ", remote: " << GetRemote()
112           << ", size: " << GetSize();
113 
114   if (remote_ == nullptr) {
115     LOG(WARNING) << "Object: " << GetTypeString()
116                  << " has no remote object set";
117     return absl::FailedPreconditionError(
118         absl::StrCat("Object: ", GetTypeString(), " has no remote object set"));
119   }
120 
121   SAPI_ASSIGN_OR_RETURN(
122       size_t ret,
123       sandbox2::util::WriteBytesToPidFrom(
124           pid, reinterpret_cast<uintptr_t>(GetRemote()),
125           absl::MakeSpan(reinterpret_cast<char*>(GetLocal()), GetSize())));
126 
127   if (ret != GetSize()) {
128     LOG(WARNING) << "process_vm_writev(pid: " << pid << " laddr: " << GetLocal()
129                  << " raddr: " << GetRemote() << " size: " << GetSize() << ")"
130                  << " transferred " << ret << " bytes";
131     return absl::UnavailableError("process_vm_writev: partial success");
132   }
133 
134   return absl::OkStatus();
135 }
136 
TransferFromSandboxee(RPCChannel * rpc_channel,pid_t pid)137 absl::Status Var::TransferFromSandboxee(RPCChannel* rpc_channel, pid_t pid) {
138   VLOG(3) << "TransferFromSandboxee for: " << ToString()
139           << ", local: " << GetLocal() << ", remote: " << GetRemote()
140           << ", size: " << GetSize();
141 
142   if (local_ == nullptr) {
143     return absl::FailedPreconditionError(
144         absl::StrCat("Object: ", GetTypeString(), " has no local storage set"));
145   }
146 
147   SAPI_ASSIGN_OR_RETURN(
148       size_t ret,
149       sandbox2::util::ReadBytesFromPidInto(
150           pid, reinterpret_cast<uintptr_t>(GetRemote()),
151           absl::MakeSpan(reinterpret_cast<char*>(GetLocal()), GetSize())));
152   if (ret != GetSize()) {
153     LOG(WARNING) << "process_vm_readv(pid: " << pid << " laddr: " << GetLocal()
154                  << " raddr: " << GetRemote() << " size: " << GetSize() << ")"
155                  << " transferred " << ret << " bytes";
156     return absl::UnavailableError("process_vm_readv succeeded partially");
157   }
158 
159   return absl::OkStatus();
160 }
161 
162 }  // namespace sapi::v
163