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

Commit ee04fa7a authored by Fabián Cañas's avatar Fabián Cañas Committed by Gerrit Code Review
Browse files

Merge "Add fuzz tests for binder RecordedTransaction"

parents ec7fa9d3 b0c5b1fd
Loading
Loading
Loading
Loading
+42 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
#include <android-base/unique_fd.h>
#include <binder/RecordedTransaction.h>
#include <sys/mman.h>
@@ -176,13 +177,33 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
    RecordedTransaction t;
    ChunkDescriptor chunk;
    const long pageSize = sysconf(_SC_PAGE_SIZE);
    struct stat fileStat;
    if (fstat(fd.get(), &fileStat) != 0) {
        LOG(ERROR) << "Unable to get file information";
        return std::nullopt;
    }

    off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR);
    if (fdCurrentPosition == -1) {
        LOG(ERROR) << "Invalid offset in file descriptor.";
        return std::nullopt;
    }
    do {
        if (fileStat.st_size < (fdCurrentPosition + (off_t)sizeof(ChunkDescriptor))) {
            LOG(ERROR) << "Not enough file remains to contain expected chunk descriptor";
            return std::nullopt;
        }
        transaction_checksum_t checksum = 0;
        if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) {
            LOG(ERROR) << "Failed to read chunk descriptor.";
            return std::nullopt;
        }
        off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR);

        fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR);
        if (fdCurrentPosition == -1) {
            LOG(ERROR) << "Invalid offset in file descriptor.";
            return std::nullopt;
        }
        off_t mmapPageAlignedStart = (fdCurrentPosition / pageSize) * pageSize;
        off_t mmapPayloadStartOffset = fdCurrentPosition - mmapPageAlignedStart;

@@ -194,14 +215,24 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
        size_t chunkPayloadSize =
                chunk.dataSize + PADDING8(chunk.dataSize) + sizeof(transaction_checksum_t);

        if (chunkPayloadSize > (size_t)(fileStat.st_size - fdCurrentPosition)) {
            LOG(ERROR) << "Chunk payload exceeds remaining file size.";
            return std::nullopt;
        }

        if (PADDING8(chunkPayloadSize) != 0) {
            LOG(ERROR) << "Invalid chunk size, not aligned " << chunkPayloadSize;
            return std::nullopt;
        }

        transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>(
                mmap(NULL, chunkPayloadSize + mmapPayloadStartOffset, PROT_READ, MAP_SHARED,
                     fd.get(), mmapPageAlignedStart));
        size_t memoryMappedSize = chunkPayloadSize + mmapPayloadStartOffset;
        void* mappedMemory =
                mmap(NULL, memoryMappedSize, PROT_READ, MAP_SHARED, fd.get(), mmapPageAlignedStart);
        auto mmap_guard = android::base::make_scope_guard(
                [mappedMemory, memoryMappedSize] { munmap(mappedMemory, memoryMappedSize); });

        transaction_checksum_t* payloadMap =
                reinterpret_cast<transaction_checksum_t*>(mappedMemory);
        payloadMap += mmapPayloadStartOffset /
                sizeof(transaction_checksum_t); // Skip chunk descriptor and required mmap
                                                // page-alignment
@@ -218,7 +249,12 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
            LOG(ERROR) << "Checksum failed.";
            return std::nullopt;
        }
        lseek(fd.get(), chunkPayloadSize, SEEK_CUR);

        fdCurrentPosition = lseek(fd.get(), chunkPayloadSize, SEEK_CUR);
        if (fdCurrentPosition == -1) {
            LOG(ERROR) << "Invalid offset in file descriptor.";
            return std::nullopt;
        }

        switch (chunk.chunkType) {
            case HEADER_CHUNK: {
@@ -255,7 +291,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd
                break;
            default:
                LOG(INFO) << "Unrecognized chunk.";
                continue;
                break;
        }
    } while (chunk.chunkType != END_CHUNK);

+39 −0
Original line number Diff line number Diff line
@@ -104,3 +104,42 @@ cc_fuzz {
    defaults: ["binder_fuzz_defaults"],
    srcs: ["MemoryDealerFuzz.cpp"],
}

cc_fuzz {
    name: "binder_recordedTransactionFileFuzz",
    defaults: ["binder_fuzz_defaults"],
    srcs: ["RecordedTransactionFileFuzz.cpp"],
    corpus: [
        "recorded_transaction_corpus/*",
    ],
}

cc_fuzz {
    name: "binder_recordedTransactionFuzz",
    defaults: ["binder_fuzz_defaults"],
    srcs: ["RecordedTransactionFuzz.cpp"],
    target: {
        android: {
            shared_libs: [
                "libcutils",
                "libutils",
                "libbase",
                "libbinder",
            ],
            static_libs: ["libbinder_random_parcel"],
        },
        host: {
            static_libs: [
                "libcutils",
                "liblog",
                "libutils",
                "libbase",
                "libbinder",
                "libbinder_random_parcel",
            ],
        },
        darwin: {
            enabled: false,
        },
    },
}
+45 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 <android-base/macros.h>
#include <binder/RecordedTransaction.h>
#include <filesystem>

#include "fuzzer/FuzzedDataProvider.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    std::FILE* intermediateFile = std::tmpfile();
    fwrite(data, sizeof(uint8_t), size, intermediateFile);
    rewind(intermediateFile);
    int fileNumber = fileno(intermediateFile);

    android::base::unique_fd fd(fileNumber);

    auto transaction = android::binder::debug::RecordedTransaction::fromFile(fd);

    std::fclose(intermediateFile);

    if (transaction.has_value()) {
        intermediateFile = std::tmpfile();

        android::base::unique_fd fdForWriting(fileno(intermediateFile));
        auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting);

        std::fclose(intermediateFile);
    }

    return 0;
}
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 <android-base/macros.h>
#include <binder/RecordedTransaction.h>
#include <fuzzbinder/random_parcel.h>
#include <filesystem>
#include <string>

#include "fuzzer/FuzzedDataProvider.h"

using android::fillRandomParcel;

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    FuzzedDataProvider provider = FuzzedDataProvider(data, size);

    android::String16 interfaceName =
            android::String16(provider.ConsumeRandomLengthString().c_str());

    uint32_t code = provider.ConsumeIntegral<uint32_t>();
    uint32_t flags = provider.ConsumeIntegral<uint32_t>();
    time_t sec = provider.ConsumeIntegral<time_t>();
    long nsec = provider.ConsumeIntegral<long>();
    timespec timestamp = {.tv_sec = sec, .tv_nsec = nsec};
    android::status_t transactionStatus = provider.ConsumeIntegral<android::status_t>();

    std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>(
            provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));

    // same options so that FDs and binders could be shared in both Parcels
    android::RandomParcelOptions options;

    android::Parcel p0, p1;
    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()), &options);
    fillRandomParcel(&p1, std::move(provider), &options);

    auto transaction =
            android::binder::debug::RecordedTransaction::fromDetails(interfaceName, code, flags,
                                                                     timestamp, p0, p1,
                                                                     transactionStatus);

    if (transaction.has_value()) {
        std::FILE* intermediateFile = std::tmpfile();
        android::base::unique_fd fdForWriting(fileno(intermediateFile));
        auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting);

        std::fclose(intermediateFile);
    }

    return 0;
}
+928 B

File added.

No diff preview for this file type.

Loading