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