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

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

Merge changes I70272891,I1f2dc971

* changes:
  Add rtp_writer_fuzzer
  Add sdploader_fuzzer
parents 46c83dcc 9c4b2297
Loading
Loading
Loading
Loading
+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.
*/

cc_defaults {
    name: "libstagefright_rtsp_fuzzer_defaults",
    shared_libs: [
        "liblog",
        "libmedia",
        "libutils",
        "libstagefright_foundation",
    ],
    static_libs: [
        "libdatasource",
        "libstagefright_rtsp",
    ],
    header_libs: [
        "libstagefright_rtsp_headers",
    ],
    fuzz_config:{
        cc: [
            "android-media-fuzzing-reports@google.com",
        ],
        componentid: 155276,
    },
}

cc_fuzz {
    name: "sdploader_fuzzer",
    srcs: [
        "sdploader_fuzzer.cpp",
    ],
    defaults: [
        "libstagefright_rtsp_fuzzer_defaults",
    ]
}

cc_fuzz {
    name: "rtp_writer_fuzzer",
    srcs: [
        "rtp_writer_fuzzer.cpp",
    ],
    defaults: [
        "libstagefright_rtsp_fuzzer_defaults",
    ],
    shared_libs:[
        "libandroid_net",
        "libbase",
        "libstagefright",
        "libcutils",
    ],
}
+64 −0
Original line number Diff line number Diff line
# Fuzzers for libstagefright_rtsp

## Table of contents
+ [sdploader_fuzzer](#SDPLoader)
+ [rtp_writer_fuzzer](#ARTPWriter)

# <a name="SDPLoader"></a> Fuzzer for SDPLoader

SDPLoader supports the following parameters:
1. Flag (parameter name: "flags")
2. URL (parameter name: "url")
3. Header (parameter name: "headers")

| Parameter| Valid Values| Configured Value|
|------------- |-------------| ----- |
|`flags`| `UINT32_MIN`  to  `UINT32_MAX` |Value obtained from FuzzedDataProvider|
|`url`| `String` |Value obtained from FuzzedDataProvider|
|`headers`| `String` |Value obtained from FuzzedDataProvider|

#### Steps to run
1. Build the fuzzer
```
  $ mm -j$(nproc) sdploader_fuzzer
```
2. Run on device
```
  $ adb sync data
  $ adb shell /data/fuzz/arm64/sdploader_fuzzer/sdploader_fuzzer
```

# <a name="ARTPWriter"></a> Fuzzer for ARTPWriter

ARTPWriter supports the following parameters:
1. File descriptor (parameter name: "fd")
2. Local Ip (parameter name: "localIp")
3. Local Port (parameter name: "localPort")
4. Remote Ip (parameter name: "remoteIp")
5. Remote Port (parameter name: "remotePort")
6. Sequence No (parameter name: "seqNo")
7. OpponentID (parameter name: "opponentID")
8. Bit Rate (parameter name: "bitrate")
9. kKeyMIMETypeArray (parameter name: "mimeType")

| Parameter| Valid Values| Configured Value|
|------------- |-------------| ----- |
|`localIp`| `String` |Value obtained from FuzzedDataProvider|
|`localPort`| `UINT32_MIN`  to  `UINT32_MAX` |Value obtained from FuzzedDataProvider|
|`remoteIp`| `String` |Value obtained from FuzzedDataProvider|
|`remotePort`| `UINT32_MIN`  to  `UINT32_MAX` |Value obtained from FuzzedDataProvider|
|`seqNo`| `0`  to  `10000000` |Value obtained from FuzzedDataProvider|
|`opponentID`| `UINT32_MIN`  to  `UINT32_MAX` |Value obtained from FuzzedDataProvider|
|`bitrate`| `UINT32_MIN`  to  `UINT32_MAX` |Value obtained from FuzzedDataProvider|
|`mimeType`| 0. `MEDIA_MIMETYPE_VIDEO_AVC`<br> 1. `MEDIA_MIMETYPE_VIDEO_HEVC`<br> 2. `MEDIA_MIMETYPE_VIDEO_H263`<br> 3. `MEDIA_MIMETYPE_AUDIO_AMR_NB`<br> 4. `MEDIA_MIMETYPE_AUDIO_AMR_WB`|Value obtained from FuzzedDataProvider|

#### Steps to run
1. Build the fuzzer
```
  $ mm -j$(nproc) rtp_writer_fuzzer
```
2. Run on device
```
  $ adb sync data
  $ adb shell /data/fuzz/arm64/rtp_writer_fuzzer/rtp_writer_fuzzer
```
+184 −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 <fuzzer/FuzzedDataProvider.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/rtsp/ARTPWriter.h>

constexpr int32_t kMinSize = 0;
constexpr int32_t kMaxSize = 65536;
constexpr int32_t kMaxTime = 1000;
constexpr int32_t kMaxBytes = 128;
constexpr int32_t kAMRNBFrameSizes[] = {13, 14, 16, 18, 20, 21, 27, 32};
constexpr int32_t kAMRWBFrameSizes[] = {18, 24, 33, 37, 41, 47, 51, 59, 61};
constexpr int32_t kAMRIndexOffset = 8;

using namespace android;

const char* kKeyMimeTypeArray[] = {MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_HEVC,
                                   MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AMR_NB,
                                   MEDIA_MIMETYPE_AUDIO_AMR_WB};

struct TestMediaSource : public MediaSource {
  public:
    TestMediaSource(FuzzedDataProvider& mFdp) : mTestMetaData(new MetaData) {
        int32_t vectorSize = 0;
        mAllowRead = mFdp.ConsumeBool();
        mKeySps = mFdp.ConsumeIntegral<int32_t>();
        mKeyVps = mFdp.ConsumeIntegral<int32_t>();
        mKeyPps = mFdp.ConsumeIntegral<int32_t>();
        mKeyTime = mFdp.ConsumeIntegralInRange<int64_t>(kMinSize, kMaxTime);

        mMimeType = mFdp.PickValueInArray(kKeyMimeTypeArray);
        mTestMetaData->setCString(kKeyMIMEType, mMimeType);
        if (mMimeType == MEDIA_MIMETYPE_AUDIO_AMR_NB) {
            int32_t index =
                    mFdp.ConsumeIntegralInRange<int32_t>(kMinSize, std::size(kAMRNBFrameSizes) - 1);
            vectorSize = kAMRNBFrameSizes[index];
            mData.push_back(kAMRIndexOffset * index);
        } else if (mMimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB) {
            int32_t index =
                    mFdp.ConsumeIntegralInRange<int32_t>(kMinSize, std::size(kAMRWBFrameSizes) - 1);
            vectorSize = kAMRWBFrameSizes[index];
            mData.push_back(kAMRIndexOffset * index);
        } else if (mMimeType == MEDIA_MIMETYPE_VIDEO_H263) {
            // Required format for H263 media data
            mData.push_back(0);
            mData.push_back(0);
            vectorSize = mFdp.ConsumeIntegralInRange<int32_t>(kMinSize, kMaxSize);
        } else {
            vectorSize = mFdp.ConsumeIntegralInRange<int32_t>(kMinSize, kMaxSize);
        }
        for (size_t idx = mData.size(); idx < vectorSize; ++idx) {
            mData.push_back(mFdp.ConsumeIntegral<uint8_t>());
        }
    }
    virtual status_t start(MetaData* /*params*/) { return OK; }
    virtual status_t stop() { return OK; }
    virtual sp<MetaData> getFormat() { return mTestMetaData; }
    virtual status_t read(MediaBufferBase** buffer, const ReadOptions* /*options*/) {
        if (!mAllowRead) {
            return -1;
        }
        *buffer = new MediaBuffer(mData.data() /*data*/, mData.size() /*size*/);
        if (mKeySps) {
            (*buffer)->meta_data().setInt32(kKeySps, mKeySps);
        }
        if (mKeyVps) {
            (*buffer)->meta_data().setInt32(kKeyVps, mKeyVps);
        }
        if (mKeyPps) {
            (*buffer)->meta_data().setInt32(kKeyPps, mKeyPps);
        }
        (*buffer)->meta_data().setInt64(kKeyTime, mKeyTime);
        return OK;
    }

  private:
    int32_t mKeySps;
    int32_t mKeyVps;
    int32_t mKeyPps;
    int64_t mKeyTime;
    bool mAllowRead;
    const char* mMimeType;
    sp<MetaData> mTestMetaData;
    std::vector<uint8_t> mData;
};

class ARTPWriterFuzzer {
  public:
    ARTPWriterFuzzer(const uint8_t* data, size_t size)
        : mDataSourceFd(memfd_create("InputFile", MFD_ALLOW_SEALING)), mFdp(data, size) {}
    ~ARTPWriterFuzzer() { close(mDataSourceFd); }
    void process();

  private:
    void createARTPWriter();
    const int32_t mDataSourceFd;
    FuzzedDataProvider mFdp;
    sp<ARTPWriter> mArtpWriter;
};

void ARTPWriterFuzzer::createARTPWriter() {
    String8 localIp = String8(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
    String8 remoteIp = String8(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
    mArtpWriter = sp<ARTPWriter>::make(
            mDataSourceFd, localIp, mFdp.ConsumeIntegral<uint16_t>() /* localPort */, remoteIp,
            mFdp.ConsumeIntegral<uint16_t>() /* remotePort */,
            mFdp.ConsumeIntegralInRange<uint32_t>(kMinSize, kMaxSize) /* seqNo */);
}

void ARTPWriterFuzzer::process() {
    if (mFdp.ConsumeBool()) {
        mArtpWriter = sp<ARTPWriter>::make(mDataSourceFd);
        if (mArtpWriter->getSequenceNum() > kMaxSize) {
            createARTPWriter();
        }
    } else {
        createARTPWriter();
    }

    mArtpWriter->addSource(sp<TestMediaSource>::make(mFdp) /* source */);

    while (mFdp.remaining_bytes()) {
        auto invokeRTPWriterFuzzer = mFdp.PickValueInArray<const std::function<void()>>({
                [&]() {
                    sp<MetaData> metaData = sp<MetaData>::make();
                    if (mFdp.ConsumeBool()) {
                        metaData->setInt32(kKeySelfID, mFdp.ConsumeIntegral<int32_t>());
                    }
                    if (mFdp.ConsumeBool()) {
                        metaData->setInt32(kKeyPayloadType, mFdp.ConsumeIntegral<int32_t>());
                    }
                    if (mFdp.ConsumeBool()) {
                        metaData->setInt32(kKeyRtpExtMap, mFdp.ConsumeIntegral<int32_t>());
                    }
                    if (mFdp.ConsumeBool()) {
                        metaData->setInt32(kKeyRtpCvoDegrees, mFdp.ConsumeIntegral<int32_t>());
                    }
                    if (mFdp.ConsumeBool()) {
                        metaData->setInt32(kKeyRtpDscp, mFdp.ConsumeIntegral<int32_t>());
                    }
                    if (mFdp.ConsumeBool()) {
                        metaData->setInt64(kKeySocketNetwork, mFdp.ConsumeIntegral<int64_t>());
                    }
                    mArtpWriter->start(metaData.get() /*param*/);
                },
                [&]() {
                    mArtpWriter->setTMMBNInfo(mFdp.ConsumeIntegral<uint32_t>() /* opponentID */,
                                              mFdp.ConsumeIntegral<uint32_t>() /* bitrate */);
                },
                [&]() { mArtpWriter->stop(); },
                [&]() {
                    mArtpWriter->updateCVODegrees(mFdp.ConsumeIntegral<int32_t>() /* cvoDegrees */);
                },
                [&]() {
                    mArtpWriter->updatePayloadType(
                            mFdp.ConsumeIntegral<int32_t>() /* payloadType */);
                },

        });
        invokeRTPWriterFuzzer();
    }
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    ARTPWriterFuzzer artpWriterFuzzer(data, size);
    artpWriterFuzzer.process();
    return 0;
}
+143 −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 <datasource/HTTPBase.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/rtsp/SDPLoader.h>

using namespace android;

constexpr int32_t kMinCapacity = 0;
constexpr int32_t kMaxCapacity = 1000;
constexpr int32_t kMaxStringLength = 20;
constexpr int32_t kMaxBytes = 128;
enum { kWhatLoad = 'load' };

struct FuzzAHandler : public AHandler {
  public:
    FuzzAHandler(std::function<void()> signalEosFunction) : mSignalEosFunction(signalEosFunction) {}

  protected:
    void onMessageReceived(const sp<AMessage>& msg) override {
        switch (msg->what()) {
            case kWhatLoad: {
                mSignalEosFunction();
                break;
            }
        }
        return;
    }

  private:
    std::function<void()> mSignalEosFunction;
};

struct FuzzMediaHTTPConnection : public MediaHTTPConnection {
  public:
    FuzzMediaHTTPConnection(FuzzedDataProvider* fdp) : mFdp(fdp) {
        mSize = mFdp->ConsumeIntegralInRange(kMinCapacity, kMaxCapacity);
        mData = mFdp->ConsumeBytes<uint8_t>(mSize);
        mSize = mData.size();
    }
    virtual bool connect(const char* /* uri */,
                         const KeyedVector<String8, String8>* /* headers */) {
        return mFdp->ConsumeBool();
    }
    virtual void disconnect() { return; }
    virtual ssize_t readAt(off64_t offset, void* data, size_t size) {
        if (size <= mSize - offset) {
            data = mData.data() + offset;
            return size;
        } else {
            data = nullptr;
            return 0;
        }
    }
    virtual off64_t getSize() { return mSize; }
    virtual status_t getMIMEType(String8* /*mimeType*/) {return mFdp->ConsumeIntegral<status_t>();}
    virtual status_t getUri(String8* /*uri*/) {return mFdp->ConsumeIntegral<status_t>();}

  private:
    FuzzedDataProvider* mFdp = nullptr;
    std::vector<uint8_t> mData;
    size_t mSize = 0;
};

struct FuzzMediaHTTPService : public MediaHTTPService {
  public:
    FuzzMediaHTTPService(FuzzedDataProvider* fdp) : mFdp(fdp) {}
    virtual sp<MediaHTTPConnection> makeHTTPConnection() {
        mediaHTTPConnection = sp<FuzzMediaHTTPConnection>::make(mFdp);
        return mediaHTTPConnection;
    }

  private:
    sp<FuzzMediaHTTPConnection> mediaHTTPConnection = nullptr;
    FuzzedDataProvider* mFdp = nullptr;
};

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

  private:
    void signalEos();

    bool mEosReached = false;
    std::mutex mMsgPostCompleteMutex;
    std::condition_variable mConditionalVariable;
    FuzzedDataProvider mFdp;
};

void SDPLoaderFuzzer::signalEos() {
    mEosReached = true;
    mConditionalVariable.notify_one();
    return;
}

void SDPLoaderFuzzer::process() {
    sp<FuzzAHandler> handler = sp<FuzzAHandler>::make(std::bind(&SDPLoaderFuzzer::signalEos, this));
    sp<ALooper> looper = sp<ALooper>::make();
    looper->start();
    looper->registerHandler(handler);
    const sp<AMessage> notify = sp<AMessage>::make(kWhatLoad, handler);
    sp<SDPLoader> sdpLoader =
            sp<SDPLoader>::make(notify, mFdp.ConsumeIntegral<uint32_t>() /* flags */,
                                sp<FuzzMediaHTTPService>::make(&mFdp) /* httpService */);

    KeyedVector<String8, String8> headers;
    for (size_t idx = 0; idx < mFdp.ConsumeIntegralInRange<size_t>(kMinCapacity, kMaxCapacity);
         ++idx) {
        headers.add(String8(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str()) /* key */,
                    String8(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str()) /* value */);
    }

    sdpLoader->load(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* url */, &headers);

    std::unique_lock waitForMsgPostComplete(mMsgPostCompleteMutex);
    mConditionalVariable.wait(waitForMsgPostComplete, [this] { return mEosReached; });
}

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