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

Commit 23c2a376 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I85da0a91,I94f4a0fc,Iee1b71a6,I15e283e1 into main

* changes:
  Added camera_metadata_fuzzer
  Added camera_utils_fuzzer
  Refactored camera_fuzzer
  Modified camera2common.h
parents ef014f03 b238df4f
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ cc_defaults {
    name: "camera_defaults",
    static_libs: [
        "libcamera_client",
        "libbinder_random_parcel",
    ],
    shared_libs: [
        "camera_platform_flags_c_lib",
@@ -38,6 +39,9 @@ cc_defaults {
        "libcamera_metadata",
        "libnativewindow",
    ],
    header_libs: [
        "libbinder_headers",
    ],
    fuzz_config: {
        cc: [
            "android-camera-fwk-eng@google.com",
@@ -157,3 +161,23 @@ cc_fuzz {
        "camera_defaults",
    ],
}

cc_fuzz {
    name: "camera_utils_fuzzer",
    srcs: [
        "camera_utils_fuzzer.cpp",
    ],
    defaults: [
        "camera_defaults",
    ],
}

cc_fuzz {
    name: "camera_metadata_fuzzer",
    srcs: [
        "camera_metadata_fuzzer.cpp",
    ],
    defaults: [
        "camera_defaults",
    ],
}
+4 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ Build the fuzzer
  $ mm -j$(nproc) camera_Parameters_fuzzer
  $ mm -j$(nproc) camera_SessionStats_fuzzer
  $ mm -j$(nproc) camera_captureResult_fuzzer
  $ mm -j$(nproc) camera_utils_fuzzer
  $ mm -j$(nproc) camera_metadata_fuzzer
```
#### Steps to run
To run on device
@@ -67,6 +69,8 @@ To run on device
  $ adb shell /data/fuzz/${TARGET_ARCH}/camera_Parameters_fuzzer/camera_Parameters_fuzzer
  $ adb shell /data/fuzz/${TARGET_ARCH}/camera_SessionStats_fuzzer/camera_SessionStats_fuzzer
  $ adb shell /data/fuzz/${TARGET_ARCH}/camera_captureResult_fuzzer/camera_captureResult_fuzzer
  $ adb shell /data/fuzz/${TARGET_ARCH}/camera_utils_fuzzer/camera_utils_fuzzer
  $ adb shell /data/fuzz/${TARGET_ARCH}/camera_metadata_fuzzer/camera_metadata_fuzzer
```

## References:
+103 −0
Original line number Diff line number Diff line
@@ -16,10 +16,93 @@
#ifndef CAMERA2COMMON_H
#define CAMERA2COMMON_H

#include <CameraSessionStats.h>
#include <android-base/logging.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <fuzzbinder/random_binder.h>
#include <fuzzbinder/random_fd.h>
#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <utils/String16.h>

using namespace android;

const std::string kFetchCameraService = "media.camera";

constexpr int8_t kMinIterations = 0;
constexpr int8_t kMaxIterations = 20;
constexpr int8_t kMinExtraFDs = 0;
constexpr int8_t kMinExtraBinder = 0;
constexpr int32_t kMaxFDs = 1000;
constexpr int32_t kMinBytes = 0;
constexpr int32_t kMaxBytes = 20;
constexpr int32_t kMinCapacity = 1;
constexpr int32_t kMaxCapacity = 1000;

const int32_t kValidFacing[] = {android::hardware::CameraSessionStats::CAMERA_FACING_BACK,
                                android::hardware::CameraSessionStats::CAMERA_FACING_FRONT};
const int32_t kValidOrientation[] = {0, 90, 180, 270};

void randomizeParcel(Parcel* parcel, FuzzedDataProvider& provider) {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16(kFetchCameraService.c_str()));
    RandomParcelOptions options{
            .extraBinders = {binder},
            .extraFds = {},
    };

    auto retFds = parcel->debugReadAllFileDescriptors();
    for (size_t i = 0; i < retFds.size(); ++i) {
        options.extraFds.push_back(base::unique_fd(dup(retFds[i])));
    }
    int8_t iterations = provider.ConsumeIntegralInRange<int8_t>(kMinIterations, kMaxIterations);
    while (--iterations >= 0) {
        auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
                // write data
                [&]() {
                    size_t toWrite = provider.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes);
                    std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(toWrite);
                    CHECK(OK == parcel->write(data.data(), data.size()));
                },
                // write FD
                [&]() {
                    if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
                        const base::unique_fd& fd =
                                options.extraFds.at(provider.ConsumeIntegralInRange<size_t>(
                                        kMinExtraFDs, options.extraFds.size() - 1));
                        CHECK(OK == parcel->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
                    } else {
                        // b/260119717 - Adding more FDs can eventually lead to FD limit exhaustion
                        if (options.extraFds.size() > kMaxFDs) {
                            return;
                        }

                        std::vector<base::unique_fd> fds = getRandomFds(&provider);
                        CHECK(OK == parcel->writeFileDescriptor(fds.begin()->release(),
                                                                true /*takeOwnership*/));

                        options.extraFds.insert(options.extraFds.end(),
                                                std::make_move_iterator(fds.begin() + 1),
                                                std::make_move_iterator(fds.end()));
                    }
                },
                // write binder
                [&]() {
                    sp<IBinder> binder;
                    if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
                        binder = options.extraBinders.at(provider.ConsumeIntegralInRange<size_t>(
                                kMinExtraBinder, options.extraBinders.size() - 1));
                    } else {
                        binder = getRandomBinder(&provider);
                    }
                    CHECK(OK == parcel->writeStrongBinder(binder));
                },
        });
        fillFunc();
    }
}

template <class type>
void invokeReadWriteNullParcel(type* obj) {
    Parcel* parcelNull = nullptr;
@@ -52,4 +135,24 @@ void invokeReadWriteParcelsp(sp<type> obj) {
    delete parcel;
}

template <class type>
void invokeNewReadWriteParcel(type* obj, FuzzedDataProvider& provider) {
    Parcel* parcel = new Parcel();
    obj->writeToParcel(parcel);
    randomizeParcel(parcel, provider);
    parcel->setDataPosition(0);
    obj->readFromParcel(parcel);
    delete parcel;
}

template <class type>
void invokeNewReadWriteParcelsp(sp<type> obj, FuzzedDataProvider& provider) {
    Parcel* parcel = new Parcel();
    obj->writeToParcel(parcel);
    randomizeParcel(parcel, provider);
    parcel->setDataPosition(0);
    obj->readFromParcel(parcel);
    delete parcel;
}

#endif  // CAMERA2COMMON_H
+192 −245

File changed.

Preview size limit exceeded, changes collapsed.

+223 −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 <CameraBase.h>
#include "camera2common.h"

using namespace std;
using namespace android;
using namespace android::hardware;

constexpr int32_t kSizeMin = 0;
constexpr int32_t kSizeMax = 1000;
constexpr int32_t kMinMetadataCapacity = 0;
constexpr int32_t kMaxMetadataCapacity = 1000;
constexpr int32_t kRangeMin = 0;
constexpr int32_t kRangeMax = 1000;

class CameraMetadataFuzzer {
  public:
    void process(const uint8_t* data, size_t size);

  private:
    void initCameraMetadata();
    void invokeCameraMetadata();
    CameraMetadata* mCameraMetadata = nullptr;
    FuzzedDataProvider* mFDP = nullptr;
    camera_metadata* mMetaBuffer = nullptr;
    bool mMetadataLocked = false;
    template <typename T>
    void callCameraMetadataUpdate(size_t dataCount, T data) {
        uint32_t tag = mFDP->ConsumeIntegral<uint32_t>();
        mCameraMetadata->update(tag, &data, dataCount);
    }
};

void CameraMetadataFuzzer::initCameraMetadata() {
    auto selectMetadataConstructor = mFDP->PickValueInArray<const std::function<void()>>({
            [&]() {
                mMetaBuffer = allocate_camera_metadata(
                        mFDP->ConsumeIntegralInRange<size_t>(
                                kMinMetadataCapacity, kMaxMetadataCapacity) /* entry_capacity */,
                        mFDP->ConsumeIntegralInRange<size_t>(
                                kMinMetadataCapacity, kMaxMetadataCapacity) /* data_capacity */);
                mCameraMetadata = new CameraMetadata(mMetaBuffer);
            },
            [&]() {
                mCameraMetadata = new CameraMetadata();
            },
            [&]() {
                size_t entryCapacity = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
                size_t dataCapacity = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
                mCameraMetadata = new CameraMetadata(entryCapacity, dataCapacity);
            },
    });
    selectMetadataConstructor();
}
void CameraMetadataFuzzer::invokeCameraMetadata() {
    initCameraMetadata();

    const camera_metadata_t* metadataBuffer = nullptr;
    mMetadataLocked = mFDP->ConsumeBool();
    if (mMetadataLocked) {
        metadataBuffer = mCameraMetadata->getAndLock();
    }

    size_t dataCount = 1;
    while (mFDP->remaining_bytes()) {
        auto callMetadataAPIs = mFDP->PickValueInArray<const std::function<void()>>({

                [&]() { mCameraMetadata->entryCount(); },
                [&]() { mCameraMetadata->isEmpty(); },
                [&]() { mCameraMetadata->bufferSize(); },
                [&]() { mCameraMetadata->sort(); },
                [&]() {
                    uint8_t dataUint8 = mFDP->ConsumeIntegral<uint8_t>();
                    callCameraMetadataUpdate(dataCount, dataUint8);
                },
                [&]() {
                    int32_t dataInt32 = mFDP->ConsumeIntegral<int32_t>();
                    callCameraMetadataUpdate(dataCount, dataInt32);
                },
                [&]() {
                    int64_t dataInt64 = mFDP->ConsumeIntegral<int64_t>();
                    callCameraMetadataUpdate(dataCount, dataInt64);
                },
                [&]() {
                    float dataFloat = mFDP->ConsumeFloatingPoint<float>();
                    callCameraMetadataUpdate(dataCount, dataFloat);
                },
                [&]() {
                    double dataDouble = mFDP->ConsumeFloatingPoint<double>();
                    callCameraMetadataUpdate(dataCount, dataDouble);
                },
                [&]() {
                    camera_metadata_rational dataRational;
                    dataRational.numerator = mFDP->ConsumeIntegral<int32_t>();
                    dataRational.denominator = mFDP->ConsumeIntegral<int32_t>();
                    callCameraMetadataUpdate(dataCount, dataRational);
                },
                [&]() {
                    uint32_t tag = mFDP->ConsumeIntegral<uint32_t>();
                    string dataStr = mFDP->ConsumeRandomLengthString(kMaxBytes);
                    String8 dataString(dataStr.c_str());
                    mCameraMetadata->update(tag, dataString);
                },
                [&]() {
                    uint32_t tag = mFDP->ConsumeIntegral<uint32_t>();
                    uint32_t tagExists =
                            mFDP->ConsumeBool() ? tag : mFDP->ConsumeIntegral<uint32_t>();
                    mCameraMetadata->exists(tagExists);
                },
                [&]() {
                    uint32_t tag = mFDP->ConsumeIntegral<uint32_t>();
                    uint32_t tagFind =
                            mFDP->ConsumeBool() ? tag : mFDP->ConsumeIntegral<uint32_t>();
                    mCameraMetadata->find(tagFind);
                },
                [&]() {
                    uint32_t tag = mFDP->ConsumeIntegral<uint32_t>();
                    uint32_t tagErase =
                            mFDP->ConsumeBool() ? tag : mFDP->ConsumeIntegral<uint32_t>();
                    mCameraMetadata->erase(tagErase);
                },
                [&]() { mCameraMetadata->unlock(metadataBuffer); },
                [&]() {
                    std::vector<int32_t> tagsRemoved;
                    uint64_t vendorId = mFDP->ConsumeIntegral<uint64_t>();
                    mCameraMetadata->removePermissionEntries(vendorId, &tagsRemoved);
                },
                [&]() {
                    string name = mFDP->ConsumeRandomLengthString(kMaxBytes);
                    VendorTagDescriptor vTags;
                    uint32_t tagName = mFDP->ConsumeIntegral<uint32_t>();
                    mCameraMetadata->getTagFromName(name.c_str(), &vTags, &tagName);
                },
                [&]() {
                    int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
                    int32_t verbosity = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
                    int32_t indentation =
                            mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
                    mCameraMetadata->dump(fd, verbosity, indentation);
                    close(fd);
                },
                [&]() { CameraMetadata metadataCopy(mCameraMetadata->release()); },
                [&]() {
                    if (mFDP->ConsumeBool()) {
                        CameraMetadata otherCameraMetadata;
                        mCameraMetadata->swap(otherCameraMetadata);
                    } else {
                        std::vector<int8_t> entryCapacityVector =
                                mFDP->ConsumeBytes<int8_t>(kMaxBytes);
                        /**
                         * Resizing vector to a size between 1 to 1000 so that vector is not empty.
                         */
                        entryCapacityVector.resize(0, mFDP->ConsumeIntegralInRange<int32_t>(
                                                              kMinCapacity, kMaxCapacity));
                        CameraMetadata otherCameraMetadata(entryCapacityVector.size());
                        mCameraMetadata->swap(otherCameraMetadata);
                    }
                },
                [&]() {
                    if (!mMetadataLocked) {
                        camera_metadata* metaBuffer = allocate_camera_metadata(
                                mFDP->ConsumeIntegralInRange<size_t>(
                                        kMinMetadataCapacity,
                                        kMaxMetadataCapacity) /* entry_capacity */,
                                mFDP->ConsumeIntegralInRange<size_t>(
                                        kMinMetadataCapacity,
                                        kMaxMetadataCapacity) /* data_capacity */);
                        mCameraMetadata->acquire(metaBuffer);
                    }
                },
                [&]() {
                    if (!mMetadataLocked) {
                        camera_metadata* metaBuffer = allocate_camera_metadata(
                                mFDP->ConsumeIntegralInRange<size_t>(
                                        kMinMetadataCapacity,
                                        kMaxMetadataCapacity) /* entry_capacity */,
                                mFDP->ConsumeIntegralInRange<size_t>(
                                        kMinMetadataCapacity,
                                        kMaxMetadataCapacity) /* data_capacity */);
                        mCameraMetadata->append(metaBuffer);
                        free_camera_metadata(metaBuffer);
                    }
                },
        });
        callMetadataAPIs();

        // Not keeping invokeReadWrite() APIs in while loop to avoid possible OOM.
        invokeReadWriteNullParcel<CameraMetadata>(mCameraMetadata);
        if (mFDP->ConsumeBool()) {
            invokeReadWriteParcel<CameraMetadata>(mCameraMetadata);
        } else {
            invokeNewReadWriteParcel<CameraMetadata>(mCameraMetadata, *mFDP);
        }
    }
    delete mCameraMetadata;
}

void CameraMetadataFuzzer::process(const uint8_t* data, size_t size) {
    mFDP = new FuzzedDataProvider(data, size);
    invokeCameraMetadata();
    delete mFDP;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    CameraMetadataFuzzer cameraMetadataFuzzer;
    cameraMetadataFuzzer.process(data, size);
    return 0;
}
Loading