blob: 692f82d6cda3ccc3f3955ff834d003970310470a [file] [log] [blame]
Andrei Homescu74a54452021-12-10 05:30:21 +00001/*
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
Andrei Homescu1c18a802022-08-17 04:59:01 +000019#include <inttypes.h>
Andrei Homescu74a54452021-12-10 05:30:21 +000020#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
30namespace android {
31
Andrei Homescu74a54452021-12-10 05:30:21 +000032// RpcTransport for Trusty.
33class RpcTransportTipcTrusty : public RpcTransport {
34public:
Pawan3e0061c2022-08-26 21:08:34 +000035 explicit RpcTransportTipcTrusty(android::RpcTransportFd socket) : mSocket(std::move(socket)) {}
Andrei Homescu74a54452021-12-10 05:30:21 +000036 ~RpcTransportTipcTrusty() { releaseMessage(); }
37
38 status_t pollRead() override {
39 auto status = ensureMessage(false);
40 if (status != OK) {
41 return status;
42 }
43 return mHaveMessage ? OK : WOULD_BLOCK;
44 }
45
46 status_t interruptableWriteFully(
Andrei Homescu875996f2022-08-24 04:25:11 +000047 FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
Sebastian Pickl84b7cff2023-10-30 08:02:24 +000048 const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
Andrei Homescu1c18a802022-08-17 04:59:01 +000049 const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
Andrei Homescu74a54452021-12-10 05:30:21 +000050 override {
51 if (niovs < 0) {
52 return BAD_VALUE;
53 }
54
55 size_t size = 0;
56 for (int i = 0; i < niovs; i++) {
57 size += iovs[i].iov_len;
58 }
59
Andrei Homescu1c18a802022-08-17 04:59:01 +000060 handle_t msgHandles[IPC_MAX_MSG_HANDLES];
Andrei Homescu74a54452021-12-10 05:30:21 +000061 ipc_msg_t msg{
62 .num_iov = static_cast<uint32_t>(niovs),
63 .iov = iovs,
Andrei Homescu1c18a802022-08-17 04:59:01 +000064 .num_handles = 0,
Andrei Homescu74a54452021-12-10 05:30:21 +000065 .handles = nullptr,
66 };
Andrei Homescu1c18a802022-08-17 04:59:01 +000067
68 if (ancillaryFds != nullptr && !ancillaryFds->empty()) {
69 if (ancillaryFds->size() > IPC_MAX_MSG_HANDLES) {
70 // This shouldn't happen because we check the FD count in RpcState.
71 ALOGE("Saw too many file descriptors in RpcTransportCtxTipcTrusty: "
72 "%zu (max is %u). Aborting session.",
73 ancillaryFds->size(), IPC_MAX_MSG_HANDLES);
74 return BAD_VALUE;
75 }
76
77 for (size_t i = 0; i < ancillaryFds->size(); i++) {
78 msgHandles[i] =
79 std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i));
80 }
81
82 msg.num_handles = ancillaryFds->size();
83 msg.handles = msgHandles;
84 }
85
Pawan49d74cb2022-08-03 21:19:11 +000086 ssize_t rc = send_msg(mSocket.fd.get(), &msg);
Andrei Homescu74a54452021-12-10 05:30:21 +000087 if (rc == ERR_NOT_ENOUGH_BUFFER) {
88 // Peer is blocked, wait until it unblocks.
89 // TODO: when tipc supports a send-unblocked handler,
90 // save the message here in a queue and retry it asynchronously
91 // when the handler gets called by the library
92 uevent uevt;
93 do {
Pawan49d74cb2022-08-03 21:19:11 +000094 rc = ::wait(mSocket.fd.get(), &uevt, INFINITE_TIME);
Andrei Homescu74a54452021-12-10 05:30:21 +000095 if (rc < 0) {
96 return statusFromTrusty(rc);
97 }
98 if (uevt.event & IPC_HANDLE_POLL_HUP) {
99 return DEAD_OBJECT;
100 }
101 } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED));
102
103 // Retry the send, it should go through this time because
104 // sending is now unblocked
Pawan49d74cb2022-08-03 21:19:11 +0000105 rc = send_msg(mSocket.fd.get(), &msg);
Andrei Homescu74a54452021-12-10 05:30:21 +0000106 }
107 if (rc < 0) {
108 return statusFromTrusty(rc);
109 }
110 LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size,
Andrei Homescub14d3e52022-08-02 22:57:15 +0000111 "Sent the wrong number of bytes %zd!=%zu", rc, size);
Andrei Homescu74a54452021-12-10 05:30:21 +0000112
113 return OK;
114 }
115
116 status_t interruptableReadFully(
Andrei Homescu875996f2022-08-24 04:25:11 +0000117 FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
Sebastian Pickl84b7cff2023-10-30 08:02:24 +0000118 const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
Andrei Homescu1c18a802022-08-17 04:59:01 +0000119 std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
Andrei Homescu74a54452021-12-10 05:30:21 +0000120 if (niovs < 0) {
121 return BAD_VALUE;
122 }
123
124 // If iovs has one or more empty vectors at the end and
125 // we somehow advance past all the preceding vectors and
126 // pass some or all of the empty ones to sendmsg/recvmsg,
127 // the call will return processSize == 0. In that case
128 // we should be returning OK but instead return DEAD_OBJECT.
129 // To avoid this problem, we make sure here that the last
130 // vector at iovs[niovs - 1] has a non-zero length.
131 while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
132 niovs--;
133 }
134 if (niovs == 0) {
135 // The vectors are all empty, so we have nothing to read.
136 return OK;
137 }
138
139 while (true) {
140 auto status = ensureMessage(true);
141 if (status != OK) {
142 return status;
143 }
144
Andrei Homescu1c18a802022-08-17 04:59:01 +0000145 LOG_ALWAYS_FATAL_IF(mMessageInfo.num_handles > IPC_MAX_MSG_HANDLES,
146 "Received too many handles %" PRIu32, mMessageInfo.num_handles);
147 bool haveHandles = mMessageInfo.num_handles != 0;
148 handle_t msgHandles[IPC_MAX_MSG_HANDLES];
149
Andrei Homescu74a54452021-12-10 05:30:21 +0000150 ipc_msg_t msg{
151 .num_iov = static_cast<uint32_t>(niovs),
152 .iov = iovs,
Andrei Homescu1c18a802022-08-17 04:59:01 +0000153 .num_handles = mMessageInfo.num_handles,
154 .handles = haveHandles ? msgHandles : 0,
Andrei Homescu74a54452021-12-10 05:30:21 +0000155 };
Pawan49d74cb2022-08-03 21:19:11 +0000156 ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg);
Andrei Homescu74a54452021-12-10 05:30:21 +0000157 if (rc < 0) {
158 return statusFromTrusty(rc);
159 }
160
161 size_t processSize = static_cast<size_t>(rc);
162 mMessageOffset += processSize;
163 LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len,
164 "Message offset exceeds length %zu/%zu", mMessageOffset,
165 mMessageInfo.len);
166
Andrei Homescu1c18a802022-08-17 04:59:01 +0000167 if (haveHandles) {
168 if (ancillaryFds != nullptr) {
169 ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles);
170 for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
171 ancillaryFds->emplace_back(base::unique_fd(msgHandles[i]));
172 }
173
174 // Clear the saved number of handles so we don't accidentally
175 // read them multiple times
176 mMessageInfo.num_handles = 0;
177 haveHandles = false;
178 } else {
179 ALOGE("Received unexpected handles %" PRIu32, mMessageInfo.num_handles);
180 // It should be safe to continue here. We could abort, but then
181 // peers could DoS us by sending messages with handles in them.
182 // Close the handles since we are ignoring them.
183 for (size_t i = 0; i < mMessageInfo.num_handles; i++) {
184 ::close(msgHandles[i]);
185 }
186 }
187 }
188
Andrei Homescu74a54452021-12-10 05:30:21 +0000189 // Release the message if all of it has been read
190 if (mMessageOffset == mMessageInfo.len) {
191 releaseMessage();
192 }
193
194 while (processSize > 0 && niovs > 0) {
195 auto& iov = iovs[0];
196 if (processSize < iov.iov_len) {
197 // Advance the base of the current iovec
198 iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
199 iov.iov_len -= processSize;
200 break;
201 }
202
203 // The current iovec was fully written
204 processSize -= iov.iov_len;
205 iovs++;
206 niovs--;
207 }
208 if (niovs == 0) {
209 LOG_ALWAYS_FATAL_IF(processSize > 0,
210 "Reached the end of iovecs "
211 "with %zd bytes remaining",
212 processSize);
213 return OK;
214 }
215 }
216 }
217
Pawan49d74cb2022-08-03 21:19:11 +0000218 bool isWaiting() override { return mSocket.isInPollingState(); }
219
Andrei Homescu74a54452021-12-10 05:30:21 +0000220private:
221 status_t ensureMessage(bool wait) {
222 int rc;
223 if (mHaveMessage) {
224 LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message");
225 return OK;
226 }
227
228 /* TODO: interruptible wait, maybe with a timeout??? */
229 uevent uevt;
Pawan49d74cb2022-08-03 21:19:11 +0000230 rc = ::wait(mSocket.fd.get(), &uevt, wait ? INFINITE_TIME : 0);
Andrei Homescu74a54452021-12-10 05:30:21 +0000231 if (rc < 0) {
232 if (rc == ERR_TIMED_OUT && !wait) {
233 // If we timed out with wait==false, then there's no message
234 return OK;
235 }
236 return statusFromTrusty(rc);
237 }
238 if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
239 /* No message, terminate here and leave mHaveMessage false */
Andrei Homescu805ca7a2022-12-09 07:16:23 +0000240 if (uevt.event & IPC_HANDLE_POLL_HUP) {
241 // Peer closed the connection. We need to preserve the order
242 // between MSG and HUP from FdTrigger.cpp, which means that
243 // getting MSG&HUP should return OK instead of DEAD_OBJECT.
244 return DEAD_OBJECT;
245 }
Andrei Homescu74a54452021-12-10 05:30:21 +0000246 return OK;
247 }
248
Pawan49d74cb2022-08-03 21:19:11 +0000249 rc = get_msg(mSocket.fd.get(), &mMessageInfo);
Andrei Homescu74a54452021-12-10 05:30:21 +0000250 if (rc < 0) {
251 return statusFromTrusty(rc);
252 }
253
254 mHaveMessage = true;
255 mMessageOffset = 0;
256 return OK;
257 }
258
259 void releaseMessage() {
260 if (mHaveMessage) {
Pawan49d74cb2022-08-03 21:19:11 +0000261 put_msg(mSocket.fd.get(), mMessageInfo.id);
Andrei Homescu74a54452021-12-10 05:30:21 +0000262 mHaveMessage = false;
263 }
264 }
265
Pawan3e0061c2022-08-26 21:08:34 +0000266 android::RpcTransportFd mSocket;
Andrei Homescu74a54452021-12-10 05:30:21 +0000267
268 bool mHaveMessage = false;
269 ipc_msg_info mMessageInfo;
270 size_t mMessageOffset;
271};
272
273// RpcTransportCtx for Trusty.
274class RpcTransportCtxTipcTrusty : public RpcTransportCtx {
275public:
Pawan3e0061c2022-08-26 21:08:34 +0000276 std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd socket,
Andrei Homescu74a54452021-12-10 05:30:21 +0000277 FdTrigger*) const override {
Pawan49d74cb2022-08-03 21:19:11 +0000278 return std::make_unique<RpcTransportTipcTrusty>(std::move(socket));
Andrei Homescu74a54452021-12-10 05:30:21 +0000279 }
280 std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
281};
282
Andrei Homescu74a54452021-12-10 05:30:21 +0000283std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const {
284 return std::make_unique<RpcTransportCtxTipcTrusty>();
285}
286
287std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const {
288 return std::make_unique<RpcTransportCtxTipcTrusty>();
289}
290
291const char* RpcTransportCtxFactoryTipcTrusty::toCString() const {
292 return "trusty";
293}
294
295std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() {
296 return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>(
297 new RpcTransportCtxFactoryTipcTrusty());
298}
299
300} // namespace android