/* * Copyright (C) 2020 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 #define LOG_TAG "MtpFuzzer" #include "IMtpHandle.h" #include "MtpMockDatabase.h" #include "MtpMockHandle.h" #include "MtpObjectInfo.h" #include "MtpServer.h" #include "MtpStorage.h" #include "MtpUtils.h" const char* storage_desc = "Fuzz Storage"; // prefer tmpfs for file operations to avoid wearing out flash const char* storage_path = "/storage/fuzzer/0"; const char* source_database = "srcdb/"; namespace android { class MtpMockServer { public: std::unique_ptr mHandle; std::unique_ptr mStorage; std::unique_ptr mDatabase; std::unique_ptr mMtp; int mStorageId; MtpMockServer(const char* storage_path) : mStorageId(0) { bool ptp = false; const char* manu = "Google"; const char* model = "Pixel 3XL"; const char* version = "1.0"; const char* serial = "ABDEF1231"; // This is unused in our harness int controlFd = -1; mHandle = std::make_unique(); mStorage = std::make_unique(mStorageId, storage_path, storage_desc, true, 0x200000000L); mDatabase = std::make_unique(); mDatabase->addStorage(mStorage.get()); mMtp = std::make_unique(mDatabase.get(), controlFd, ptp, manu, model, version, serial); mMtp->addStorage(mStorage.get()); // clear the old handle first, so we don't leak memory delete mMtp->mHandle; mMtp->mHandle = mHandle.get(); } void run() { mMtp->run(); } int createDatabaseFromSourceDir(const char* fromPath, const char* toPath, MtpObjectHandle parentHandle) { int ret = 0; std::string fromPathStr(fromPath); std::string toPathStr(toPath); DIR* dir = opendir(fromPath); if (!dir) { ALOGE("opendir %s failed", fromPath); return -1; } if (fromPathStr[fromPathStr.size() - 1] != '/') fromPathStr += '/'; if (toPathStr[toPathStr.size() - 1] != '/') toPathStr += '/'; struct dirent* entry; while ((entry = readdir(dir))) { const char* name = entry->d_name; // ignore "." and ".." if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { continue; } std::string oldFile = fromPathStr + name; std::string newFile = toPathStr + name; if (entry->d_type == DT_DIR) { ret += makeFolder(newFile.c_str()); MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle()); objectInfo->mStorageID = mStorage->getStorageID(); objectInfo->mParent = parentHandle; objectInfo->mFormat = MTP_FORMAT_ASSOCIATION; // folder objectInfo->mName = strdup(name); objectInfo->mKeywords = strdup(""); mDatabase->addObject(objectInfo); ret += createDatabaseFromSourceDir(oldFile.c_str(), newFile.c_str(), objectInfo->mHandle); } else { ret += copyFile(oldFile.c_str(), newFile.c_str()); MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle()); objectInfo->mStorageID = mStorage->getStorageID(); objectInfo->mParent = parentHandle; objectInfo->mFormat = MTP_FORMAT_TEXT; objectInfo->mName = strdup(name); objectInfo->mKeywords = strdup(""); mDatabase->addObject(objectInfo); } } closedir(dir); return ret; } }; }; // namespace android extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) __attribute__((optnone)) { // reset our storage (from MtpUtils.h) android::deletePath(storage_path); android::makeFolder("/storage/fuzzer"); android::makeFolder(storage_path); std::unique_ptr mtp = std::make_unique(storage_path); size_t off = 0; // Packetize the input stream for (size_t i = 0; i < size; i++) { // A longer delimiter could be used, but this worked in practice if (data[i] == '@') { size_t pktsz = i - off; if (pktsz > 0) { packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i); // insert into packet buffer mtp->mHandle->add_packet(pkt); off = i; } } } mtp->createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT); mtp->run(); return 0; }