• 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 
interruptableWriteFully(FdTrigger *,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> &,const std::vector<std::variant<unique_fd,borrowed_fd>> * ancillaryFds)50     status_t interruptableWriteFully(
51             FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
52             const std::optional<SmallFunction<status_t()>>& /*altPoll*/,
53             const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
54         if (niovs < 0) {
55             return BAD_VALUE;
56         }
57 
58         size_t size = 0;
59         for (int i = 0; i < niovs; i++) {
60             size += iovs[i].iov_len;
61         }
62 
63         handle_t msgHandles[IPC_MAX_MSG_HANDLES];
64         ipc_msg_t msg{
65                 .num_iov = static_cast<uint32_t>(niovs),
66                 .iov = iovs,
67                 .num_handles = 0,
68                 .handles = nullptr,
69         };
70 
71         if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
72             if (ancillaryFds->size() > IPC_MAX_MSG_HANDLES) {
73                 // This shouldn't happen because we check the FD count in RpcState.
74                 ALOGE("Saw too many file descriptors in RpcTransportCtxTipcTrusty: "
75                       "%zu (max is %u). Aborting session.",
76                       ancillaryFds->size(), IPC_MAX_MSG_HANDLES);
77                 return BAD_VALUE;
78             }
79 
80             for (size_t i = 0; i < ancillaryFds->size(); i++) {
81                 msgHandles[i] =
82                         std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i));
83             }
84 
85             msg.num_handles = ancillaryFds->size();
86             msg.handles = msgHandles;
87         }
88 
89         ssize_t rc = send_msg(mSocket.fd.get(), &msg);
90         if (rc == ERR_NOT_ENOUGH_BUFFER) {
91             // Peer is blocked, wait until it unblocks.
92             // TODO: when tipc supports a send-unblocked handler,
93             // save the message here in a queue and retry it asynchronously
94             // when the handler gets called by the library
95             uevent uevt;
96             do {
97                 rc = ::wait(mSocket.fd.get(), &uevt, INFINITE_TIME);
98                 if (rc < 0) {
99                     return statusFromTrusty(rc);
100                 }
101                 if (uevt.event & IPC_HANDLE_POLL_HUP) {
102                     return DEAD_OBJECT;
103                 }
104             } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED));
105 
106             // Retry the send, it should go through this time because
107             // sending is now unblocked
108             rc = send_msg(mSocket.fd.get(), &msg);
109         }
110         if (rc < 0) {
111             return statusFromTrusty(rc);
112         }
113         LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size,
114                             "Sent the wrong number of bytes %zd!=%zu", rc, size);
115 
116         return OK;
117     }
118 
interruptableReadFully(FdTrigger *,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> &,std::vector<std::variant<unique_fd,borrowed_fd>> * ancillaryFds)119     status_t interruptableReadFully(
120             FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
121             const std::optional<SmallFunction<status_t()>>& /*altPoll*/,
122             std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
123         if (niovs < 0) {
124             return BAD_VALUE;
125         }
126 
127         // If iovs has one or more empty vectors at the end and
128         // we somehow advance past all the preceding vectors and
129         // pass some or all of the empty ones to sendmsg/recvmsg,
130         // the call will return processSize == 0. In that case
131         // we should be returning OK but instead return DEAD_OBJECT.
132         // To avoid this problem, we make sure here that the last
133         // vector at iovs[niovs - 1] has a non-zero length.
134         while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
135             niovs--;
136         }
137         if (niovs == 0) {
138             // The vectors are all empty, so we have nothing to read.
139             return OK;
140         }
141 
142         while (true) {
143             auto status = ensureMessage(true);
144             if (status != OK) {
145                 return status;
146             }
147 
148             LOG_ALWAYS_FATAL_IF(mMessageInfo.num_handles > IPC_MAX_MSG_HANDLES,
149                                 "Received too many handles %" PRIu32, mMessageInfo.num_handles);
150             bool haveHandles = mMessageInfo.num_handles != 0;
151             handle_t msgHandles[IPC_MAX_MSG_HANDLES];
152 
153             ipc_msg_t msg{
154                     .num_iov = static_cast<uint32_t>(niovs),
155                     .iov = iovs,
156                     .num_handles = mMessageInfo.num_handles,
157                     .handles = haveHandles ? msgHandles : 0,
158             };
159             ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg);
160             if (rc < 0) {
161                 return statusFromTrusty(rc);
162             }
163 
164             size_t processSize = static_cast<size_t>(rc);
165             mMessageOffset += processSize;
166             LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len,
167                                 "Message offset exceeds length %zu/%zu", mMessageOffset,
168                                 mMessageInfo.len);
169 
170             if (haveHandles) {
171                 if (ancillaryFds != nullptr) {
172                     ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles);
173                     for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
174                         ancillaryFds->emplace_back(unique_fd(msgHandles[i]));
175                     }
176 
177                     // Clear the saved number of handles so we don't accidentally
178                     // read them multiple times
179                     mMessageInfo.num_handles = 0;
180                     haveHandles = false;
181                 } else {
182                     ALOGE("Received unexpected handles %" PRIu32, mMessageInfo.num_handles);
183                     // It should be safe to continue here. We could abort, but then
184                     // peers could DoS us by sending messages with handles in them.
185                     // Close the handles since we are ignoring them.
186                     for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
187                         ::close(msgHandles[i]);
188                     }
189                 }
190             }
191 
192             // Release the message if all of it has been read
193             if (mMessageOffset == mMessageInfo.len) {
194                 releaseMessage();
195             }
196 
197             while (processSize > 0 && niovs > 0) {
198                 auto& iov = iovs[0];
199                 if (processSize < iov.iov_len) {
200                     // Advance the base of the current iovec
201                     iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
202                     iov.iov_len -= processSize;
203                     break;
204                 }
205 
206                 // The current iovec was fully written
207                 processSize -= iov.iov_len;
208                 iovs++;
209                 niovs--;
210             }
211             if (niovs == 0) {
212                 LOG_ALWAYS_FATAL_IF(processSize > 0,
213                                     "Reached the end of iovecs "
214                                     "with %zd bytes remaining",
215                                     processSize);
216                 return OK;
217             }
218         }
219     }
220 
isWaiting()221     bool isWaiting() override { return mSocket.isInPollingState(); }
222 
223 private:
ensureMessage(bool wait)224     status_t ensureMessage(bool wait) {
225         int rc;
226         if (mHaveMessage) {
227             LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message");
228             return OK;
229         }
230 
231         /* TODO: interruptible wait, maybe with a timeout??? */
232         uevent uevt;
233         rc = ::wait(mSocket.fd.get(), &uevt, wait ? INFINITE_TIME : 0);
234         if (rc < 0) {
235             if (rc == ERR_TIMED_OUT && !wait) {
236                 // If we timed out with wait==false, then there's no message
237                 return OK;
238             }
239             return statusFromTrusty(rc);
240         }
241         if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
242             /* No message, terminate here and leave mHaveMessage false */
243             if (uevt.event & IPC_HANDLE_POLL_HUP) {
244                 // Peer closed the connection. We need to preserve the order
245                 // between MSG and HUP from FdTrigger.cpp, which means that
246                 // getting MSG&HUP should return OK instead of DEAD_OBJECT.
247                 return DEAD_OBJECT;
248             }
249             return OK;
250         }
251 
252         rc = get_msg(mSocket.fd.get(), &mMessageInfo);
253         if (rc < 0) {
254             return statusFromTrusty(rc);
255         }
256 
257         mHaveMessage = true;
258         mMessageOffset = 0;
259         return OK;
260     }
261 
releaseMessage()262     void releaseMessage() {
263         if (mHaveMessage) {
264             put_msg(mSocket.fd.get(), mMessageInfo.id);
265             mHaveMessage = false;
266         }
267     }
268 
269     android::RpcTransportFd mSocket;
270 
271     bool mHaveMessage = false;
272     ipc_msg_info mMessageInfo;
273     size_t mMessageOffset;
274 };
275 
276 // RpcTransportCtx for Trusty.
277 class RpcTransportCtxTipcTrusty : public RpcTransportCtx {
278 public:
newTransport(android::RpcTransportFd socket,FdTrigger *) const279     std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd socket,
280                                                FdTrigger*) const override {
281         return std::make_unique<RpcTransportTipcTrusty>(std::move(socket));
282     }
getCertificate(RpcCertificateFormat) const283     std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
284 };
285 
newServerCtx() const286 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const {
287     return std::make_unique<RpcTransportCtxTipcTrusty>();
288 }
289 
newClientCtx() const290 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const {
291     return std::make_unique<RpcTransportCtxTipcTrusty>();
292 }
293 
toCString() const294 const char* RpcTransportCtxFactoryTipcTrusty::toCString() const {
295     return "trusty";
296 }
297 
make()298 std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() {
299     return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>(
300             new RpcTransportCtxFactoryTipcTrusty());
301 }
302 
303 } // namespace android
304