1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android-base/unique_fd.h>
18 #include <stddef.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22
23 #include <string>
24
25 #define LOG_TAG "MtpFuzzer"
26
27 #include "IMtpHandle.h"
28 #include "MtpMockDatabase.h"
29 #include "MtpMockHandle.h"
30 #include "MtpObjectInfo.h"
31 #include "MtpServer.h"
32 #include "MtpStorage.h"
33 #include "MtpUtils.h"
34
35 const char* storage_desc = "Fuzz Storage";
36 // prefer tmpfs for file operations to avoid wearing out flash
37 const char* storage_path = "/storage/fuzzer/0";
38 const char* source_database = "srcdb/";
39
40 namespace android {
41 class MtpMockServer {
42 public:
43 std::unique_ptr<MtpMockHandle> mHandle;
44 std::unique_ptr<MtpStorage> mStorage;
45 std::unique_ptr<MtpMockDatabase> mDatabase;
46 std::unique_ptr<MtpServer> mMtp;
47 int mStorageId;
48
MtpMockServer(const char * storage_path)49 MtpMockServer(const char* storage_path) : mStorageId(0) {
50 bool ptp = false;
51 const char* manu = "Google";
52 const char* model = "Pixel 3XL";
53 const char* version = "1.0";
54 const char* serial = "ABDEF1231";
55
56 // This is unused in our harness
57 int controlFd = -1;
58
59 mHandle = std::make_unique<MtpMockHandle>();
60 mStorage = std::make_unique<MtpStorage>(mStorageId, storage_path, storage_desc, true,
61 0x200000000L);
62 mDatabase = std::make_unique<MtpMockDatabase>();
63 mDatabase->addStorage(mStorage.get());
64
65 mMtp = std::make_unique<MtpServer>(mDatabase.get(), controlFd, ptp, manu, model, version,
66 serial);
67 mMtp->addStorage(mStorage.get());
68
69 // clear the old handle first, so we don't leak memory
70 delete mMtp->mHandle;
71 mMtp->mHandle = mHandle.get();
72 }
73
run()74 void run() { mMtp->run(); }
75
createDatabaseFromSourceDir(const char * fromPath,const char * toPath,MtpObjectHandle parentHandle)76 int createDatabaseFromSourceDir(const char* fromPath, const char* toPath,
77 MtpObjectHandle parentHandle) {
78 int ret = 0;
79 std::string fromPathStr(fromPath);
80 std::string toPathStr(toPath);
81
82 DIR* dir = opendir(fromPath);
83 if (!dir) {
84 ALOGE("opendir %s failed", fromPath);
85 return -1;
86 }
87 if (fromPathStr[fromPathStr.size() - 1] != '/') fromPathStr += '/';
88 if (toPathStr[toPathStr.size() - 1] != '/') toPathStr += '/';
89
90 struct dirent* entry;
91 while ((entry = readdir(dir))) {
92 const char* name = entry->d_name;
93
94 // ignore "." and ".."
95 if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
96 continue;
97 }
98
99 std::string oldFile = fromPathStr + name;
100 std::string newFile = toPathStr + name;
101
102 if (entry->d_type == DT_DIR) {
103 ret += makeFolder(newFile.c_str());
104
105 MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle());
106 objectInfo->mStorageID = mStorage->getStorageID();
107 objectInfo->mParent = parentHandle;
108 objectInfo->mFormat = MTP_FORMAT_ASSOCIATION; // folder
109 objectInfo->mName = strdup(name);
110 objectInfo->mKeywords = strdup("");
111
112 mDatabase->addObject(objectInfo);
113
114 ret += createDatabaseFromSourceDir(oldFile.c_str(), newFile.c_str(),
115 objectInfo->mHandle);
116 } else {
117 ret += copyFile(oldFile.c_str(), newFile.c_str());
118
119 MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle());
120 objectInfo->mStorageID = mStorage->getStorageID();
121 objectInfo->mParent = parentHandle;
122 objectInfo->mFormat = MTP_FORMAT_TEXT;
123 objectInfo->mName = strdup(name);
124 objectInfo->mKeywords = strdup("");
125
126 mDatabase->addObject(objectInfo);
127 }
128 }
129
130 closedir(dir);
131 return ret;
132 }
133 };
134 }; // namespace android
135
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)136 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) __attribute__((optnone)) {
137 // reset our storage (from MtpUtils.h)
138 android::deletePath(storage_path);
139 android::makeFolder("/storage/fuzzer");
140 android::makeFolder(storage_path);
141
142 std::unique_ptr<android::MtpMockServer> mtp =
143 std::make_unique<android::MtpMockServer>(storage_path);
144
145 size_t off = 0;
146
147 // Packetize the input stream
148 for (size_t i = 0; i < size; i++) {
149 // A longer delimiter could be used, but this worked in practice
150 if (data[i] == '@') {
151 size_t pktsz = i - off;
152 if (pktsz > 0) {
153 packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i);
154 // insert into packet buffer
155 mtp->mHandle->add_packet(pkt);
156 off = i;
157 }
158 }
159 }
160
161 mtp->createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT);
162 mtp->run();
163
164 return 0;
165 }
166