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
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index 1bf3d88..40331bc 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -78,11 +78,11 @@
};
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 @@
// 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 @@
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 @@
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 @@
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
- std::lock_guard<std::mutex> _l(mSocketMutex);
- sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
- connection->fd = std::move(serverFd);
- mClients.push_back(connection);
+ addClient(std::move(serverFd));
return true;
}
-void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) {
+void RpcConnection::addClient(unique_fd&& fd) {
+ std::lock_guard<std::mutex> _l(mSocketMutex);
+ sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
+ connection->fd = std::move(fd);
+ mClients.push_back(connection);
+}
+
+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 211790d..9578372 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -101,6 +101,10 @@
// 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 @@
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 efa922d..dba47b4 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -74,6 +74,15 @@
#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 @@
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 b92a6a9..749bf21 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 78606cc..332e2ad 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 @@
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 9ca4c8a..b045a22 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -75,4 +75,9 @@
}
}
+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