blob: 5d95aa2a9ddbe0c3867892dba3df574db556e01c [file] [log] [blame]
James Weidd2f9682020-11-09 22:42:15 +08001/*
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
31namespace android {
32
33MtpMockDatabase::MtpMockDatabase() : mLastObjectHandle(0) {}
34
35MtpMockDatabase::~MtpMockDatabase() {
36 for (MtpObjectInfo* i : mObjects) {
37 delete i;
38 }
39 mObjects.clear();
40}
41
42void MtpMockDatabase::addObject(MtpObjectInfo* info) {
43 assert(hasStorage(info->storageID));
44
45 // we take ownership
46 mObjects.push_back(info);
47
48 return;
49}
50
51MtpObjectHandle 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.
57MtpObjectHandle 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.
72void 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.
77void 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
81MtpObjectHandleList* 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
88int 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
98MtpObjectFormatList* MtpMockDatabase::getSupportedPlaybackFormats() {
99 ALOGD("MockDatabase %s\n", __func__);
100 return nullptr;
101}
102MtpObjectFormatList* MtpMockDatabase::getSupportedCaptureFormats() {
103 ALOGD("MockDatabase %s\n", __func__);
104 return nullptr;
105}
106MtpObjectPropertyList* MtpMockDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
107 ALOGD("MockDatabase %s: oformat=0x%04x\n", __func__, format);
108 return nullptr;
109}
110MtpDevicePropertyList* MtpMockDatabase::getSupportedDeviceProperties() {
111 ALOGD("MockDatabase %s\n", __func__);
112 return nullptr;
113}
114
115MtpResponseCode 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
123MtpResponseCode 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
131MtpResponseCode 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
137MtpResponseCode 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
143MtpResponseCode MtpMockDatabase::resetDeviceProperty(MtpDeviceProperty property) {
144 ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
145 return MTP_RESPONSE_OK;
146}
147
148MtpResponseCode 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
158MtpResponseCode 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
187void* 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
201MtpResponseCode 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
255MtpResponseCode MtpMockDatabase::beginDeleteObject(MtpObjectHandle handle) {
256 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
257 return MTP_RESPONSE_OK;
258}
259void MtpMockDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
260 ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
261 return;
262}
263
264MtpObjectHandleList* MtpMockDatabase::getObjectReferences(MtpObjectHandle handle) {
265 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
266 return nullptr;
267}
268
269MtpResponseCode MtpMockDatabase::setObjectReferences(MtpObjectHandle handle,
270 MtpObjectHandleList* references) {
271 ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
272 return MTP_RESPONSE_OK;
273}
274
275MtpProperty* MtpMockDatabase::getObjectPropertyDesc(MtpObjectProperty property,
276 MtpObjectFormat format) {
277 ALOGD("MockDatabase %s: property=%s format=%s\n", __func__,
278 MtpDebug::getObjectPropCodeName(property), MtpDebug::getFormatCodeName(format));
279
280 return nullptr;
281}
282
283MtpProperty* MtpMockDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
284 ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
285 return nullptr;
286}
287
288MtpResponseCode MtpMockDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
289 MtpStorageID newStorage) {
290 ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
291 newStorage);
292 return MTP_RESPONSE_OK;
293}
294
295void MtpMockDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
296 MtpStorageID oldStorage, MtpStorageID newStorage,
297 MtpObjectHandle handle, bool succeeded) {
298 ALOGD("MockDatabase %s: oldParent=%u newParent=%u oldStorage=%u newStorage=%u "
299 "ohandle=%u succeeded=%d\n",
300 __func__, oldParent, newParent, oldStorage, newStorage, handle, succeeded);
301 return;
302}
303
304MtpResponseCode MtpMockDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
305 MtpStorageID newStorage) {
306 ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
307 newStorage);
308 return MTP_RESPONSE_OK;
309}
310
311void MtpMockDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
312 ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
313}
314
315}; // namespace android