• 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 "RpcTransportTipcAndroid"
18 
19 #include <binder/RpcSession.h>
20 #include <binder/RpcTransportTipcAndroid.h>
21 #include <log/log.h>
22 #include <poll.h>
23 #include <trusty/tipc.h>
24 #include <type_traits>
25 
26 #include "FdTrigger.h"
27 #include "RpcState.h"
28 #include "RpcTransportUtils.h"
29 
30 using namespace android::binder::impl;
31 using android::binder::borrowed_fd;
32 using android::binder::unique_fd;
33 
34 namespace android {
35 
36 // Corresponds to IPC_MAX_MSG_HANDLES in the Trusty kernel
37 constexpr size_t kMaxTipcHandles = 8;
38 
39 // RpcTransport for writing Trusty IPC clients in Android.
40 class RpcTransportTipcAndroid : public RpcTransport {
41 public:
RpcTransportTipcAndroid(android::RpcTransportFd socket)42     explicit RpcTransportTipcAndroid(android::RpcTransportFd socket) : mSocket(std::move(socket)) {}
43 
pollRead()44     status_t pollRead() override {
45         if (mReadBufferPos < mReadBufferSize) {
46             // We have more data in the read buffer
47             return OK;
48         }
49 
50         // Trusty IPC device is not a socket, so MSG_PEEK is not available
51         pollfd pfd{.fd = mSocket.fd.get(), .events = static_cast<int16_t>(POLLIN), .revents = 0};
52         ssize_t ret = TEMP_FAILURE_RETRY(::poll(&pfd, 1, 0));
53         if (ret < 0) {
54             int savedErrno = errno;
55             if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
56                 return WOULD_BLOCK;
57             }
58 
59             LOG_RPC_DETAIL("RpcTransport poll(): %s", strerror(savedErrno));
60             return adjustStatus(-savedErrno);
61         }
62 
63         if (pfd.revents & POLLNVAL) {
64             return BAD_VALUE;
65         }
66         if (pfd.revents & POLLERR) {
67             return DEAD_OBJECT;
68         }
69         if (pfd.revents & POLLIN) {
70             // Copied from FdTrigger.cpp: Even though POLLHUP may also be set,
71             // treat it as a success condition to ensure data is drained.
72             return OK;
73         }
74         if (pfd.revents & POLLHUP) {
75             return DEAD_OBJECT;
76         }
77 
78         return WOULD_BLOCK;
79     }
80 
interruptableWriteFully(FdTrigger * fdTrigger,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> & altPoll,const std::vector<std::variant<unique_fd,borrowed_fd>> * ancillaryFds)81     status_t interruptableWriteFully(
82             FdTrigger* fdTrigger, iovec* iovs, int niovs,
83             const std::optional<SmallFunction<status_t()>>& altPoll,
84             const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
85         bool sentFds = false;
86         auto writeFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
87             trusty_shm shms[kMaxTipcHandles] = {{0}};
88             ssize_t shm_count = 0;
89 
90             if (!sentFds && ancillaryFds != nullptr && !ancillaryFds->empty()) {
91                 if (ancillaryFds->size() > kMaxTipcHandles) {
92                     ALOGE("Too many file descriptors for TIPC: %zu", ancillaryFds->size());
93                     errno = EINVAL;
94                     return -1;
95                 }
96                 for (const auto& fdVariant : *ancillaryFds) {
97                     shms[shm_count++] = {std::visit([](const auto& fd) { return fd.get(); },
98                                                     fdVariant),
99                                          TRUSTY_SEND_SECURE_OR_SHARE};
100                 }
101             }
102 
103             auto ret = TEMP_FAILURE_RETRY(tipc_send(mSocket.fd.get(), iovs, niovs,
104                                                     (shm_count == 0) ? nullptr : shms, shm_count));
105             sentFds |= ret >= 0;
106             return ret;
107         };
108 
109         status_t status = interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, writeFn,
110                                                    "tipc_send", POLLOUT, altPoll);
111         return adjustStatus(status);
112     }
113 
interruptableReadFully(FdTrigger * fdTrigger,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> & altPoll,std::vector<std::variant<unique_fd,borrowed_fd>> *)114     status_t interruptableReadFully(
115             FdTrigger* fdTrigger, iovec* iovs, int niovs,
116             const std::optional<SmallFunction<status_t()>>& altPoll,
117             std::vector<std::variant<unique_fd, borrowed_fd>>* /*ancillaryFds*/) override {
118         auto readFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
119             // Fill the read buffer at most once per readFn call, then try to
120             // return as much of it as possible. If the input iovecs are spread
121             // across multiple messages that require multiple fillReadBuffer
122             // calls, we expect the caller to advance the iovecs past the first
123             // read and call readFn as many times as needed to get all the data
124             status_t ret = fillReadBuffer();
125             if (ret != OK) {
126                 // We need to emulate a Linux read call, which sets errno on
127                 // error and returns -1
128                 errno = -ret;
129                 return -1;
130             }
131 
132             ssize_t processSize = 0;
133             for (size_t i = 0; i < niovs && mReadBufferPos < mReadBufferSize; i++) {
134                 auto& iov = iovs[i];
135                 size_t numBytes = std::min(iov.iov_len, mReadBufferSize - mReadBufferPos);
136                 memcpy(iov.iov_base, mReadBuffer.get() + mReadBufferPos, numBytes);
137                 mReadBufferPos += numBytes;
138                 processSize += numBytes;
139             }
140 
141             return processSize;
142         };
143 
144         status_t status = interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, readFn, "read",
145                                                    POLLIN, altPoll);
146         return adjustStatus(status);
147     }
148 
isWaiting()149     bool isWaiting() override { return mSocket.isInPollingState(); }
150 
151 private:
adjustStatus(status_t status)152     status_t adjustStatus(status_t status) {
153         if (status == -ENOTCONN) {
154             // TIPC returns ENOTCONN on disconnect, but that's basically
155             // the same as DEAD_OBJECT and the latter is the common libbinder
156             // error code for dead connections
157             return DEAD_OBJECT;
158         }
159 
160         return status;
161     }
162 
fillReadBuffer()163     status_t fillReadBuffer() {
164         if (mReadBufferPos < mReadBufferSize) {
165             return OK;
166         }
167 
168         if (!mReadBuffer) {
169             // Guarantee at least kDefaultBufferSize bytes
170             mReadBufferCapacity = std::max(mReadBufferCapacity, kDefaultBufferSize);
171             mReadBuffer.reset(new (std::nothrow) uint8_t[mReadBufferCapacity]);
172             if (!mReadBuffer) {
173                 return NO_MEMORY;
174             }
175         }
176 
177         // Reset the size and position in case we have to exit with an error.
178         // After we read a message into the buffer, we update the size
179         // with the actual value.
180         mReadBufferPos = 0;
181         mReadBufferSize = 0;
182 
183         while (true) {
184             ssize_t processSize = TEMP_FAILURE_RETRY(
185                     read(mSocket.fd.get(), mReadBuffer.get(), mReadBufferCapacity));
186             if (processSize == 0) {
187                 return DEAD_OBJECT;
188             } else if (processSize < 0) {
189                 int savedErrno = errno;
190                 if (savedErrno == EMSGSIZE) {
191                     // Buffer was too small, double it and retry
192                     if (__builtin_mul_overflow(mReadBufferCapacity, 2, &mReadBufferCapacity)) {
193                         return NO_MEMORY;
194                     }
195                     mReadBuffer.reset(new (std::nothrow) uint8_t[mReadBufferCapacity]);
196                     if (!mReadBuffer) {
197                         return NO_MEMORY;
198                     }
199                     continue;
200                 } else {
201                     LOG_RPC_DETAIL("RpcTransport fillBuffer(): %s", strerror(savedErrno));
202                     return adjustStatus(-savedErrno);
203                 }
204             } else {
205                 mReadBufferSize = static_cast<size_t>(processSize);
206                 return OK;
207             }
208         }
209     }
210 
211     RpcTransportFd mSocket;
212 
213     // For now, we copy all the input data into a temporary buffer because
214     // we might get multiple interruptableReadFully calls per message, but
215     // the tipc device only allows one read call. We read every message into
216     // this temporary buffer, then return pieces of it from our method.
217     //
218     // The special transaction GET_MAX_THREADS takes 40 bytes, so the default
219     // size should start pretty high.
220     static constexpr size_t kDefaultBufferSize = 64;
221     std::unique_ptr<uint8_t[]> mReadBuffer;
222     size_t mReadBufferPos = 0;
223     size_t mReadBufferSize = 0;
224     size_t mReadBufferCapacity = 0;
225 };
226 
227 // RpcTransportCtx for Trusty.
228 class RpcTransportCtxTipcAndroid : public RpcTransportCtx {
229 public:
newTransport(android::RpcTransportFd fd,FdTrigger *) const230     std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd fd,
231                                                FdTrigger*) const override {
232         return std::make_unique<RpcTransportTipcAndroid>(std::move(fd));
233     }
getCertificate(RpcCertificateFormat) const234     std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
235 };
236 
newServerCtx() const237 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcAndroid::newServerCtx() const {
238     return std::make_unique<RpcTransportCtxTipcAndroid>();
239 }
240 
newClientCtx() const241 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcAndroid::newClientCtx() const {
242     return std::make_unique<RpcTransportCtxTipcAndroid>();
243 }
244 
toCString() const245 const char* RpcTransportCtxFactoryTipcAndroid::toCString() const {
246     return "trusty";
247 }
248 
make()249 std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcAndroid::make() {
250     return std::unique_ptr<RpcTransportCtxFactoryTipcAndroid>(
251             new RpcTransportCtxFactoryTipcAndroid());
252 }
253 
254 } // namespace android
255