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 <stdlib.h>
18 #include <string.h>
19 #include <sys/stat.h>
20
21 #include <string>
22
23 #define LOG_TAG "MtpFuzzer"
24
25 #include <log/log.h>
26
27 #include "MtpDebug.h"
28 #include "MtpMockDatabase.h"
29 #include "MtpObjectInfo.h"
30
31 namespace android {
32
MtpMockDatabase()33 MtpMockDatabase::MtpMockDatabase() : mLastObjectHandle(0) {}
34
~MtpMockDatabase()35 MtpMockDatabase::~MtpMockDatabase() {
36 for (MtpObjectInfo* i : mObjects) {
37 delete i;
38 }
39 mObjects.clear();
40 }
41
addObject(MtpObjectInfo * info)42 void MtpMockDatabase::addObject(MtpObjectInfo* info) {
43 assert(hasStorage(info->storageID));
44
45 // we take ownership
46 mObjects.push_back(info);
47
48 return;
49 }
50
allocateObjectHandle()51 MtpObjectHandle MtpMockDatabase::allocateObjectHandle() {
52 // this is in sync with our mObjects database
53 return mLastObjectHandle++;
54 }
55
56 // Called from SendObjectInfo to reserve a database entry for the incoming file.
beginSendObject(const char * path,MtpObjectFormat format,MtpObjectHandle parent,MtpStorageID storage)57 MtpObjectHandle MtpMockDatabase::beginSendObject(const char* path, MtpObjectFormat format,
58 MtpObjectHandle parent, MtpStorageID storage) {
59 if (!hasStorage(storage)) {
60 ALOGW("%s: Tried to lookup storageID %u, but doesn't exist\n", __func__, storage);
61 return kInvalidObjectHandle;
62 }
63
64 ALOGD("MockDatabase %s: path=%s oformat=0x%04x parent_handle=%u "
65 "storage_id=%u\n",
66 __func__, path, format, parent, storage);
67
68 return mLastObjectHandle;
69 }
70
71 // Called to report success or failure of the SendObject file transfer.
endSendObject(MtpObjectHandle handle,bool succeeded)72 void MtpMockDatabase::endSendObject(MtpObjectHandle handle, bool succeeded) {
73 ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
74 }
75
76 // Called to rescan a file, such as after an edit.
rescanFile(const char * path,MtpObjectHandle handle,MtpObjectFormat format)77 void MtpMockDatabase::rescanFile(const char* path, MtpObjectHandle handle, MtpObjectFormat format) {
78 ALOGD("MockDatabase %s: path=%s ohandle=%u, oformat=0x%04x\n", __func__, path, handle, format);
79 }
80
getObjectList(MtpStorageID storageID,MtpObjectFormat format,MtpObjectHandle parent)81 MtpObjectHandleList* MtpMockDatabase::getObjectList(MtpStorageID storageID, MtpObjectFormat format,
82 MtpObjectHandle parent) {
83 ALOGD("MockDatabase %s: storage_id=%u oformat=0x%04x ohandle=%u\n", __func__, storageID, format,
84 parent);
85 return nullptr;
86 }
87
getNumObjects(MtpStorageID storageID,MtpObjectFormat format,MtpObjectHandle parent)88 int MtpMockDatabase::getNumObjects(MtpStorageID storageID, MtpObjectFormat format,
89 MtpObjectHandle parent) {
90 ALOGD("MockDatabase %s: storage_id=%u oformat=0x%04x ohandle=%u\n", __func__, storageID, format,
91 parent);
92 // TODO: return MTP_RESPONSE_OK when it stops segfaulting
93 return 0;
94 }
95
96 // callee should delete[] the results from these
97 // results can be NULL
getSupportedPlaybackFormats()98 MtpObjectFormatList* MtpMockDatabase::getSupportedPlaybackFormats() {
99 ALOGD("MockDatabase %s\n", __func__);
100 return nullptr;
101 }
getSupportedCaptureFormats()102 MtpObjectFormatList* MtpMockDatabase::getSupportedCaptureFormats() {
103 ALOGD("MockDatabase %s\n", __func__);
104 return nullptr;
105 }
getSupportedObjectProperties(MtpObjectFormat format)106 MtpObjectPropertyList* MtpMockDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
107 ALOGD("MockDatabase %s: oformat=0x%04x\n", __func__, format);
108 return nullptr;
109 }
getSupportedDeviceProperties()110 MtpDevicePropertyList* MtpMockDatabase::getSupportedDeviceProperties() {
111 ALOGD("MockDatabase %s\n", __func__);
112 return nullptr;
113 }
114
getObjectPropertyValue(MtpObjectHandle handle,MtpObjectProperty property,MtpDataPacket & packet)115 MtpResponseCode MtpMockDatabase::getObjectPropertyValue(MtpObjectHandle handle,
116 MtpObjectProperty property,
117 MtpDataPacket& packet) {
118 ALOGD("MockDatabase %s: ohandle=%u property=%s\n", __func__, handle,
119 MtpDebug::getObjectPropCodeName(property));
120 return MTP_RESPONSE_OK;
121 }
122
setObjectPropertyValue(MtpObjectHandle handle,MtpObjectProperty property,MtpDataPacket & packet)123 MtpResponseCode MtpMockDatabase::setObjectPropertyValue(MtpObjectHandle handle,
124 MtpObjectProperty property,
125 MtpDataPacket& packet) {
126 ALOGD("MockDatabase %s: ohandle=%u property=%s\n", __func__, handle,
127 MtpDebug::getObjectPropCodeName(property));
128 return MTP_RESPONSE_OK;
129 }
130
getDevicePropertyValue(MtpDeviceProperty property,MtpDataPacket & packet)131 MtpResponseCode MtpMockDatabase::getDevicePropertyValue(MtpDeviceProperty property,
132 MtpDataPacket& packet) {
133 ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
134 return MTP_RESPONSE_OK;
135 }
136
setDevicePropertyValue(MtpDeviceProperty property,MtpDataPacket & packet)137 MtpResponseCode MtpMockDatabase::setDevicePropertyValue(MtpDeviceProperty property,
138 MtpDataPacket& packet) {
139 ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
140 return MTP_RESPONSE_OK;
141 }
142
resetDeviceProperty(MtpDeviceProperty property)143 MtpResponseCode MtpMockDatabase::resetDeviceProperty(MtpDeviceProperty property) {
144 ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
145 return MTP_RESPONSE_OK;
146 }
147
getObjectPropertyList(MtpObjectHandle handle,uint32_t format,uint32_t property,int groupCode,int depth,MtpDataPacket & packet)148 MtpResponseCode MtpMockDatabase::getObjectPropertyList(MtpObjectHandle handle, uint32_t format,
149 uint32_t property, int groupCode, int depth,
150 MtpDataPacket& packet) {
151 ALOGD("MockDatabase %s: ohandle=%u format=%s property=%s groupCode=%d "
152 "depth=%d\n",
153 __func__, handle, MtpDebug::getFormatCodeName(format),
154 MtpDebug::getObjectPropCodeName(property), groupCode, depth);
155 return MTP_RESPONSE_OK;
156 }
157
getObjectInfo(MtpObjectHandle handle,MtpObjectInfo & info)158 MtpResponseCode MtpMockDatabase::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) {
159 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
160
161 // used for the root
162 if (handle == kInvalidObjectHandle) {
163 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
164 } else {
165 if (mObjects.size() == 0) {
166 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
167 }
168
169 // this is used to let the fuzzer make progress, otherwise
170 // it has to brute-force a 32-bit handle
171 MtpObjectHandle reducedHandle = handle % mObjects.size();
172 MtpObjectInfo* obj = mObjects[reducedHandle];
173
174 // make a copy, but make sure to maintain ownership of string pointers
175 info = *obj;
176
177 // fixup the response handle
178 info.mHandle = handle;
179
180 if (obj->mName) info.mName = strdup(obj->mName);
181 if (obj->mKeywords) info.mKeywords = strdup(obj->mKeywords);
182
183 return MTP_RESPONSE_OK;
184 }
185 }
186
getThumbnail(MtpObjectHandle handle,size_t & outThumbSize)187 void* MtpMockDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
188 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
189
190 size_t allocSize = handle % 0x1000;
191 void* data = calloc(allocSize, sizeof(uint8_t));
192 if (!data) {
193 return nullptr;
194 } else {
195 ALOGD("MockDatabase %s\n", __func__);
196 outThumbSize = allocSize;
197 return data;
198 }
199 }
200
getObjectFilePath(MtpObjectHandle handle,MtpStringBuffer & outFilePath,int64_t & outFileLength,MtpObjectFormat & outFormat)201 MtpResponseCode MtpMockDatabase::getObjectFilePath(MtpObjectHandle handle,
202 MtpStringBuffer& outFilePath,
203 int64_t& outFileLength,
204 MtpObjectFormat& outFormat) {
205 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
206
207 if (mObjects.size() == 0) {
208 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
209 }
210
211 // this is used to let the fuzzer make progress, otherwise
212 // it has to brute-force a 32-bit handle
213 MtpObjectHandle reducedHandle = handle % mObjects.size();
214 MtpObjectInfo* obj = mObjects[reducedHandle];
215 MtpStorage* storage = mStorage[obj->mStorageID];
216
217 // walk up the tree to build a full path of the object
218 MtpObjectHandle currentHandle = reducedHandle;
219 std::string path = "";
220
221 while (currentHandle != MTP_PARENT_ROOT) {
222 MtpObjectInfo* next = mObjects[currentHandle];
223
224 // prepend the name
225 if (path == "")
226 path = std::string(next->mName);
227 else
228 path = std::string(next->mName) + "/" + path;
229
230 currentHandle = next->mParent;
231 }
232
233 outFilePath.set(storage->getPath());
234 outFilePath.append("/");
235 outFilePath.append(path.c_str());
236
237 outFormat = obj->mFormat;
238
239 ALOGD("MockDatabase %s: get file %s\n", __func__, (const char*)outFilePath);
240
241 struct stat sstat;
242 // this should not happen unless our database view of the filesystem is out of
243 // sync
244 if (stat((const char*)outFilePath, &sstat) < 0) {
245 ALOGE("MockDatabase %s: unable to stat %s\n", __func__, (const char*)outFilePath);
246
247 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
248 }
249
250 outFileLength = sstat.st_size;
251
252 return MTP_RESPONSE_OK;
253 }
254
openFilePath(const char * path,bool transcode)255 int MtpMockDatabase::openFilePath(const char* path, bool transcode) {
256 ALOGD("MockDatabase %s: filePath=%s transcode=%d\n", __func__, path, transcode);
257 return 0;
258 }
259
beginDeleteObject(MtpObjectHandle handle)260 MtpResponseCode MtpMockDatabase::beginDeleteObject(MtpObjectHandle handle) {
261 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
262 return MTP_RESPONSE_OK;
263 }
endDeleteObject(MtpObjectHandle handle,bool succeeded)264 void MtpMockDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
265 ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
266 return;
267 }
268
getObjectReferences(MtpObjectHandle handle)269 MtpObjectHandleList* MtpMockDatabase::getObjectReferences(MtpObjectHandle handle) {
270 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
271 return nullptr;
272 }
273
setObjectReferences(MtpObjectHandle handle,MtpObjectHandleList * references)274 MtpResponseCode MtpMockDatabase::setObjectReferences(MtpObjectHandle handle,
275 MtpObjectHandleList* references) {
276 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
277 return MTP_RESPONSE_OK;
278 }
279
getObjectPropertyDesc(MtpObjectProperty property,MtpObjectFormat format)280 MtpProperty* MtpMockDatabase::getObjectPropertyDesc(MtpObjectProperty property,
281 MtpObjectFormat format) {
282 ALOGD("MockDatabase %s: property=%s format=%s\n", __func__,
283 MtpDebug::getObjectPropCodeName(property), MtpDebug::getFormatCodeName(format));
284
285 return nullptr;
286 }
287
getDevicePropertyDesc(MtpDeviceProperty property)288 MtpProperty* MtpMockDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
289 ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
290 return nullptr;
291 }
292
beginMoveObject(MtpObjectHandle handle,MtpObjectHandle newParent,MtpStorageID newStorage)293 MtpResponseCode MtpMockDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
294 MtpStorageID newStorage) {
295 ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
296 newStorage);
297 return MTP_RESPONSE_OK;
298 }
299
endMoveObject(MtpObjectHandle oldParent,MtpObjectHandle newParent,MtpStorageID oldStorage,MtpStorageID newStorage,MtpObjectHandle handle,bool succeeded)300 void MtpMockDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
301 MtpStorageID oldStorage, MtpStorageID newStorage,
302 MtpObjectHandle handle, bool succeeded) {
303 ALOGD("MockDatabase %s: oldParent=%u newParent=%u oldStorage=%u newStorage=%u "
304 "ohandle=%u succeeded=%d\n",
305 __func__, oldParent, newParent, oldStorage, newStorage, handle, succeeded);
306 return;
307 }
308
beginCopyObject(MtpObjectHandle handle,MtpObjectHandle newParent,MtpStorageID newStorage)309 MtpResponseCode MtpMockDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
310 MtpStorageID newStorage) {
311 ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
312 newStorage);
313 return MTP_RESPONSE_OK;
314 }
315
endCopyObject(MtpObjectHandle handle,bool succeeded)316 void MtpMockDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
317 ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
318 }
319
320 }; // namespace android
321