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

Commit adea7159 authored by Pawan Wagh's avatar Pawan Wagh
Browse files

Adding a separate lib for random seed generation

Adding a lib which produces fuzzer seeds from recorded transaction.
It includes utility which reverses bytes from given value based
on the ranges provided.

Test: m libbinder_random_parcel_seeds
Bug: 278975837
Change-Id: Ic6f27b4d8eec6329a9437af9a8ec217c76fbef19
parent 1411c396
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -104,3 +104,28 @@ cc_library_static {
    local_include_dirs: ["include_random_parcel"],
    export_include_dirs: ["include_random_parcel"],
}

cc_library {
    name: "libbinder_random_parcel_seeds",
    host_supported: true,
    vendor_available: true,
    target: {
        darwin: {
            enabled: false,
        },
    },
    srcs: [
        "random_parcel_seeds.cpp",
    ],
    shared_libs: [
        "libbase",
        "libbinder",
        "libbinder_ndk",
        "libcutils",
        "libutils",
    ],
    local_include_dirs: [
        "include_random_parcel_seeds",
    ],
    export_include_dirs: ["include_random_parcel_seeds"],
}
+47 −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/file.h>
#include <android-base/hex.h>
#include <android-base/logging.h>

#include <binder/Binder.h>
#include <binder/Parcel.h>
#include <binder/RecordedTransaction.h>

#include <private/android_filesystem_config.h>

#include <vector>

using android::Parcel;
using android::base::HexString;
using std::vector;

namespace android {
namespace impl {
// computes the bytes so that if they are passed to FuzzedDataProvider and
// provider.ConsumeIntegralInRange<T>(min, max) is called, it will return val
template <typename T>
void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T min, T max, T val);

// Calls writeInBuffer method with min and max numeric limits of type T. This method
// is reversal of ConsumeIntegral<T>() in FuzzedDataProvider
template <typename T>
void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T val);
} // namespace impl
void generateSeedsFromRecording(base::borrowed_fd fd,
                                binder::debug::RecordedTransaction&& transaction);
} // namespace android
+146 −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/file.h>
#include <android-base/logging.h>

#include <binder/RecordedTransaction.h>

#include <fuzzseeds/random_parcel_seeds.h>

using android::base::WriteFully;

namespace android {
namespace impl {
template <typename T>
std::vector<uint8_t> reverseBytes(T min, T max, T val) {
    uint64_t range = static_cast<uint64_t>(max) - min;
    uint64_t result = val - min;
    size_t offset = 0;

    std::vector<uint8_t> reverseData;
    uint8_t reversed = 0;
    reversed |= result;

    while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0) {
        reverseData.push_back(reversed);
        reversed = 0;
        reversed |= (result >> CHAR_BIT);
        result = result >> CHAR_BIT;
        offset += CHAR_BIT;
    }

    return std::move(reverseData);
}

template <typename T>
void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T min, T max, T val) {
    std::vector<uint8_t> reversedData = reverseBytes(min, max, val);
    // ConsumeIntegral Calls read buffer from the end. Keep inserting at the front of the buffer
    // so that we can align fuzzService operations with seed generation for readability.
    integralBuffer.insert(integralBuffer.begin(), reversedData.begin(), reversedData.end());
}

template <typename T>
void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) {
    // For ConsumeIntegral<T>() calls, FuzzedDataProvider uses numeric limits min and max
    // as range
    writeReversedBuffer(integralBuffer, std::numeric_limits<T>::min(),
                        std::numeric_limits<T>::max(), val);
}

} // namespace impl

void generateSeedsFromRecording(base::borrowed_fd fd,
                                binder::debug::RecordedTransaction&& transaction) {
    // Write Reserved bytes for future use
    std::vector<uint8_t> reservedBytes(8);
    CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get();

    std::vector<uint8_t> integralBuffer;

    // Write UID array : Array elements are initialized in the order that they are declared
    // UID array index 2 element
    // int64_t aidRoot = 0;
    impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32,
                              static_cast<int64_t>(AID_USER) << 32,
                              static_cast<int64_t>(AID_ROOT) << 32);

    // UID array index 3 element
    impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32);

    // always pick AID_ROOT -> index 0
    size_t uidIndex = 0;
    impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(3),
                              uidIndex);

    // Never set uid in seed corpus
    uint8_t writeUid = 0;
    impl::writeReversedBuffer(integralBuffer, writeUid);

    // Read random code. this will be from recorded transaction
    uint8_t selectCode = 1;
    impl::writeReversedBuffer(integralBuffer, selectCode);

    // Get from recorded transaction
    uint32_t code = transaction.getCode();
    impl::writeReversedBuffer(integralBuffer, code);

    // Get from recorded transaction
    uint32_t flags = transaction.getFlags();
    impl::writeReversedBuffer(integralBuffer, flags);

    // always fuzz primary binder
    size_t extraBindersIndex = 0;
    impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(0),
                              extraBindersIndex);

    const Parcel& dataParcel = transaction.getDataParcel();

    // This buffer holds the bytes which will be used for fillRandomParcel API
    std::vector<uint8_t> fillParcelBuffer;

    // Don't take rpc path
    uint8_t rpcBranch = 0;
    impl::writeReversedBuffer(fillParcelBuffer, rpcBranch);

    // Implicit branch on this path -> options->writeHeader(p, provider)
    uint8_t writeHeaderInternal = 0;
    impl::writeReversedBuffer(fillParcelBuffer, writeHeaderInternal);

    // Choose to write data in parcel
    size_t fillFuncIndex = 0;
    impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
                              fillFuncIndex);

    // Write parcel data size from recorded transaction
    size_t toWrite = transaction.getDataParcel().dataBufferSize();
    impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), toWrite, toWrite);

    // Write parcel data with size towrite from recorded transaction
    CHECK(WriteFully(fd, dataParcel.data(), toWrite)) << fd.get();

    // Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data
    size_t subDataSize = toWrite + fillParcelBuffer.size();
    impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), subDataSize, subDataSize);

    // Write fill parcel buffer
    CHECK(WriteFully(fd, fillParcelBuffer.data(), fillParcelBuffer.size())) << fd.get();

    // Write the integralBuffer to data
    CHECK(WriteFully(fd, integralBuffer.data(), integralBuffer.size())) << fd.get();
}
} // namespace android