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