blob: 1e2d798dbac0c23acb6c7e435479ae0586bf48a8 [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
19#include <trusty_ipc.h>
20
21#include <binder/RpcSession.h>
22#include <binder/RpcTransportTipcTrusty.h>
23#include <log/log.h>
24
25#include "../FdTrigger.h"
26#include "../RpcState.h"
27#include "TrustyStatus.h"
28
29namespace android {
30
31namespace {
32
33// RpcTransport for Trusty.
34class RpcTransportTipcTrusty : public RpcTransport {
35public:
36 explicit RpcTransportTipcTrusty(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
37 ~RpcTransportTipcTrusty() { releaseMessage(); }
38
39 status_t pollRead() override {
40 auto status = ensureMessage(false);
41 if (status != OK) {
42 return status;
43 }
44 return mHaveMessage ? OK : WOULD_BLOCK;
45 }
46
47 status_t interruptableWriteFully(
Andrei Homescu875996f2022-08-24 04:25:11 +000048 FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
49 const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
50 const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
Andrei Homescu74a54452021-12-10 05:30:21 +000051 override {
52 if (niovs < 0) {
53 return BAD_VALUE;
54 }
55
56 size_t size = 0;
57 for (int i = 0; i < niovs; i++) {
58 size += iovs[i].iov_len;
59 }
60
61 ipc_msg_t msg{
62 .num_iov = static_cast<uint32_t>(niovs),
63 .iov = iovs,
64 .num_handles = 0, // TODO: add ancillaryFds
65 .handles = nullptr,
66 };
Andrei Homescub14d3e52022-08-02 22:57:15 +000067 ssize_t rc = send_msg(mSocket.get(), &msg);
Andrei Homescu74a54452021-12-10 05:30:21 +000068 if (rc == ERR_NOT_ENOUGH_BUFFER) {
69 // Peer is blocked, wait until it unblocks.
70 // TODO: when tipc supports a send-unblocked handler,
71 // save the message here in a queue and retry it asynchronously
72 // when the handler gets called by the library
73 uevent uevt;
74 do {
75 rc = ::wait(mSocket.get(), &uevt, INFINITE_TIME);
76 if (rc < 0) {
77 return statusFromTrusty(rc);
78 }
79 if (uevt.event & IPC_HANDLE_POLL_HUP) {
80 return DEAD_OBJECT;
81 }
82 } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED));
83
84 // Retry the send, it should go through this time because
85 // sending is now unblocked
86 rc = send_msg(mSocket.get(), &msg);
87 }
88 if (rc < 0) {
89 return statusFromTrusty(rc);
90 }
91 LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size,
Andrei Homescub14d3e52022-08-02 22:57:15 +000092 "Sent the wrong number of bytes %zd!=%zu", rc, size);
Andrei Homescu74a54452021-12-10 05:30:21 +000093
94 return OK;
95 }
96
97 status_t interruptableReadFully(
Andrei Homescu875996f2022-08-24 04:25:11 +000098 FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs,
99 const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/,
100 std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
101 override {
Andrei Homescu74a54452021-12-10 05:30:21 +0000102 if (niovs < 0) {
103 return BAD_VALUE;
104 }
105
106 // If iovs has one or more empty vectors at the end and
107 // we somehow advance past all the preceding vectors and
108 // pass some or all of the empty ones to sendmsg/recvmsg,
109 // the call will return processSize == 0. In that case
110 // we should be returning OK but instead return DEAD_OBJECT.
111 // To avoid this problem, we make sure here that the last
112 // vector at iovs[niovs - 1] has a non-zero length.
113 while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
114 niovs--;
115 }
116 if (niovs == 0) {
117 // The vectors are all empty, so we have nothing to read.
118 return OK;
119 }
120
121 while (true) {
122 auto status = ensureMessage(true);
123 if (status != OK) {
124 return status;
125 }
126
127 ipc_msg_t msg{
128 .num_iov = static_cast<uint32_t>(niovs),
129 .iov = iovs,
130 .num_handles = 0, // TODO: support ancillaryFds
131 .handles = nullptr,
132 };
Andrei Homescub14d3e52022-08-02 22:57:15 +0000133 ssize_t rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg);
Andrei Homescu74a54452021-12-10 05:30:21 +0000134 if (rc < 0) {
135 return statusFromTrusty(rc);
136 }
137
138 size_t processSize = static_cast<size_t>(rc);
139 mMessageOffset += processSize;
140 LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len,
141 "Message offset exceeds length %zu/%zu", mMessageOffset,
142 mMessageInfo.len);
143
144 // Release the message if all of it has been read
145 if (mMessageOffset == mMessageInfo.len) {
146 releaseMessage();
147 }
148
149 while (processSize > 0 && niovs > 0) {
150 auto& iov = iovs[0];
151 if (processSize < iov.iov_len) {
152 // Advance the base of the current iovec
153 iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
154 iov.iov_len -= processSize;
155 break;
156 }
157
158 // The current iovec was fully written
159 processSize -= iov.iov_len;
160 iovs++;
161 niovs--;
162 }
163 if (niovs == 0) {
164 LOG_ALWAYS_FATAL_IF(processSize > 0,
165 "Reached the end of iovecs "
166 "with %zd bytes remaining",
167 processSize);
168 return OK;
169 }
170 }
171 }
172
173private:
174 status_t ensureMessage(bool wait) {
175 int rc;
176 if (mHaveMessage) {
177 LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message");
178 return OK;
179 }
180
181 /* TODO: interruptible wait, maybe with a timeout??? */
182 uevent uevt;
183 rc = ::wait(mSocket.get(), &uevt, wait ? INFINITE_TIME : 0);
184 if (rc < 0) {
185 if (rc == ERR_TIMED_OUT && !wait) {
186 // If we timed out with wait==false, then there's no message
187 return OK;
188 }
189 return statusFromTrusty(rc);
190 }
191 if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
192 /* No message, terminate here and leave mHaveMessage false */
193 return OK;
194 }
195
196 rc = get_msg(mSocket.get(), &mMessageInfo);
197 if (rc < 0) {
198 return statusFromTrusty(rc);
199 }
200
201 mHaveMessage = true;
202 mMessageOffset = 0;
203 return OK;
204 }
205
206 void releaseMessage() {
207 if (mHaveMessage) {
208 put_msg(mSocket.get(), mMessageInfo.id);
209 mHaveMessage = false;
210 }
211 }
212
213 base::unique_fd mSocket;
214
215 bool mHaveMessage = false;
216 ipc_msg_info mMessageInfo;
217 size_t mMessageOffset;
218};
219
220// RpcTransportCtx for Trusty.
221class RpcTransportCtxTipcTrusty : public RpcTransportCtx {
222public:
223 std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
224 FdTrigger*) const override {
225 return std::make_unique<RpcTransportTipcTrusty>(std::move(fd));
226 }
227 std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
228};
229
230} // namespace
231
232std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const {
233 return std::make_unique<RpcTransportCtxTipcTrusty>();
234}
235
236std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const {
237 return std::make_unique<RpcTransportCtxTipcTrusty>();
238}
239
240const char* RpcTransportCtxFactoryTipcTrusty::toCString() const {
241 return "trusty";
242}
243
244std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() {
245 return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>(
246 new RpcTransportCtxFactoryTipcTrusty());
247}
248
249} // namespace android