/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace android; constexpr int32_t kMaxStringLength = 20; constexpr int32_t kMaxBytes = 200; constexpr int32_t kMaxDataSize = 20; constexpr uint16_t kWMaxPacketSize = 64; constexpr uint16_t kEndpointsCount = 3; const std::string kInputFile = "/dev/null"; const std::string kConfigFilePath = "/data/local/tmp/config"; static bool readCallback(void* data, uint32_t offset, uint32_t length, void* clientData) { return true; } struct fdDescriptors { struct usb_interface_descriptor interface; struct usb_endpoint_descriptor ep[kEndpointsCount]; }; fdDescriptors writeDescriptorsToFd(int32_t fd, FuzzedDataProvider& fdp) { fdDescriptors desc; desc.interface.bLength = sizeof(desc.interface); desc.interface.bDescriptorType = USB_DT_INTERFACE; desc.interface.bInterfaceNumber = fdp.ConsumeIntegral(); desc.interface.bNumEndpoints = kEndpointsCount; desc.interface.bInterfaceClass = fdp.ConsumeBool() ? USB_CLASS_STILL_IMAGE : USB_CLASS_VENDOR_SPEC; desc.interface.bInterfaceSubClass = fdp.ConsumeBool() ? 1 : 0xFF; desc.interface.bInterfaceProtocol = fdp.ConsumeBool() ? 1 : 0; desc.interface.iInterface = fdp.ConsumeIntegral(); for (uint16_t idx = 0; idx < kEndpointsCount; ++idx) { desc.ep[idx].bLength = sizeof(desc.ep[idx]); desc.ep[idx].bDescriptorType = USB_DT_ENDPOINT; desc.ep[idx].bEndpointAddress = idx | (fdp.ConsumeBool() ? USB_DIR_OUT : USB_DIR_IN); desc.ep[idx].bmAttributes = fdp.ConsumeBool() ? USB_ENDPOINT_XFER_BULK : USB_ENDPOINT_XFER_INT; desc.ep[idx].wMaxPacketSize = kWMaxPacketSize; } write(fd, &desc, sizeof(fdDescriptors)); return desc; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider fdp(data, size); int32_t fd = memfd_create(kConfigFilePath.c_str(), MFD_ALLOW_SEALING); fdDescriptors descriptor = writeDescriptorsToFd(fd, fdp); std::string deviceName = fdp.ConsumeRandomLengthString(kMaxStringLength); usb_device* device = usb_device_new(deviceName.c_str(), fd); MtpDevice mtpDevice(device, fdp.ConsumeIntegral(), &descriptor.ep[0], &descriptor.ep[1], &descriptor.ep[2]); while (fdp.remaining_bytes()) { auto mtpDeviceFunction = fdp.PickValueInArray>( {[&]() { mtpDevice.getStorageIDs(); }, [&]() { mtpDevice.getStorageInfo(fdp.ConsumeIntegral() /* storageID */); }, [&]() { mtpDevice.getObjectHandles(fdp.ConsumeIntegral() /* storageID */, fdp.ConsumeIntegral() /* format */, fdp.ConsumeIntegral() /* parent */); }, [&]() { mtpDevice.initialize(); }, [&]() { int32_t outLength = 0; mtpDevice.getThumbnail(fdp.ConsumeIntegral() /* handle */, outLength); }, [&]() { MtpObjectInfo mtpObjectInfo(fdp.ConsumeIntegral() /* handle */); std::string name = fdp.ConsumeRandomLengthString(kMaxStringLength); std::string keywords = fdp.ConsumeRandomLengthString(kMaxStringLength); mtpObjectInfo.mName = strdup(name.c_str()); mtpObjectInfo.mKeywords = strdup(keywords.c_str()); mtpDevice.sendObjectInfo(&mtpObjectInfo); }, [&]() { mtpDevice.sendObject(fdp.ConsumeIntegral() /* handle */, fdp.ConsumeIntegral() /* size */, fd); }, [&]() { mtpDevice.deleteObject(fdp.ConsumeIntegral() /* handle */); }, [&]() { mtpDevice.getObjectPropsSupported( fdp.ConsumeIntegral() /* format */); }, [&]() { MtpDataType dataType = fdp.ConsumeIntegral(); MtpProperty mtpProperty(fdp.ConsumeIntegral() /* propCode */, dataType, fdp.ConsumeBool() /* writeable */, fdp.ConsumeIntegral() /* defaultValue */); if (dataType == MTP_TYPE_STR) { mtpProperty.setCurrentValue( fdp.ConsumeRandomLengthString(kMaxStringLength).c_str()); } mtpDevice.setDevicePropValueStr(&mtpProperty); }, [&]() { mtpDevice.getObjectPropDesc(fdp.ConsumeIntegral() /* code */, fdp.ConsumeIntegral() /* format */); }, [&]() { MtpProperty property; mtpDevice.getObjectPropValue(fdp.ConsumeIntegral() /* handle */, &property); }, [&]() { std::vector clientData = fdp.ConsumeBytes(kMaxDataSize); mtpDevice.readObject( fdp.ConsumeIntegral() /* handle */, readCallback, fdp.ConsumeIntegral() /* objectSize */, &clientData); }, [&]() { std::vector clientData = fdp.ConsumeBytes(kMaxDataSize); uint32_t writtenSize = 0; mtpDevice.readPartialObject(fdp.ConsumeIntegral() /* handle */, fdp.ConsumeIntegral() /* offset */, fdp.ConsumeIntegral() /* size */, &writtenSize, readCallback, &clientData); }, [&]() { std::vector clientData = fdp.ConsumeBytes(kMaxDataSize); uint32_t writtenSize = 0; mtpDevice.readPartialObject(fdp.ConsumeIntegral() /* handle */, fdp.ConsumeIntegral() /* offset */, fdp.ConsumeIntegral() /* size */, &writtenSize, readCallback, &clientData); }, [&]() { if (mtpDevice.submitEventRequest() != -1) { uint32_t parameters[3]; mtpDevice.reapEventRequest(fdp.ConsumeIntegral() /* handle */, ¶meters); } }, [&]() { mtpDevice.discardEventRequest(fdp.ConsumeIntegral() /*handle*/); }, [&]() { mtpDevice.discardEventRequest(fdp.ConsumeIntegral() /* handle */); }, [&]() { mtpDevice.print(); }, [&]() { mtpDevice.getDeviceName(); }, [&]() { mtpDevice.getObjectInfo(fdp.ConsumeIntegral() /* handle */); }, [&]() { mtpDevice.getParent(fdp.ConsumeIntegral() /* handle */); }, [&]() { mtpDevice.getStorageID(fdp.ConsumeIntegral() /* handle */); }, [&]() { mtpDevice.getDevicePropDesc(fdp.ConsumeIntegral() /* code */); }, [&]() { mtpDevice.readObject( fdp.ConsumeIntegral() /* handle */, fdp.ConsumeRandomLengthString(kMaxStringLength).c_str() /* destPath */, fdp.ConsumeIntegral() /* group */, fdp.ConsumeIntegral() /* perm */); }, [&]() { int32_t filefd = open(kConfigFilePath.c_str(), O_CREAT | O_RDWR); mtpDevice.readObject(fdp.ConsumeIntegral() /* handle */, filefd); close(filefd); }, [&]() { MtpDevice::open(deviceName.c_str(), fd); }, [&]() { MtpObjectInfo objectinfo(fdp.ConsumeIntegral() /* handle */); MtpDataPacket mtpDataPacket; MtpDevHandle devHandle; std::vector packet = fdp.ConsumeBytes(kMaxBytes); mtpDataPacket.writeData(&devHandle, packet.data(), packet.size()); objectinfo.read(mtpDataPacket); objectinfo.print(); }, [&]() { MtpStorageInfo storageInfo(fdp.ConsumeIntegral() /* id */); MtpDataPacket mtpDataPacket; MtpDevHandle devHandle; std::vector packet = fdp.ConsumeBytes(kMaxBytes); mtpDataPacket.writeData(&devHandle, packet.data(), packet.size()); storageInfo.read(mtpDataPacket); storageInfo.print(); }}); mtpDeviceFunction(); } close(fd); return 0; }