blob: a7cb689a5f2ceb2ac317a9b3f6d4644e93601ce3 [file] [log] [blame]
/*
* Copyright (C) 2021 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 <StagefrightMetadataRetriever.h>
#include <binder/ProcessState.h>
#include <datasource/FileSource.h>
#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/foundation/base64.h>
#include <fuzzer/FuzzedDataProvider.h>
using namespace std;
using namespace android;
const char *kMimeTypes[] = {MEDIA_MIMETYPE_IMAGE_JPEG, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
MEDIA_MIMETYPE_VIDEO_AV1, MEDIA_MIMETYPE_VIDEO_AVC,
MEDIA_MIMETYPE_VIDEO_HEVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_VIDEO_MPEG2,
MEDIA_MIMETYPE_VIDEO_RAW, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
MEDIA_MIMETYPE_VIDEO_SCRAMBLED, MEDIA_MIMETYPE_VIDEO_DIVX,
MEDIA_MIMETYPE_VIDEO_DIVX3, MEDIA_MIMETYPE_VIDEO_XVID,
MEDIA_MIMETYPE_VIDEO_MJPEG, MEDIA_MIMETYPE_AUDIO_AMR_NB,
MEDIA_MIMETYPE_AUDIO_AMR_WB, MEDIA_MIMETYPE_AUDIO_MPEG,
MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
MEDIA_MIMETYPE_AUDIO_MIDI, MEDIA_MIMETYPE_AUDIO_AAC,
MEDIA_MIMETYPE_AUDIO_QCELP, MEDIA_MIMETYPE_AUDIO_VORBIS,
MEDIA_MIMETYPE_AUDIO_OPUS, MEDIA_MIMETYPE_AUDIO_G711_ALAW,
MEDIA_MIMETYPE_AUDIO_G711_MLAW, MEDIA_MIMETYPE_AUDIO_RAW,
MEDIA_MIMETYPE_AUDIO_FLAC, MEDIA_MIMETYPE_AUDIO_AAC_ADTS,
MEDIA_MIMETYPE_AUDIO_MSGSM, MEDIA_MIMETYPE_AUDIO_AC3,
MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_EAC3_JOC,
MEDIA_MIMETYPE_AUDIO_AC4, MEDIA_MIMETYPE_AUDIO_SCRAMBLED,
MEDIA_MIMETYPE_AUDIO_ALAC, MEDIA_MIMETYPE_AUDIO_WMA,
MEDIA_MIMETYPE_AUDIO_MS_ADPCM, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM,
MEDIA_MIMETYPE_CONTAINER_MPEG4, MEDIA_MIMETYPE_CONTAINER_WAV,
MEDIA_MIMETYPE_CONTAINER_OGG, MEDIA_MIMETYPE_CONTAINER_MATROSKA,
MEDIA_MIMETYPE_CONTAINER_MPEG2TS, MEDIA_MIMETYPE_CONTAINER_AVI,
MEDIA_MIMETYPE_CONTAINER_MPEG2PS, MEDIA_MIMETYPE_CONTAINER_HEIF,
MEDIA_MIMETYPE_TEXT_3GPP, MEDIA_MIMETYPE_TEXT_SUBRIP,
MEDIA_MIMETYPE_TEXT_VTT, MEDIA_MIMETYPE_TEXT_CEA_608,
MEDIA_MIMETYPE_TEXT_CEA_708, MEDIA_MIMETYPE_DATA_TIMED_ID3};
class MetadataRetrieverFuzzer {
public:
MetadataRetrieverFuzzer(const uint8_t *data, size_t size)
: mFdp(data, size),
mMdRetriever(new StagefrightMetadataRetriever()),
mDataSourceFd(memfd_create("InputFile", MFD_ALLOW_SEALING)) {}
~MetadataRetrieverFuzzer() { close(mDataSourceFd); }
bool setDataSource(const uint8_t *data, size_t size);
void getData();
private:
FuzzedDataProvider mFdp;
sp<StagefrightMetadataRetriever> mMdRetriever = nullptr;
const int32_t mDataSourceFd;
};
void MetadataRetrieverFuzzer::getData() {
int64_t timeUs = mFdp.ConsumeIntegral<int64_t>();
int32_t option = mFdp.ConsumeIntegral<int32_t>();
int32_t colorFormat = mFdp.ConsumeIntegral<int32_t>();
bool metaOnly = mFdp.ConsumeBool();
mMdRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
int32_t index = mFdp.ConsumeIntegral<int32_t>();
colorFormat = mFdp.ConsumeIntegral<int32_t>();
metaOnly = mFdp.ConsumeBool();
bool thumbnail = mFdp.ConsumeBool();
mMdRetriever->getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
index = mFdp.ConsumeIntegral<int32_t>();
colorFormat = mFdp.ConsumeIntegral<int32_t>();
int32_t left = mFdp.ConsumeIntegral<int32_t>();
int32_t top = mFdp.ConsumeIntegral<int32_t>();
int32_t right = mFdp.ConsumeIntegral<int32_t>();
int32_t bottom = mFdp.ConsumeIntegral<int32_t>();
mMdRetriever->getImageRectAtIndex(index, colorFormat, left, top, right, bottom);
index = mFdp.ConsumeIntegral<int32_t>();
colorFormat = mFdp.ConsumeIntegral<int32_t>();
metaOnly = mFdp.ConsumeBool();
mMdRetriever->getFrameAtIndex(index, colorFormat, metaOnly);
mMdRetriever->extractAlbumArt();
int32_t keyCode = mFdp.ConsumeIntegral<int32_t>();
mMdRetriever->extractMetadata(keyCode);
}
bool MetadataRetrieverFuzzer::setDataSource(const uint8_t *data, size_t size) {
status_t status = -1;
enum DataSourceChoice {FromHttp, FromFd, FromFileSource, kMaxValue = FromFileSource};
switch (mFdp.ConsumeEnum<DataSourceChoice>()) {
case FromHttp: {
KeyedVector<String8, String8> mHeaders;
mHeaders.add(String8(mFdp.ConsumeRandomLengthString().c_str()),
String8(mFdp.ConsumeRandomLengthString().c_str()));
uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(0, size);
vector<uint8_t> uriSuffix = mFdp.ConsumeBytes<uint8_t>(dataBlobSize);
string uri("data:");
uri += ";base64,";
AString out;
encodeBase64(uriSuffix.data(), uriSuffix.size(), &out);
uri += out.c_str();
status = mMdRetriever->setDataSource(nullptr /*httpService*/, uri.c_str(), &mHeaders);
break;
}
case FromFd: {
write(mDataSourceFd, data, size);
status = mMdRetriever->setDataSource(mDataSourceFd, 0, size);
break;
}
case FromFileSource: {
write(mDataSourceFd, data, size);
sp<DataSource> dataSource = new FileSource(dup(mDataSourceFd), 0, size);
status = mMdRetriever->setDataSource(dataSource, mFdp.PickValueInArray(kMimeTypes));
break;
}
}
if (status != 0) {
return false;
}
return true;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
MetadataRetrieverFuzzer mrtFuzzer(data, size);
ProcessState::self()->startThreadPool();
if (mrtFuzzer.setDataSource(data, size)) {
mrtFuzzer.getData();
}
return 0;
}