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