diff options
| author | 2021-04-13 02:03:08 +0000 | |
|---|---|---|
| committer | 2021-04-13 23:32:01 +0000 | |
| commit | d47b32cdcde83fec09e76b2990945694a6d6477e (patch) | |
| tree | 9e1a218439e2fa593133bfca1b8c070f79b17c5f | |
| parent | eeb7b74c211555bf38f708f82ddbdcf5bd2a1ba6 (diff) | |
binder_parcel_fuzzer: fuzz RPC format
We'll need a separate fuzzer for the binder RPC wire protocol, but for
now we should fuzz the RPC wire format.
Bug: 182938024
Test: binderRpcTest
Test: binder_parcel_fuzzer
Change-Id: I82c4908529c3198104b43fdefb1e715a2be05797
| -rw-r--r-- | libs/binder/RpcConnection.cpp | 34 | ||||
| -rw-r--r-- | libs/binder/include/binder/Parcel.h | 8 | ||||
| -rw-r--r-- | libs/binder/include/binder/RpcConnection.h | 14 | ||||
| -rw-r--r-- | libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h | 7 | ||||
| -rw-r--r-- | libs/binder/tests/parcel_fuzzer/main.cpp | 16 | ||||
| -rw-r--r-- | libs/binder/tests/parcel_fuzzer/random_parcel.cpp | 5 |
6 files changed, 68 insertions, 16 deletions
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp index 1bf3d889a5..40331bc004 100644 --- a/libs/binder/RpcConnection.cpp +++ b/libs/binder/RpcConnection.cpp @@ -78,11 +78,11 @@ private: }; bool RpcConnection::setupUnixDomainServer(const char* path) { - return addServer(UnixSocketAddress(path)); + return setupSocketServer(UnixSocketAddress(path)); } bool RpcConnection::addUnixDomainClient(const char* path) { - return addClient(UnixSocketAddress(path)); + return addSocketClient(UnixSocketAddress(path)); } #ifdef __BIONIC__ @@ -110,15 +110,27 @@ bool RpcConnection::setupVsockServer(unsigned int port) { // realizing value w/ this type at compile time to avoid ubsan abort constexpr unsigned int kAnyCid = VMADDR_CID_ANY; - return addServer(VsockSocketAddress(kAnyCid, port)); + return setupSocketServer(VsockSocketAddress(kAnyCid, port)); } bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) { - return addClient(VsockSocketAddress(cid, port)); + return addSocketClient(VsockSocketAddress(cid, port)); } #endif // __BIONIC__ +bool RpcConnection::addNullDebuggingClient() { + unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC))); + + if (serverFd == -1) { + ALOGE("Could not connect to /dev/null: %s", strerror(errno)); + return false; + } + + addClient(std::move(serverFd)); + return true; +} + sp<IBinder> RpcConnection::getRootObject() { ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT); return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this)); @@ -179,7 +191,7 @@ wp<RpcServer> RpcConnection::server() { return mForServer; } -bool RpcConnection::addServer(const SocketAddress& addr) { +bool RpcConnection::setupSocketServer(const SocketAddress& addr) { LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server."); unique_fd serverFd( @@ -205,7 +217,7 @@ bool RpcConnection::addServer(const SocketAddress& addr) { return true; } -bool RpcConnection::addClient(const SocketAddress& addr) { +bool RpcConnection::addSocketClient(const SocketAddress& addr) { unique_fd serverFd( TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); if (serverFd == -1) { @@ -222,14 +234,18 @@ bool RpcConnection::addClient(const SocketAddress& addr) { LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get()); + addClient(std::move(serverFd)); + return true; +} + +void RpcConnection::addClient(unique_fd&& fd) { std::lock_guard<std::mutex> _l(mSocketMutex); sp<ConnectionSocket> connection = sp<ConnectionSocket>::make(); - connection->fd = std::move(serverFd); + connection->fd = std::move(fd); mClients.push_back(connection); - return true; } -void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) { +void RpcConnection::assignServerToThisThread(unique_fd&& fd) { std::lock_guard<std::mutex> _l(mSocketMutex); sp<ConnectionSocket> connection = sp<ConnectionSocket>::make(); connection->fd = std::move(fd); diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 211790d14c..957837233b 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -101,6 +101,10 @@ public: // is for an RPC transaction). void markForBinder(const sp<IBinder>& binder); + // Whenever possible, markForBinder should be preferred. This method is + // called automatically on reply Parcels for RPC transactions. + void markForRpc(const sp<RpcConnection>& connection); + // Whether this Parcel is written for RPC transactions (after calls to // markForBinder or markForRpc). bool isForRpc() const; @@ -536,10 +540,6 @@ private: const binder_size_t* objects, size_t objectsCount, release_func relFunc); - // Whenever possible, markForBinder should be preferred. This method is - // called automatically on reply Parcels for RPC transactions. - void markForRpc(const sp<RpcConnection>& connection); - status_t finishWrite(size_t len); void releaseObjects(); void acquireObjects(); diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h index efa922dbda..dba47b4d15 100644 --- a/libs/binder/include/binder/RpcConnection.h +++ b/libs/binder/include/binder/RpcConnection.h @@ -74,6 +74,15 @@ public: #endif // __BIONIC__ /** + * For debugging! + * + * Sets up an empty socket. All queries to this socket which require a + * response will never be satisfied. All data sent here will be + * unceremoniously cast down the bottomless pit, /dev/null. + */ + [[nodiscard]] bool addNullDebuggingClient(); + + /** * Query the other side of the connection for the root object hosted by that * process's RpcServer (if one exists) */ @@ -109,8 +118,9 @@ private: friend sp<RpcConnection>; RpcConnection(); - bool addServer(const SocketAddress& address); - bool addClient(const SocketAddress& address); + bool setupSocketServer(const SocketAddress& address); + bool addSocketClient(const SocketAddress& address); + void addClient(base::unique_fd&& fd); void assignServerToThisThread(base::unique_fd&& fd); struct ConnectionSocket : public RefBase { diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h index b92a6a9f8e..749bf212e6 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h @@ -20,5 +20,12 @@ #include <fuzzer/FuzzedDataProvider.h> namespace android { +/** + * Fill parcel data, including some random binder objects and FDs + */ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider); +/** + * Fill parcel data, but don't fill any objects. + */ +void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider); } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp index 78606ccd91..332e2ada52 100644 --- a/libs/binder/tests/parcel_fuzzer/main.cpp +++ b/libs/binder/tests/parcel_fuzzer/main.cpp @@ -23,6 +23,7 @@ #include <iostream> #include <android-base/logging.h> +#include <binder/RpcConnection.h> #include <fuzzbinder/random_parcel.h> #include <fuzzer/FuzzedDataProvider.h> @@ -32,6 +33,8 @@ #include <sys/time.h> using android::fillRandomParcel; +using android::RpcConnection; +using android::sp; void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) { // TODO: functionality to create random parcels for libhwbinder parcels @@ -56,7 +59,18 @@ void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads, provider.ConsumeIntegralInRange<size_t>(0, maxInstructions)); P p; - fillRandomParcel(&p, std::move(provider)); + if constexpr (std::is_same_v<P, android::Parcel>) { + if (provider.ConsumeBool()) { + auto connection = sp<RpcConnection>::make(); + CHECK(connection->addNullDebuggingClient()); + p.markForRpc(connection); + fillRandomParcelData(&p, std::move(provider)); + } else { + fillRandomParcel(&p, std::move(provider)); + } + } else { + fillRandomParcel(&p, std::move(provider)); + } // since we are only using a byte to index CHECK(reads.size() <= 255) << reads.size(); diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index 9ca4c8aca4..b045a22eff 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -75,4 +75,9 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) { } } +void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) { + std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(provider.remaining_bytes()); + CHECK(OK == p->write(data.data(), data.size())); +} + } // namespace android |