• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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