Loading libs/binder/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,6 @@ cc_library { "ParcelFileDescriptor.cpp", "PersistableBundle.cpp", "ProcessState.cpp", "RpcAddress.cpp", "RpcSession.cpp", "RpcServer.cpp", "RpcState.cpp", Loading libs/binder/BpBinder.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -156,7 +156,7 @@ sp<BpBinder> BpBinder::create(int32_t handle) { return sp<BpBinder>::make(BinderHandle{handle}, trackedUid); } sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, const RpcAddress& address) { sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, uint64_t address) { LOG_ALWAYS_FATAL_IF(session == nullptr, "BpBinder::create null session"); // These are not currently tracked, since there is no UID or other Loading Loading @@ -193,7 +193,7 @@ bool BpBinder::isRpcBinder() const { return std::holds_alternative<RpcHandle>(mHandle); } const RpcAddress& BpBinder::rpcAddress() const { uint64_t BpBinder::rpcAddress() const { return std::get<RpcHandle>(mHandle).address; } Loading libs/binder/Parcel.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -205,11 +205,11 @@ status_t Parcel::flattenBinder(const sp<IBinder>& binder) { if (binder) { status_t status = writeInt32(1); // non-null if (status != OK) return status; RpcAddress address = RpcAddress::zero(); uint64_t address; // TODO(b/167966510): need to undo this if the Parcel is not sent status = mSession->state()->onBinderLeaving(mSession, binder, &address); if (status != OK) return status; status = address.writeToParcel(this); status = writeUint64(address); if (status != OK) return status; } else { status_t status = writeInt32(0); // null Loading Loading @@ -279,15 +279,15 @@ status_t Parcel::unflattenBinder(sp<IBinder>* out) const if (isForRpc()) { LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel"); int32_t isNull; status_t status = readInt32(&isNull); int32_t isPresent; status_t status = readInt32(&isPresent); if (status != OK) return status; sp<IBinder> binder; if (isNull & 1) { auto addr = RpcAddress::zero(); if (status_t status = addr.readFromParcel(*this); status != OK) return status; if (isPresent & 1) { uint64_t addr; if (status_t status = readUint64(&addr); status != OK) return status; if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder); status != OK) return status; Loading libs/binder/RpcAddress.cppdeleted 100644 → 0 +0 −112 Original line number Diff line number Diff line /* * Copyright (C) 2020 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. */ #include <binder/RpcAddress.h> #include <android-base/hex.h> #include <binder/Parcel.h> #include "Debug.h" #include "RpcState.h" #include "RpcWireFormat.h" namespace android { RpcAddress RpcAddress::zero() { return RpcAddress(); } bool RpcAddress::isZero() const { RpcWireAddress ZERO{.options = 0}; return memcmp(mRawAddr.get(), &ZERO, sizeof(RpcWireAddress)) == 0; } static void ReadRandomBytes(uint8_t* buf, size_t len) { int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); if (fd == -1) { ALOGE("%s: cannot read /dev/urandom", __func__); return; } size_t n; while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) { len -= n; buf += n; } if (len > 0) { ALOGW("%s: there are %d bytes skipped", __func__, (int)len); } close(fd); } RpcAddress RpcAddress::random(bool forServer) { // The remainder of this header acts as reserved space for different kinds // of binder objects. uint64_t options = RPC_WIRE_ADDRESS_OPTION_CREATED; // servers and clients allocate addresses independently, so this bit can // tell you where an address originates if (forServer) options |= RPC_WIRE_ADDRESS_OPTION_FOR_SERVER; RpcAddress ret; RpcWireAddress* raw = ret.mRawAddr.get(); raw->options = options; ReadRandomBytes(raw->address, sizeof(raw->address)); LOG_RPC_DETAIL("Creating new address: %s", ret.toString().c_str()); return ret; } bool RpcAddress::isForServer() const { return mRawAddr.get()->options & RPC_WIRE_ADDRESS_OPTION_FOR_SERVER; } bool RpcAddress::isRecognizedType() const { uint64_t allKnownOptions = RPC_WIRE_ADDRESS_OPTION_CREATED | RPC_WIRE_ADDRESS_OPTION_FOR_SERVER; return (mRawAddr.get()->options & ~allKnownOptions) == 0; } RpcAddress RpcAddress::fromRawEmbedded(const RpcWireAddress* raw) { RpcAddress addr; memcpy(addr.mRawAddr.get(), raw, sizeof(RpcWireAddress)); return addr; } const RpcWireAddress& RpcAddress::viewRawEmbedded() const { return *mRawAddr.get(); } bool RpcAddress::operator<(const RpcAddress& rhs) const { return std::memcmp(mRawAddr.get(), rhs.mRawAddr.get(), sizeof(RpcWireAddress)) < 0; } std::string RpcAddress::toString() const { return base::HexString(mRawAddr.get(), sizeof(RpcWireAddress)); } status_t RpcAddress::writeToParcel(Parcel* parcel) const { return parcel->write(mRawAddr.get(), sizeof(RpcWireAddress)); } status_t RpcAddress::readFromParcel(const Parcel& parcel) { return parcel.read(mRawAddr.get(), sizeof(RpcWireAddress)); } RpcAddress::~RpcAddress() {} RpcAddress::RpcAddress() : mRawAddr(std::make_shared<RpcWireAddress>()) {} } // namespace android libs/binder/RpcServer.cpp +38 −12 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <thread> #include <vector> #include <android-base/file.h> #include <android-base/hex.h> #include <android-base/scopeguard.h> #include <binder/Parcel.h> #include <binder/RpcServer.h> Loading Loading @@ -281,17 +283,29 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie } } std::vector<uint8_t> sessionId; if (status == OK) { if (header.sessionIdSize > 0) { sessionId.resize(header.sessionIdSize); status = client->interruptableReadFully(server->mShutdownTrigger.get(), sessionId.data(), sessionId.size()); if (status != OK) { ALOGE("Failed to read session ID for client connecting to RPC server: %s", statusToString(status).c_str()); // still need to cleanup before we can return } } } bool incoming = false; uint32_t protocolVersion = 0; RpcAddress sessionId = RpcAddress::zero(); bool requestingNewSession = false; if (status == OK) { incoming = header.options & RPC_CONNECTION_OPTION_INCOMING; protocolVersion = std::min(header.version, server->mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION)); sessionId = RpcAddress::fromRawEmbedded(&header.sessionId); requestingNewSession = sessionId.isZero(); requestingNewSession = sessionId.empty(); if (requestingNewSession) { RpcNewSessionResponse response{ Loading Loading @@ -333,15 +347,26 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie return; } // Uniquely identify session at the application layer. Even if a // client/server use the same certificates, if they create multiple // sessions, we still want to distinguish between them. constexpr size_t kSessionIdSize = 32; sessionId.resize(kSessionIdSize); size_t tries = 0; do { // don't block if there is some entropy issue if (tries++ > 5) { ALOGE("Cannot find new address: %s", sessionId.toString().c_str()); ALOGE("Cannot find new address: %s", base::HexString(sessionId.data(), sessionId.size()).c_str()); return; } sessionId = RpcAddress::random(true /*forServer*/); base::unique_fd fd(TEMP_FAILURE_RETRY( open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW))); if (!base::ReadFully(fd, sessionId.data(), sessionId.size())) { ALOGE("Could not read from /dev/urandom to create session ID"); return; } } while (server->mSessions.end() != server->mSessions.find(sessionId)); session = RpcSession::make(); Loading @@ -361,7 +386,7 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie auto it = server->mSessions.find(sessionId); if (it == server->mSessions.end()) { ALOGE("Cannot add thread, no record of session with ID %s", sessionId.toString().c_str()); base::HexString(sessionId.data(), sessionId.size()).c_str()); return; } session = it->second; Loading Loading @@ -423,16 +448,17 @@ status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) { } void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) { auto id = session->mId; LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID"); LOG_RPC_DETAIL("Dropping session with address %s", id->toString().c_str()); const std::vector<uint8_t>& id = session->mId; LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID"); LOG_RPC_DETAIL("Dropping session with address %s", base::HexString(id.data(), id.size()).c_str()); std::lock_guard<std::mutex> _l(mLock); auto it = mSessions.find(*id); auto it = mSessions.find(id); LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s", id->toString().c_str()); base::HexString(id.data(), id.size()).c_str()); LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %s", id->toString().c_str()); base::HexString(id.data(), id.size()).c_str()); (void)mSessions.erase(it); } Loading Loading
libs/binder/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,6 @@ cc_library { "ParcelFileDescriptor.cpp", "PersistableBundle.cpp", "ProcessState.cpp", "RpcAddress.cpp", "RpcSession.cpp", "RpcServer.cpp", "RpcState.cpp", Loading
libs/binder/BpBinder.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -156,7 +156,7 @@ sp<BpBinder> BpBinder::create(int32_t handle) { return sp<BpBinder>::make(BinderHandle{handle}, trackedUid); } sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, const RpcAddress& address) { sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, uint64_t address) { LOG_ALWAYS_FATAL_IF(session == nullptr, "BpBinder::create null session"); // These are not currently tracked, since there is no UID or other Loading Loading @@ -193,7 +193,7 @@ bool BpBinder::isRpcBinder() const { return std::holds_alternative<RpcHandle>(mHandle); } const RpcAddress& BpBinder::rpcAddress() const { uint64_t BpBinder::rpcAddress() const { return std::get<RpcHandle>(mHandle).address; } Loading
libs/binder/Parcel.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -205,11 +205,11 @@ status_t Parcel::flattenBinder(const sp<IBinder>& binder) { if (binder) { status_t status = writeInt32(1); // non-null if (status != OK) return status; RpcAddress address = RpcAddress::zero(); uint64_t address; // TODO(b/167966510): need to undo this if the Parcel is not sent status = mSession->state()->onBinderLeaving(mSession, binder, &address); if (status != OK) return status; status = address.writeToParcel(this); status = writeUint64(address); if (status != OK) return status; } else { status_t status = writeInt32(0); // null Loading Loading @@ -279,15 +279,15 @@ status_t Parcel::unflattenBinder(sp<IBinder>* out) const if (isForRpc()) { LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel"); int32_t isNull; status_t status = readInt32(&isNull); int32_t isPresent; status_t status = readInt32(&isPresent); if (status != OK) return status; sp<IBinder> binder; if (isNull & 1) { auto addr = RpcAddress::zero(); if (status_t status = addr.readFromParcel(*this); status != OK) return status; if (isPresent & 1) { uint64_t addr; if (status_t status = readUint64(&addr); status != OK) return status; if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder); status != OK) return status; Loading
libs/binder/RpcAddress.cppdeleted 100644 → 0 +0 −112 Original line number Diff line number Diff line /* * Copyright (C) 2020 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. */ #include <binder/RpcAddress.h> #include <android-base/hex.h> #include <binder/Parcel.h> #include "Debug.h" #include "RpcState.h" #include "RpcWireFormat.h" namespace android { RpcAddress RpcAddress::zero() { return RpcAddress(); } bool RpcAddress::isZero() const { RpcWireAddress ZERO{.options = 0}; return memcmp(mRawAddr.get(), &ZERO, sizeof(RpcWireAddress)) == 0; } static void ReadRandomBytes(uint8_t* buf, size_t len) { int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); if (fd == -1) { ALOGE("%s: cannot read /dev/urandom", __func__); return; } size_t n; while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) { len -= n; buf += n; } if (len > 0) { ALOGW("%s: there are %d bytes skipped", __func__, (int)len); } close(fd); } RpcAddress RpcAddress::random(bool forServer) { // The remainder of this header acts as reserved space for different kinds // of binder objects. uint64_t options = RPC_WIRE_ADDRESS_OPTION_CREATED; // servers and clients allocate addresses independently, so this bit can // tell you where an address originates if (forServer) options |= RPC_WIRE_ADDRESS_OPTION_FOR_SERVER; RpcAddress ret; RpcWireAddress* raw = ret.mRawAddr.get(); raw->options = options; ReadRandomBytes(raw->address, sizeof(raw->address)); LOG_RPC_DETAIL("Creating new address: %s", ret.toString().c_str()); return ret; } bool RpcAddress::isForServer() const { return mRawAddr.get()->options & RPC_WIRE_ADDRESS_OPTION_FOR_SERVER; } bool RpcAddress::isRecognizedType() const { uint64_t allKnownOptions = RPC_WIRE_ADDRESS_OPTION_CREATED | RPC_WIRE_ADDRESS_OPTION_FOR_SERVER; return (mRawAddr.get()->options & ~allKnownOptions) == 0; } RpcAddress RpcAddress::fromRawEmbedded(const RpcWireAddress* raw) { RpcAddress addr; memcpy(addr.mRawAddr.get(), raw, sizeof(RpcWireAddress)); return addr; } const RpcWireAddress& RpcAddress::viewRawEmbedded() const { return *mRawAddr.get(); } bool RpcAddress::operator<(const RpcAddress& rhs) const { return std::memcmp(mRawAddr.get(), rhs.mRawAddr.get(), sizeof(RpcWireAddress)) < 0; } std::string RpcAddress::toString() const { return base::HexString(mRawAddr.get(), sizeof(RpcWireAddress)); } status_t RpcAddress::writeToParcel(Parcel* parcel) const { return parcel->write(mRawAddr.get(), sizeof(RpcWireAddress)); } status_t RpcAddress::readFromParcel(const Parcel& parcel) { return parcel.read(mRawAddr.get(), sizeof(RpcWireAddress)); } RpcAddress::~RpcAddress() {} RpcAddress::RpcAddress() : mRawAddr(std::make_shared<RpcWireAddress>()) {} } // namespace android
libs/binder/RpcServer.cpp +38 −12 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <thread> #include <vector> #include <android-base/file.h> #include <android-base/hex.h> #include <android-base/scopeguard.h> #include <binder/Parcel.h> #include <binder/RpcServer.h> Loading Loading @@ -281,17 +283,29 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie } } std::vector<uint8_t> sessionId; if (status == OK) { if (header.sessionIdSize > 0) { sessionId.resize(header.sessionIdSize); status = client->interruptableReadFully(server->mShutdownTrigger.get(), sessionId.data(), sessionId.size()); if (status != OK) { ALOGE("Failed to read session ID for client connecting to RPC server: %s", statusToString(status).c_str()); // still need to cleanup before we can return } } } bool incoming = false; uint32_t protocolVersion = 0; RpcAddress sessionId = RpcAddress::zero(); bool requestingNewSession = false; if (status == OK) { incoming = header.options & RPC_CONNECTION_OPTION_INCOMING; protocolVersion = std::min(header.version, server->mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION)); sessionId = RpcAddress::fromRawEmbedded(&header.sessionId); requestingNewSession = sessionId.isZero(); requestingNewSession = sessionId.empty(); if (requestingNewSession) { RpcNewSessionResponse response{ Loading Loading @@ -333,15 +347,26 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie return; } // Uniquely identify session at the application layer. Even if a // client/server use the same certificates, if they create multiple // sessions, we still want to distinguish between them. constexpr size_t kSessionIdSize = 32; sessionId.resize(kSessionIdSize); size_t tries = 0; do { // don't block if there is some entropy issue if (tries++ > 5) { ALOGE("Cannot find new address: %s", sessionId.toString().c_str()); ALOGE("Cannot find new address: %s", base::HexString(sessionId.data(), sessionId.size()).c_str()); return; } sessionId = RpcAddress::random(true /*forServer*/); base::unique_fd fd(TEMP_FAILURE_RETRY( open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW))); if (!base::ReadFully(fd, sessionId.data(), sessionId.size())) { ALOGE("Could not read from /dev/urandom to create session ID"); return; } } while (server->mSessions.end() != server->mSessions.find(sessionId)); session = RpcSession::make(); Loading @@ -361,7 +386,7 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie auto it = server->mSessions.find(sessionId); if (it == server->mSessions.end()) { ALOGE("Cannot add thread, no record of session with ID %s", sessionId.toString().c_str()); base::HexString(sessionId.data(), sessionId.size()).c_str()); return; } session = it->second; Loading Loading @@ -423,16 +448,17 @@ status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) { } void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) { auto id = session->mId; LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID"); LOG_RPC_DETAIL("Dropping session with address %s", id->toString().c_str()); const std::vector<uint8_t>& id = session->mId; LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID"); LOG_RPC_DETAIL("Dropping session with address %s", base::HexString(id.data(), id.size()).c_str()); std::lock_guard<std::mutex> _l(mLock); auto it = mSessions.find(*id); auto it = mSessions.find(id); LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s", id->toString().c_str()); base::HexString(id.data(), id.size()).c_str()); LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %s", id->toString().c_str()); base::HexString(id.data(), id.size()).c_str()); (void)mSessions.erase(it); } Loading