blob: f5784626e59a46d3b84b1b5597d13d16ded15228 [file] [log] [blame]
/*
* 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 <android-base/unique_fd.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#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<MtpMockHandle> mHandle;
std::unique_ptr<MtpStorage> mStorage;
std::unique_ptr<MtpMockDatabase> mDatabase;
std::unique_ptr<MtpServer> 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<MtpMockHandle>();
mStorage = std::make_unique<MtpStorage>(mStorageId, storage_path, storage_desc, true,
0x200000000L);
mDatabase = std::make_unique<MtpMockDatabase>();
mDatabase->addStorage(mStorage.get());
mMtp = std::make_unique<MtpServer>(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<android::MtpMockServer> mtp =
std::make_unique<android::MtpMockServer>(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;
}