summaryrefslogtreecommitdiff
path: root/libs/binder/trusty/RpcServerTrusty.cpp
blob: 17919c2a25539de1209fb1a7d8344b053423f092 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "RpcServerTrusty"

#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <binder/RpcServerTrusty.h>
#include <binder/RpcThreads.h>
#include <binder/RpcTransportTipcTrusty.h>
#include <log/log.h>

#include "../FdTrigger.h"
#include "../RpcState.h"
#include "TrustyStatus.h"

using android::binder::unique_fd;

namespace android {

sp<RpcServerTrusty> RpcServerTrusty::make(
        tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl,
        size_t msgMaxSize, std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
    // Default is without TLS.
    if (rpcTransportCtxFactory == nullptr)
        rpcTransportCtxFactory = RpcTransportCtxFactoryTipcTrusty::make();
    auto ctx = rpcTransportCtxFactory->newServerCtx();
    if (ctx == nullptr) {
        ALOGE("Failed to create RpcServerTrusty: can't create server context");
        return nullptr;
    }

    auto srv = sp<RpcServerTrusty>::make(std::move(ctx), std::move(portName), std::move(portAcl),
                                         msgMaxSize);
    if (srv == nullptr) {
        ALOGE("Failed to create RpcServerTrusty: can't create server object");
        return nullptr;
    }

    int rc = tipc_add_service(handleSet, &srv->mTipcPort, 1, 0, &kTipcOps);
    if (rc != NO_ERROR) {
        ALOGE("Failed to create RpcServerTrusty: can't add service: %d", rc);
        return nullptr;
    }
    return srv;
}

RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName,
                                 std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize)
      : mRpcServer(makeRpcServer(std::move(ctx))),
        mPortName(std::move(portName)),
        mPortAcl(std::move(portAcl)) {
    mTipcPort.name = mPortName.c_str();
    mTipcPort.msg_max_size = msgMaxSize;
    mTipcPort.msg_queue_len = 6; // Three each way
    mTipcPort.priv = this;

    if (mPortAcl) {
        // Initialize the array of pointers to uuids.
        // The pointers in mUuidPtrs should stay valid across moves of
        // RpcServerTrusty (the addresses of a std::vector's elements
        // shouldn't change when the vector is moved), but would be invalidated
        // by a copy which is why we disable the copy constructor and assignment
        // operator for RpcServerTrusty.
        auto numUuids = mPortAcl->uuids.size();
        mUuidPtrs.resize(numUuids);
        for (size_t i = 0; i < numUuids; i++) {
            mUuidPtrs[i] = &mPortAcl->uuids[i];
        }

        // Copy the contents of portAcl into the tipc_port_acl structure that we
        // pass to tipc_add_service
        mTipcPortAcl.flags = mPortAcl->flags;
        mTipcPortAcl.uuid_num = numUuids;
        mTipcPortAcl.uuids = mUuidPtrs.data();
        mTipcPortAcl.extra_data = mPortAcl->extraData;

        mTipcPort.acl = &mTipcPortAcl;
    } else {
        mTipcPort.acl = nullptr;
    }
}

int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer,
                                   void** ctx_p) {
    auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv));
    return handleConnectInternal(server->mRpcServer.get(), chan, peer, ctx_p);
}

int RpcServerTrusty::handleConnectInternal(RpcServer* rpcServer, handle_t chan, const uuid* peer,
                                           void** ctx_p) {
    rpcServer->mShutdownTrigger = FdTrigger::make();
    rpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread();

    int rc = NO_ERROR;
    auto joinFn = [&](sp<RpcSession>&& session, RpcSession::PreJoinSetupResult&& result) {
        if (result.status != OK) {
            rc = statusToTrusty(result.status);
            return;
        }

        /* Save the session and connection for the other callbacks */
        auto* channelContext = new (std::nothrow) ChannelContext;
        if (channelContext == nullptr) {
            rc = ERR_NO_MEMORY;
            return;
        }

        channelContext->session = std::move(session);
        channelContext->connection = std::move(result.connection);

        *ctx_p = channelContext;
    };

    // We need to duplicate the channel handle here because the tipc library
    // owns the original handle and closes is automatically on channel cleanup.
    // We use dup() because Trusty does not have fcntl().
    // NOLINTNEXTLINE(android-cloexec-dup)
    handle_t chanDup = dup(chan);
    if (chanDup < 0) {
        return chanDup;
    }
    unique_fd clientFd(chanDup);
    android::RpcTransportFd transportFd(std::move(clientFd));

    std::array<uint8_t, RpcServer::kRpcAddressSize> addr;
    constexpr size_t addrLen = sizeof(*peer);
    memcpy(addr.data(), peer, addrLen);
    RpcServer::establishConnection(sp<RpcServer>::fromExisting(rpcServer), std::move(transportFd),
                                   addr, addrLen, joinFn);

    return rc;
}

int RpcServerTrusty::handleMessage(const tipc_port* /*port*/, handle_t /*chan*/, void* ctx) {
    return handleMessageInternal(ctx);
}

int RpcServerTrusty::handleMessageInternal(void* ctx) {
    auto* channelContext = reinterpret_cast<ChannelContext*>(ctx);
    LOG_ALWAYS_FATAL_IF(channelContext == nullptr,
                        "bad state: message received on uninitialized channel");

    auto& session = channelContext->session;
    auto& connection = channelContext->connection;
    status_t status =
            session->state()->drainCommands(connection, session, RpcState::CommandType::ANY);
    if (status != OK) {
        LOG_RPC_DETAIL("Binder connection thread closing w/ status %s",
                       statusToString(status).c_str());
    }

    return NO_ERROR;
}

void RpcServerTrusty::handleDisconnect(const tipc_port* /*port*/, handle_t /*chan*/, void* ctx) {
    return handleDisconnectInternal(ctx);
}

void RpcServerTrusty::handleDisconnectInternal(void* ctx) {
    auto* channelContext = reinterpret_cast<ChannelContext*>(ctx);
    if (channelContext == nullptr) {
        // Connections marked "incoming" (outgoing from the server's side)
        // do not have a valid channel context because joinFn does not get
        // called for them. We ignore them here.
        return;
    }

    auto& session = channelContext->session;
    (void)session->shutdownAndWait(false);
}

void RpcServerTrusty::handleChannelCleanup(void* ctx) {
    auto* channelContext = reinterpret_cast<ChannelContext*>(ctx);
    if (channelContext == nullptr) {
        return;
    }

    auto& session = channelContext->session;
    auto& connection = channelContext->connection;
    LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
                        "bad state: connection object guaranteed to be in list");

    delete channelContext;
}

} // namespace android