1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "RpcTransportTipcTrusty"
18
19 #include <inttypes.h>
20 #include <trusty_ipc.h>
21
22 #include <binder/RpcSession.h>
23 #include <binder/RpcTransportTipcTrusty.h>
24 #include <log/log.h>
25
26 #include "../FdTrigger.h"
27 #include "../RpcState.h"
28 #include "TrustyStatus.h"
29
30 namespace android {
31
32 using namespace android::binder::impl;
33 using android::binder::borrowed_fd;
34 using android::binder::unique_fd;
35
36 // RpcTransport for Trusty.
37 class RpcTransportTipcTrusty : public RpcTransport {
38 public:
RpcTransportTipcTrusty(android::RpcTransportFd socket)39 explicit RpcTransportTipcTrusty(android::RpcTransportFd socket) : mSocket(std::move(socket)) {}
~RpcTransportTipcTrusty()40 ~RpcTransportTipcTrusty() { releaseMessage(); }
41
pollRead()42 status_t pollRead() override {
43 auto status = ensureMessage(false);
44 if (status != OK) {
45 return status;
46 }
47 return mHaveMessage ? OK : WOULD_BLOCK;
48 }
49
moveMsgStart(ipc_msg_t * msg,size_t msg_size,size_t offset)50 void moveMsgStart(ipc_msg_t* msg, size_t msg_size, size_t offset) {
51 LOG_ALWAYS_FATAL_IF(offset > msg_size, "tried to move message past its end %zd>%zd", offset,
52 msg_size);
53 while (true) {
54 if (offset == 0) {
55 break;
56 }
57 if (offset >= msg->iov[0].iov_len) {
58 // Move to the next iov, this one was sent already
59 offset -= msg->iov[0].iov_len;
60 msg->iov++;
61 msg->num_iov -= 1;
62 } else {
63 // We need to move the base of the current iov
64 msg->iov[0].iov_len -= offset;
65 msg->iov[0].iov_base = static_cast<char*>(msg->iov[0].iov_base) + offset;
66 offset = 0;
67 }
68 }
69 // We only send handles on the first message. This can be changed in the future if we want
70 // to send more handles than the maximum per message limit (which would require sending
71 // multiple messages). The current code makes sure that we send less handles than the
72 // maximum trusty allows.
73 msg->num_handles = 0;
74 }
75
sendTrustyMsg(ipc_msg_t * msg,size_t msg_size)76 status_t sendTrustyMsg(ipc_msg_t* msg, size_t msg_size) {
77 do {
78 ssize_t rc = send_msg(mSocket.fd.get(), msg);
79 if (rc == ERR_NOT_ENOUGH_BUFFER) {
80 // Peer is blocked, wait until it unblocks.
81 // TODO: when tipc supports a send-unblocked handler,
82 // save the message here in a queue and retry it asynchronously
83 // when the handler gets called by the library
84 uevent uevt;
85 do {
86 rc = ::wait(mSocket.fd.get(), &uevt, INFINITE_TIME);
87 if (rc < 0) {
88 return statusFromTrusty(rc);
89 }
90 if (uevt.event & IPC_HANDLE_POLL_HUP) {
91 return DEAD_OBJECT;
92 }
93 } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED));
94
95 // Retry the send, it should go through this time because
96 // sending is now unblocked
97 rc = send_msg(mSocket.fd.get(), msg);
98 }
99 if (rc < 0) {
100 return statusFromTrusty(rc);
101 }
102 size_t sent_bytes = static_cast<size_t>(rc);
103 if (sent_bytes < msg_size) {
104 moveMsgStart(msg, msg_size, static_cast<size_t>(sent_bytes));
105 msg_size -= sent_bytes;
106 } else {
107 LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != msg_size,
108 "Sent the wrong number of bytes %zd!=%zu", rc, msg_size);
109 break;
110 }
111 } while (true);
112 return OK;
113 }
114
interruptableWriteFully(FdTrigger *,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> &,const std::vector<std::variant<unique_fd,borrowed_fd>> * ancillaryFds)115 status_t interruptableWriteFully(
116 FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
117 const std::optional<SmallFunction<status_t()>>& /*altPoll*/,
118 const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
119 if (niovs < 0) {
120 return BAD_VALUE;
121 }
122
123 size_t size = 0;
124 for (int i = 0; i < niovs; i++) {
125 size += iovs[i].iov_len;
126 }
127
128 handle_t msgHandles[IPC_MAX_MSG_HANDLES];
129 ipc_msg_t msg{
130 .num_iov = static_cast<uint32_t>(niovs),
131 .iov = iovs,
132 .num_handles = 0,
133 .handles = nullptr,
134 };
135
136 if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
137 if (ancillaryFds->size() > IPC_MAX_MSG_HANDLES) {
138 // This shouldn't happen because we check the FD count in RpcState.
139 ALOGE("Saw too many file descriptors in RpcTransportCtxTipcTrusty: "
140 "%zu (max is %u). Aborting session.",
141 ancillaryFds->size(), IPC_MAX_MSG_HANDLES);
142 return BAD_VALUE;
143 }
144
145 for (size_t i = 0; i < ancillaryFds->size(); i++) {
146 msgHandles[i] =
147 std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i));
148 }
149
150 msg.num_handles = ancillaryFds->size();
151 msg.handles = msgHandles;
152 }
153
154 return sendTrustyMsg(&msg, size);
155 }
156
interruptableReadFully(FdTrigger *,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> &,std::vector<std::variant<unique_fd,borrowed_fd>> * ancillaryFds)157 status_t interruptableReadFully(
158 FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
159 const std::optional<SmallFunction<status_t()>>& /*altPoll*/,
160 std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
161 if (niovs < 0) {
162 return BAD_VALUE;
163 }
164
165 // If iovs has one or more empty vectors at the end and
166 // we somehow advance past all the preceding vectors and
167 // pass some or all of the empty ones to sendmsg/recvmsg,
168 // the call will return processSize == 0. In that case
169 // we should be returning OK but instead return DEAD_OBJECT.
170 // To avoid this problem, we make sure here that the last
171 // vector at iovs[niovs - 1] has a non-zero length.
172 while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
173 niovs--;
174 }
175 if (niovs == 0) {
176 // The vectors are all empty, so we have nothing to read.
177 return OK;
178 }
179
180 while (true) {
181 auto status = ensureMessage(true);
182 if (status != OK) {
183 return status;
184 }
185
186 LOG_ALWAYS_FATAL_IF(mMessageInfo.num_handles > IPC_MAX_MSG_HANDLES,
187 "Received too many handles %" PRIu32, mMessageInfo.num_handles);
188 bool haveHandles = mMessageInfo.num_handles != 0;
189 handle_t msgHandles[IPC_MAX_MSG_HANDLES];
190
191 ipc_msg_t msg{
192 .num_iov = static_cast<uint32_t>(niovs),
193 .iov = iovs,
194 .num_handles = mMessageInfo.num_handles,
195 .handles = haveHandles ? msgHandles : 0,
196 };
197 ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg);
198 if (rc < 0) {
199 return statusFromTrusty(rc);
200 }
201
202 size_t processSize = static_cast<size_t>(rc);
203 mMessageOffset += processSize;
204 LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len,
205 "Message offset exceeds length %zu/%zu", mMessageOffset,
206 mMessageInfo.len);
207
208 if (haveHandles) {
209 if (ancillaryFds != nullptr) {
210 ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles);
211 for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
212 ancillaryFds->emplace_back(unique_fd(msgHandles[i]));
213 }
214
215 // Clear the saved number of handles so we don't accidentally
216 // read them multiple times
217 mMessageInfo.num_handles = 0;
218 haveHandles = false;
219 } else {
220 ALOGE("Received unexpected handles %" PRIu32, mMessageInfo.num_handles);
221 // It should be safe to continue here. We could abort, but then
222 // peers could DoS us by sending messages with handles in them.
223 // Close the handles since we are ignoring them.
224 for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
225 ::close(msgHandles[i]);
226 }
227 }
228 }
229
230 // Release the message if all of it has been read
231 if (mMessageOffset == mMessageInfo.len) {
232 releaseMessage();
233 }
234
235 while (processSize > 0 && niovs > 0) {
236 auto& iov = iovs[0];
237 if (processSize < iov.iov_len) {
238 // Advance the base of the current iovec
239 iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
240 iov.iov_len -= processSize;
241 break;
242 }
243
244 // The current iovec was fully written
245 processSize -= iov.iov_len;
246 iovs++;
247 niovs--;
248 }
249 if (niovs == 0) {
250 LOG_ALWAYS_FATAL_IF(processSize > 0,
251 "Reached the end of iovecs "
252 "with %zd bytes remaining",
253 processSize);
254 return OK;
255 }
256 }
257 }
258
isWaiting()259 bool isWaiting() override { return mSocket.isInPollingState(); }
260
261 private:
ensureMessage(bool wait)262 status_t ensureMessage(bool wait) {
263 int rc;
264 if (mHaveMessage) {
265 LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message");
266 return OK;
267 }
268
269 /* TODO: interruptible wait, maybe with a timeout??? */
270 uevent uevt;
271 rc = ::wait(mSocket.fd.get(), &uevt, wait ? INFINITE_TIME : 0);
272 if (rc < 0) {
273 if (rc == ERR_TIMED_OUT && !wait) {
274 // If we timed out with wait==false, then there's no message
275 return OK;
276 }
277 return statusFromTrusty(rc);
278 }
279 if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
280 /* No message, terminate here and leave mHaveMessage false */
281 if (uevt.event & IPC_HANDLE_POLL_HUP) {
282 // Peer closed the connection. We need to preserve the order
283 // between MSG and HUP from FdTrigger.cpp, which means that
284 // getting MSG&HUP should return OK instead of DEAD_OBJECT.
285 return DEAD_OBJECT;
286 }
287 return OK;
288 }
289
290 rc = get_msg(mSocket.fd.get(), &mMessageInfo);
291 if (rc < 0) {
292 return statusFromTrusty(rc);
293 }
294
295 mHaveMessage = true;
296 mMessageOffset = 0;
297 return OK;
298 }
299
releaseMessage()300 void releaseMessage() {
301 if (mHaveMessage) {
302 put_msg(mSocket.fd.get(), mMessageInfo.id);
303 mHaveMessage = false;
304 }
305 }
306
307 android::RpcTransportFd mSocket;
308
309 bool mHaveMessage = false;
310 ipc_msg_info mMessageInfo;
311 size_t mMessageOffset;
312 };
313
314 // RpcTransportCtx for Trusty.
315 class RpcTransportCtxTipcTrusty : public RpcTransportCtx {
316 public:
newTransport(android::RpcTransportFd socket,FdTrigger *) const317 std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd socket,
318 FdTrigger*) const override {
319 return std::make_unique<RpcTransportTipcTrusty>(std::move(socket));
320 }
getCertificate(RpcCertificateFormat) const321 std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
322 };
323
newServerCtx() const324 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const {
325 return std::make_unique<RpcTransportCtxTipcTrusty>();
326 }
327
newClientCtx() const328 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const {
329 return std::make_unique<RpcTransportCtxTipcTrusty>();
330 }
331
toCString() const332 const char* RpcTransportCtxFactoryTipcTrusty::toCString() const {
333 return "trusty";
334 }
335
make()336 std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() {
337 return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>(
338 new RpcTransportCtxFactoryTipcTrusty());
339 }
340
341 } // namespace android
342