Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d47b32cd authored by Steven Moreland's avatar Steven Moreland
Browse files

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
parent eeb7b74c
Loading
Loading
Loading
Loading
+25 −9
Original line number Original line Diff line number Diff line
@@ -78,11 +78,11 @@ private:
};
};


bool RpcConnection::setupUnixDomainServer(const char* path) {
bool RpcConnection::setupUnixDomainServer(const char* path) {
    return addServer(UnixSocketAddress(path));
    return setupSocketServer(UnixSocketAddress(path));
}
}


bool RpcConnection::addUnixDomainClient(const char* path) {
bool RpcConnection::addUnixDomainClient(const char* path) {
    return addClient(UnixSocketAddress(path));
    return addSocketClient(UnixSocketAddress(path));
}
}


#ifdef __BIONIC__
#ifdef __BIONIC__
@@ -110,15 +110,27 @@ bool RpcConnection::setupVsockServer(unsigned int port) {
    // realizing value w/ this type at compile time to avoid ubsan abort
    // realizing value w/ this type at compile time to avoid ubsan abort
    constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
    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) {
bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) {
    return addClient(VsockSocketAddress(cid, port));
    return addSocketClient(VsockSocketAddress(cid, port));
}
}


#endif // __BIONIC__
#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() {
sp<IBinder> RpcConnection::getRootObject() {
    ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
    ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
    return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this));
    return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this));
@@ -179,7 +191,7 @@ wp<RpcServer> RpcConnection::server() {
    return mForServer;
    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.");
    LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");


    unique_fd serverFd(
    unique_fd serverFd(
@@ -205,7 +217,7 @@ bool RpcConnection::addServer(const SocketAddress& addr) {
    return true;
    return true;
}
}


bool RpcConnection::addClient(const SocketAddress& addr) {
bool RpcConnection::addSocketClient(const SocketAddress& addr) {
    unique_fd serverFd(
    unique_fd serverFd(
            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
    if (serverFd == -1) {
    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());
    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);
    std::lock_guard<std::mutex> _l(mSocketMutex);
    sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
    sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
    connection->fd = std::move(serverFd);
    connection->fd = std::move(fd);
    mClients.push_back(connection);
    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);
    std::lock_guard<std::mutex> _l(mSocketMutex);
    sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
    sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
    connection->fd = std::move(fd);
    connection->fd = std::move(fd);
+4 −4
Original line number Original line Diff line number Diff line
@@ -101,6 +101,10 @@ public:
    // is for an RPC transaction).
    // is for an RPC transaction).
    void markForBinder(const sp<IBinder>& binder);
    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
    // Whether this Parcel is written for RPC transactions (after calls to
    // markForBinder or markForRpc).
    // markForBinder or markForRpc).
    bool isForRpc() const;
    bool isForRpc() const;
@@ -536,10 +540,6 @@ private:
                                            const binder_size_t* objects, size_t objectsCount,
                                            const binder_size_t* objects, size_t objectsCount,
                                            release_func relFunc);
                                            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);
    status_t            finishWrite(size_t len);
    void                releaseObjects();
    void                releaseObjects();
    void                acquireObjects();
    void                acquireObjects();
+12 −2
Original line number Original line Diff line number Diff line
@@ -73,6 +73,15 @@ public:
    [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port);
    [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port);
#endif // __BIONIC__
#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
     * Query the other side of the connection for the root object hosted by that
     * process's RpcServer (if one exists)
     * process's RpcServer (if one exists)
@@ -109,8 +118,9 @@ private:
    friend sp<RpcConnection>;
    friend sp<RpcConnection>;
    RpcConnection();
    RpcConnection();


    bool addServer(const SocketAddress& address);
    bool setupSocketServer(const SocketAddress& address);
    bool addClient(const SocketAddress& address);
    bool addSocketClient(const SocketAddress& address);
    void addClient(base::unique_fd&& fd);
    void assignServerToThisThread(base::unique_fd&& fd);
    void assignServerToThisThread(base::unique_fd&& fd);


    struct ConnectionSocket : public RefBase {
    struct ConnectionSocket : public RefBase {
+7 −0
Original line number Original line Diff line number Diff line
@@ -20,5 +20,12 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <fuzzer/FuzzedDataProvider.h>


namespace android {
namespace android {
/**
 * Fill parcel data, including some random binder objects and FDs
 */
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
/**
 * Fill parcel data, but don't fill any objects.
 */
void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider);
} // namespace android
} // namespace android
+15 −1
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include <iostream>
#include <iostream>


#include <android-base/logging.h>
#include <android-base/logging.h>
#include <binder/RpcConnection.h>
#include <fuzzbinder/random_parcel.h>
#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <fuzzer/FuzzedDataProvider.h>


@@ -32,6 +33,8 @@
#include <sys/time.h>
#include <sys/time.h>


using android::fillRandomParcel;
using android::fillRandomParcel;
using android::RpcConnection;
using android::sp;


void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
    // TODO: functionality to create random parcels for libhwbinder parcels
    // 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));
            provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));


    P p;
    P p;
    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));
            fillRandomParcel(&p, std::move(provider));
        }
    } else {
        fillRandomParcel(&p, std::move(provider));
    }


    // since we are only using a byte to index
    // since we are only using a byte to index
    CHECK(reads.size() <= 255) << reads.size();
    CHECK(reads.size() <= 255) << reads.size();
Loading