blob: 63002564f48c5fcc381d1dd10d3ec8ef223981e6 [file] [log] [blame]
/*
* Copyright (C) 2022 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 <MtpDataPacket.h>
#include <MtpDevHandle.h>
#include <MtpPacketFuzzerUtils.h>
#include <MtpProperty.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <utils/String16.h>
using namespace android;
constexpr uint16_t kFeasibleTypes[] = {
MTP_TYPE_UNDEFINED, MTP_TYPE_INT8, MTP_TYPE_UINT8, MTP_TYPE_INT16, MTP_TYPE_UINT16,
MTP_TYPE_INT32, MTP_TYPE_UINT32, MTP_TYPE_INT64, MTP_TYPE_UINT64, MTP_TYPE_INT128,
MTP_TYPE_UINT128, MTP_TYPE_AINT8, MTP_TYPE_AUINT8, MTP_TYPE_AINT16, MTP_TYPE_AUINT16,
MTP_TYPE_AINT32, MTP_TYPE_AUINT32, MTP_TYPE_AINT64, MTP_TYPE_AUINT64, MTP_TYPE_AINT128,
MTP_TYPE_AUINT128, MTP_TYPE_STR,
};
class MtpPropertyFuzzer : MtpPacketFuzzerUtils {
public:
MtpPropertyFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
mUsbDevFsUrb = (struct usbdevfs_urb*)malloc(sizeof(struct usbdevfs_urb) +
sizeof(struct usbdevfs_iso_packet_desc));
};
~MtpPropertyFuzzer() { free(mUsbDevFsUrb); };
void process();
private:
FuzzedDataProvider mFdp;
};
void MtpPropertyFuzzer::process() {
MtpProperty* mtpProperty = nullptr;
if (mFdp.ConsumeBool()) {
mtpProperty = new MtpProperty();
} else {
uint16_t type = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint16_t>()
: mFdp.PickValueInArray<uint16_t>(kFeasibleTypes);
mtpProperty = new MtpProperty(mFdp.ConsumeIntegral<uint16_t>(), type, mFdp.ConsumeBool(),
mFdp.ConsumeIntegral<uint16_t>());
}
while (mFdp.remaining_bytes() > 0) {
auto invokeMtpPropertyFuzzer = mFdp.PickValueInArray<const std::function<void()>>({
[&]() {
MtpDataPacket mtpDataPacket;
if (mFdp.ConsumeBool()) {
mtpProperty->read(mtpDataPacket);
} else {
if (mFdp.ConsumeBool()) {
#ifdef MTP_DEVICE
android::IMtpHandle* h = new MtpDevHandle();
h->start(mFdp.ConsumeBool());
std::string text = mFdp.ConsumeRandomLengthString(kMaxLength);
char* data = const_cast<char*>(text.c_str());
h->read(static_cast<void*>(data), text.length());
mtpDataPacket.write(h);
h->close();
delete h;
#endif
#ifdef MTP_HOST
fillFilePath(&mFdp);
int32_t fd = memfd_create(mPath.c_str(), MFD_ALLOW_SEALING);
fillUsbRequest(fd, &mFdp);
mUsbRequest.dev = usb_device_new(mPath.c_str(), fd);
mtpDataPacket.write(&mUsbRequest,
mFdp.PickValueInArray<UrbPacketDivisionMode>(
kUrbPacketDivisionModes),
fd,
mFdp.ConsumeIntegralInRange(kMinSize, kMaxSize));
usb_device_close(mUsbRequest.dev);
#endif
}
if (mFdp.ConsumeBool()) {
mtpProperty->write(mtpDataPacket);
} else {
mtpProperty->setCurrentValue(mtpDataPacket);
}
}
},
[&]() {
char16_t* data = nullptr;
std::string str = mFdp.ConsumeRandomLengthString(kMaxLength);
android::String16 s(str.c_str());
if (mFdp.ConsumeBool()) {
data = const_cast<char16_t*>(s.c_str());
}
if (mFdp.ConsumeBool()) {
mtpProperty->setDefaultValue(reinterpret_cast<uint16_t*>(data));
} else if (mFdp.ConsumeBool()) {
mtpProperty->setCurrentValue(reinterpret_cast<uint16_t*>(data));
} else {
mtpProperty->setCurrentValue(str.c_str());
}
},
[&]() {
mtpProperty->setFormRange(mFdp.ConsumeIntegral<int32_t>(),
mFdp.ConsumeIntegral<int32_t>(),
mFdp.ConsumeIntegral<int32_t>());
},
[&]() {
std::vector<int32_t> init;
for (size_t idx = 0; idx < mFdp.ConsumeIntegralInRange(kMinSize, kMaxSize);
++idx) {
init.push_back(mFdp.ConsumeIntegral<int32_t>());
}
mtpProperty->setFormEnum(init.data(), init.size());
},
});
invokeMtpPropertyFuzzer();
}
delete (mtpProperty);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
MtpPropertyFuzzer mtpPropertyFuzzer(data, size);
mtpPropertyFuzzer.process();
return 0;
}