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 <sys/types.h>
20 #include <sys/uio.h>
21
22 #include <memory>
23 #include <string>
24
25 #include "absl/log/log.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/str_cat.h"
28 #include "sandboxed_api/rpcchannel.h"
29 #include "sandboxed_api/util/raw_logging.h"
30 #include "sandboxed_api/util/status_macros.h"
31 #include "sandboxed_api/var_ptr.h"
32
33 namespace sapi::v {
34
~Var()35 Var::~Var() {
36 if (free_rpc_channel_ && GetRemote()) {
37 this->Free(free_rpc_channel_).IgnoreError();
38 }
39 }
40
operator ()(Ptr * p)41 void Var::PtrDeleter::operator()(Ptr* p) { delete p; }
42
PtrNone()43 Ptr* Var::PtrNone() {
44 if (!ptr_none_) {
45 ptr_none_.reset(new Ptr(this, kSyncNone));
46 }
47 return ptr_none_.get();
48 }
49
PtrBoth()50 Ptr* Var::PtrBoth() {
51 if (!ptr_both_) {
52 ptr_both_.reset(new Ptr(this, kSyncBoth));
53 }
54 return ptr_both_.get();
55 }
56
PtrBefore()57 Ptr* Var::PtrBefore() {
58 if (!ptr_before_) {
59 ptr_before_.reset(new Ptr(this, kSyncBefore));
60 }
61 return ptr_before_.get();
62 }
63
PtrAfter()64 Ptr* Var::PtrAfter() {
65 if (!ptr_after_) {
66 ptr_after_.reset(new Ptr(this, kSyncAfter));
67 }
68 return ptr_after_.get();
69 }
70
Allocate(RPCChannel * rpc_channel,bool automatic_free)71 absl::Status Var::Allocate(RPCChannel* rpc_channel, bool automatic_free) {
72 void* addr;
73 SAPI_RETURN_IF_ERROR(rpc_channel->Allocate(GetSize(), &addr));
74
75 if (!addr) {
76 LOG(ERROR) << "Allocate: returned nullptr";
77 return absl::UnavailableError("Allocating memory failed");
78 }
79
80 SetRemote(addr);
81 if (automatic_free) {
82 SetFreeRPCChannel(rpc_channel);
83 }
84
85 return absl::OkStatus();
86 }
87
Free(RPCChannel * rpc_channel)88 absl::Status Var::Free(RPCChannel* rpc_channel) {
89 SAPI_RETURN_IF_ERROR(rpc_channel->Free(GetRemote()));
90
91 SetRemote(nullptr);
92 return absl::OkStatus();
93 }
94
TransferToSandboxee(RPCChannel * rpc_channel,pid_t pid)95 absl::Status Var::TransferToSandboxee(RPCChannel* rpc_channel, pid_t pid) {
96 VLOG(3) << "TransferToSandboxee for: " << ToString()
97 << ", local: " << GetLocal() << ", remote: " << GetRemote()
98 << ", size: " << GetSize();
99
100 if (remote_ == nullptr) {
101 LOG(WARNING) << "Object: " << GetType() << " has no remote object set";
102 return absl::FailedPreconditionError(
103 absl::StrCat("Object: ", GetType(), " has no remote object set"));
104 }
105
106 struct iovec local = {
107 .iov_base = GetLocal(),
108 .iov_len = GetSize(),
109 };
110 struct iovec remote = {
111 .iov_base = GetRemote(),
112 .iov_len = GetSize(),
113 };
114
115 ssize_t ret = process_vm_writev(pid, &local, 1, &remote, 1, 0);
116 if (ret == -1) {
117 PLOG(WARNING) << "process_vm_writev(pid: " << pid
118 << " laddr: " << GetLocal() << " raddr: " << GetRemote()
119 << " size: " << GetSize() << ")";
120 return absl::UnavailableError("process_vm_writev failed");
121 }
122 if (ret != GetSize()) {
123 LOG(WARNING) << "process_vm_writev(pid: " << pid << " laddr: " << GetLocal()
124 << " raddr: " << GetRemote() << " size: " << GetSize() << ")"
125 << " transferred " << ret << " bytes";
126 return absl::UnavailableError("process_vm_writev: partial success");
127 }
128
129 return absl::OkStatus();
130 }
131
TransferFromSandboxee(RPCChannel * rpc_channel,pid_t pid)132 absl::Status Var::TransferFromSandboxee(RPCChannel* rpc_channel, pid_t pid) {
133 VLOG(3) << "TransferFromSandboxee for: " << ToString()
134 << ", local: " << GetLocal() << ", remote: " << GetRemote()
135 << ", size: " << GetSize();
136
137 if (local_ == nullptr) {
138 return absl::FailedPreconditionError(
139 absl::StrCat("Object: ", GetType(), " has no local storage set"));
140 }
141
142 struct iovec local = {
143 .iov_base = GetLocal(),
144 .iov_len = GetSize(),
145 };
146 struct iovec remote = {
147 .iov_base = GetRemote(),
148 .iov_len = GetSize(),
149 };
150
151 ssize_t ret = process_vm_readv(pid, &local, 1, &remote, 1, 0);
152 if (ret == -1) {
153 PLOG(WARNING) << "process_vm_readv(pid: " << pid << " laddr: " << GetLocal()
154 << " raddr: " << GetRemote() << " size: " << GetSize() << ")";
155 return absl::UnavailableError("process_vm_readv failed");
156 }
157 if (ret != GetSize()) {
158 LOG(WARNING) << "process_vm_readv(pid: " << pid << " laddr: " << GetLocal()
159 << " raddr: " << GetRemote() << " size: " << GetSize() << ")"
160 << " transferred " << ret << " bytes";
161 return absl::UnavailableError("process_vm_readv succeeded partially");
162 }
163
164 return absl::OkStatus();
165 }
166
167 } // namespace sapi::v
168