166 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			166 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
}
 |