1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <libmtp.h>
16 #include "libmtp_fuzzer.h"
17
18 #include <cstddef>
19 #include <cstdint>
20 #include <algorithm>
21
22 namespace OHOS {
23 constexpr size_t MIN_STORAGE_SIZE = sizeof(uint16_t) * 3 + sizeof(uint32_t) + sizeof(uint64_t) * 3 + sizeof(char *) * 2;
24 constexpr size_t MIN_EXTENSION_SIZE = sizeof(char *) + sizeof(int) * 2;
25 constexpr size_t MIN_MTPDEVICE_SIZE = sizeof(uint8_t) * 2 + sizeof(uint32_t) * 8 + sizeof(int);
26 constexpr size_t MIN_SIZE = std::max({MIN_STORAGE_SIZE, MIN_EXTENSION_SIZE, MIN_MTPDEVICE_SIZE});
27 constexpr size_t MIN_RAWDEVICE_SIZE = sizeof(uint32_t) * 2 + sizeof(uint16_t) * 2 +
28 sizeof(uint8_t) + sizeof(int) + sizeof(char *) * 2;
29 constexpr size_t MIN_FOLDER_SIZE = sizeof(uint32_t) * 3 + sizeof(char *);
30 constexpr size_t MIN_FILE_SIZE = sizeof(uint32_t) * 3 + sizeof(uint64_t) + sizeof(char *) +
31 sizeof(time_t) + sizeof(LIBMTP_filetype_t);
32
33 template<class T>
TypeCast(const uint8_t * data,int * pos=nullptr)34 T TypeCast(const uint8_t *data, int *pos = nullptr)
35 {
36 if (pos) {
37 *pos += sizeof(T);
38 }
39 return *(reinterpret_cast<const T*>(data));
40 }
41
ConstructRawDevice(const uint8_t * data,size_t size,LIBMTP_device_entry_t * entry,LIBMTP_raw_device_t * device)42 int ConstructRawDevice(const uint8_t *data, size_t size, LIBMTP_device_entry_t *entry, LIBMTP_raw_device_t *device)
43 {
44 int pos = 0;
45 if (entry != nullptr) {
46 entry->vendor = TypeCast<char*>(data, &pos);
47 entry->product = TypeCast<char*>(data + pos);
48 entry->vendor_id = TypeCast<uint16_t>(data + pos);
49 entry->product_id = TypeCast<uint16_t>(data + pos);
50 entry->device_flags = TypeCast<uint32_t>(data + pos);
51 device->bus_location = TypeCast<uint32_t>(data + pos);
52 device->devnum = TypeCast<uint8_t>(data + pos);
53 device->device_entry = *entry;
54 }
55 return pos;
56 }
57
ConstructDeviceStorage(const uint8_t * data,size_t size,LIBMTP_devicestorage_t * storage)58 void ConstructDeviceStorage(const uint8_t *data, size_t size, LIBMTP_devicestorage_t *storage)
59 {
60 int pos = 0;
61 if (storage != nullptr) {
62 storage->id = TypeCast<uint32_t>(data, &pos);
63 storage->StorageType = TypeCast<uint16_t>(data + pos);
64 storage->FilesystemType = TypeCast<uint16_t>(data + pos);
65 storage->AccessCapability = TypeCast<uint16_t>(data + pos);
66 storage->MaxCapacity = TypeCast<uint64_t>(data + pos);
67 storage->FreeSpaceInBytes = TypeCast<uint64_t>(data + pos);
68 storage->FreeSpaceInObjects = TypeCast<uint64_t>(data + pos);
69 storage->StorageDescription = TypeCast<char*>(data + pos);
70 storage->VolumeIdentifier = TypeCast<char*>(data + pos);
71 storage->next = nullptr;
72 storage->prev = nullptr;
73 }
74 }
75
ConstructDeviceExtension(const uint8_t * data,size_t size,LIBMTP_device_extension_t * extensions)76 void ConstructDeviceExtension(const uint8_t *data, size_t size, LIBMTP_device_extension_t *extensions)
77 {
78 int pos = 0;
79 if (extensions != nullptr) {
80 extensions->name = TypeCast<char*>(data + pos);
81 extensions->major = TypeCast<int>(data + pos);
82 extensions->minor = TypeCast<int>(data + pos);
83 extensions->next = nullptr;
84 }
85 }
86
ConstructMtpDevice(const uint8_t * data,size_t size,LIBMTP_mtpdevice_t * device)87 int ConstructMtpDevice(const uint8_t *data, size_t size, LIBMTP_mtpdevice_t *device)
88 {
89 if (data == nullptr || size <= MIN_SIZE) {
90 return 0;
91 }
92 LIBMTP_devicestorage_t storage;
93 LIBMTP_device_extension_t extensions;
94 LIBMTP_error_t errorStack;
95
96 int pos = 0;
97 if (device == nullptr) {
98 return 0;
99 }
100 device->object_bitsize = TypeCast<uint8_t>(data, &pos);
101 ConstructDeviceStorage(data, size, &storage);
102 device->storage = &storage;
103 errorStack = TypeCast<LIBMTP_error_t>(data + pos);
104 device->errorstack = &errorStack;
105 device->maximum_battery_level = TypeCast<uint8_t>(data + pos);
106 device->default_music_folder = TypeCast<uint32_t>(data + pos);
107 device->default_playlist_folder = TypeCast<uint32_t>(data + pos);
108 device->default_picture_folder = TypeCast<uint32_t>(data + pos);
109 device->default_video_folder = TypeCast<uint32_t>(data + pos);
110 device->default_organizer_folder = TypeCast<uint32_t>(data + pos);
111 device->default_zencast_folder = TypeCast<uint32_t>(data + pos);
112 device->default_album_folder = TypeCast<uint32_t>(data + pos);
113 device->default_text_folder = TypeCast<uint32_t>(data + pos);
114 ConstructDeviceExtension(data, size, &extensions);
115 device->extensions = &extensions;
116 device->cached = TypeCast<int>(data + pos);
117 device->next = nullptr;
118
119 return pos;
120 }
121
ConstructFolder(const uint8_t * data,size_t size,int pos,LIBMTP_folder_t * folder)122 int ConstructFolder(const uint8_t *data, size_t size, int pos, LIBMTP_folder_t *folder)
123 {
124 if (folder != nullptr) {
125 folder->folder_id = TypeCast<uint32_t>(data + pos);
126 folder->parent_id = TypeCast<uint32_t>(data + pos);
127 folder->storage_id = TypeCast<uint32_t>(data + pos);
128 folder->name = TypeCast<char*>(data + pos);
129 folder->sibling = nullptr;
130 folder->child = nullptr;
131 }
132 }
133
ConstructFile(const uint8_t * data,size_t size,int pos,LIBMTP_file_t * file)134 int ConstructFile(const uint8_t *data, size_t size, int pos, LIBMTP_file_t *file)
135 {
136 if (file != nullptr) {
137 file->item_id = TypeCast<uint32_t>(data + pos);
138 file->parent_id = TypeCast<uint32_t>(data + pos);
139 file->storage_id = TypeCast<uint32_t>(data + pos);
140 file->filename = TypeCast<char*>(data + pos);
141 file->filesize = TypeCast<uint64_t>(data + pos);
142 file->modificationdate = TypeCast<time_t>(data + pos);
143 file->filetype = TypeCast<LIBMTP_filetype_t>(data + pos);
144 file->next = nullptr;
145 }
146 }
147
CheckSpecificDeviceFuzzTest(const uint8_t * data,size_t size)148 bool CheckSpecificDeviceFuzzTest(const uint8_t *data, size_t size)
149 {
150 int numPara32 = 2;
151 if (data == nullptr || size <= sizeof(int) * numPara32) {
152 return false;
153 }
154
155 int pos = 0;
156 int busno = TypeCast<int>(data, &pos);
157 int devno = TypeCast<int>(data + pos);
158
159 LIBMTP_Check_Specific_Device(busno, devno);
160 return true;
161 }
162
OpenRawDeviceUncachedTest(const uint8_t * data,size_t size)163 bool OpenRawDeviceUncachedTest(const uint8_t *data, size_t size)
164 {
165 if (data == nullptr || size <= MIN_RAWDEVICE_SIZE) {
166 return false;
167 }
168
169 LIBMTP_device_entry_t entry;
170 LIBMTP_raw_device_t device;
171 ConstructRawDevice(data, size, &entry, &device);
172
173 LIBMTP_mtpdevice_t *ret = LIBMTP_Open_Raw_Device_Uncached(&device);
174 if (ret == NULL) {
175 return false;
176 }
177 return true;
178 }
179
DetectRawDevicesTest(const uint8_t * data,size_t size)180 bool DetectRawDevicesTest(const uint8_t *data, size_t size)
181 {
182 if (data == nullptr || size <= MIN_RAWDEVICE_SIZE) {
183 return false;
184 }
185
186 LIBMTP_device_entry_t entry;
187 LIBMTP_raw_device_t *device;
188 int pos = ConstructRawDevice(data, size, &entry, device);
189 int numdevs = TypeCast<int>(data + pos);
190
191 LIBMTP_error_number_t result = LIBMTP_Detect_Raw_Devices(&device, &numdevs);
192 if (result != 0) {
193 return false;
194 }
195 return true;
196 }
197
ReleaseDeviceTest(const uint8_t * data,size_t size)198 bool ReleaseDeviceTest(const uint8_t *data, size_t size)
199 {
200 if (data == nullptr || size <= MIN_SIZE) {
201 return false;
202 }
203 LIBMTP_mtpdevice_t mtpDevice;
204 int ret = ConstructMtpDevice(data, size, &mtpDevice);
205 LIBMTP_Release_Device(&mtpDevice);
206 return true;
207 }
208
GetFilesAndFoldersTest(const uint8_t * data,size_t size)209 bool GetFilesAndFoldersTest(const uint8_t *data, size_t size)
210 {
211 int numPara32 = 2;
212 if (data == nullptr || size <= MIN_SIZE + sizeof(uint32_t) * numPara32) {
213 return false;
214 }
215 LIBMTP_mtpdevice_t mtpDevice;
216 int pos = ConstructMtpDevice(data, size, &mtpDevice);
217 uint32_t storage = TypeCast<uint32_t>(data + pos);
218 uint32_t parent = TypeCast<uint32_t>(data + pos);
219 LIBMTP_file_t *ret = LIBMTP_Get_Files_And_Folders(&mtpDevice, storage, parent);
220 if (ret == NULL) {
221 return false;
222 }
223 return true;
224 }
225
CreateFolderTest(const uint8_t * data,size_t size)226 bool CreateFolderTest(const uint8_t *data, size_t size)
227 {
228 int numPara32 = 2;
229 if (data == nullptr || size <= MIN_SIZE + sizeof(uint32_t) * numPara32 + sizeof(char*)) {
230 return false;
231 }
232 LIBMTP_mtpdevice_t mtpDevice;
233 int pos = ConstructMtpDevice(data, size, &mtpDevice);
234 char* name = TypeCast<char*>(data + pos);
235 uint32_t parentId = TypeCast<uint32_t>(data + pos);
236 uint32_t storageId = TypeCast<uint32_t>(data + pos);
237 uint32_t ret = LIBMTP_Create_Folder(&mtpDevice, name, parentId, storageId);
238 if (ret == 0) {
239 return false;
240 }
241 return true;
242 }
243
SetFolderNameTest(const uint8_t * data,size_t size)244 bool SetFolderNameTest(const uint8_t *data, size_t size)
245 {
246 if (data == nullptr || size <= MIN_SIZE + MIN_FOLDER_SIZE + sizeof(char*)) {
247 return false;
248 }
249 LIBMTP_mtpdevice_t mtpDevice;
250 LIBMTP_folder_t folder;
251 int pos = ConstructMtpDevice(data, size, &mtpDevice);
252 pos = ConstructFolder(data, size, pos, &folder);
253 char* newName = TypeCast<char*>(data + pos);
254 uint32_t ret = LIBMTP_Set_Folder_Name(&mtpDevice, &folder, newName);
255 if (ret != 0) {
256 return false;
257 }
258 return true;
259 }
260
GetFileToFileTest(const uint8_t * data,size_t size)261 bool GetFileToFileTest(const uint8_t *data, size_t size)
262 {
263 if (data == nullptr || size <= MIN_SIZE + sizeof(uint32_t) + sizeof(LIBMTP_progressfunc_t)
264 + sizeof(char const *const) + sizeof(void const *const)) {
265 return false;
266 }
267 LIBMTP_mtpdevice_t mtpDevice;
268
269 int pos = ConstructMtpDevice(data, size, &mtpDevice);
270 uint32_t id = TypeCast<uint32_t>(data + pos);
271 char const *const path = TypeCast<char const *const>(data + pos);
272 LIBMTP_progressfunc_t const callback = TypeCast<LIBMTP_progressfunc_t const>(data + pos);
273 void const * const userData = TypeCast<void const * const>(data + pos);
274
275 int ret = LIBMTP_Get_File_To_File(&mtpDevice, id, path, callback, userData);
276 if (ret != 0) {
277 return false;
278 }
279 return true;
280 }
281
SendFileFromFileTest(const uint8_t * data,size_t size)282 bool SendFileFromFileTest(const uint8_t *data, size_t size)
283 {
284 if (data == nullptr || size <= MIN_SIZE + MIN_FILE_SIZE + sizeof(LIBMTP_progressfunc_t)
285 + sizeof(char const *const) + sizeof(void const *const)) {
286 return false;
287 }
288 LIBMTP_mtpdevice_t mtpDevice;
289 LIBMTP_file_t file;
290 int pos = ConstructMtpDevice(data, size, &mtpDevice);
291 char const *const path = TypeCast<char const *const>(data + pos);
292 pos = ConstructFile(data, size, pos, &file);
293 LIBMTP_progressfunc_t const callback = TypeCast<LIBMTP_progressfunc_t const>(data + pos);
294 void const * const userData = TypeCast<void const * const>(data + pos);
295
296 int ret = LIBMTP_Send_File_From_File(&mtpDevice, path, &file, callback, userData);
297 if (ret != 0) {
298 return false;
299 }
300 return true;
301 }
302
SetFileNameTest(const uint8_t * data,size_t size)303 bool SetFileNameTest(const uint8_t *data, size_t size)
304 {
305 if (data == nullptr || size <= MIN_SIZE + MIN_FILE_SIZE + sizeof(const char*)) {
306 return false;
307 }
308 LIBMTP_mtpdevice_t mtpDevice;
309 LIBMTP_file_t file;
310 int pos = ConstructMtpDevice(data, size, &mtpDevice);
311 pos = ConstructFile(data, size, pos, &file);
312 char *newName = TypeCast<char *>(data + pos);
313
314 int ret = LIBMTP_Set_File_Name(&mtpDevice, &file, newName);
315 if (ret != 0) {
316 return false;
317 }
318 return true;
319 }
320
DeleteObjectTest(const uint8_t * data,size_t size)321 bool DeleteObjectTest(const uint8_t *data, size_t size)
322 {
323 if (data == nullptr || size <= MIN_SIZE + sizeof(uint32_t)) {
324 return false;
325 }
326 LIBMTP_mtpdevice_t mtpDevice;
327 int pos = ConstructMtpDevice(data, size, &mtpDevice);
328 uint32_t objectId = TypeCast<uint32_t>(data + pos);
329
330 int ret = LIBMTP_Delete_Object(&mtpDevice, objectId);
331 if (ret != 0) {
332 return false;
333 }
334 return true;
335 }
336
SetObjectU32Test(const uint8_t * data,size_t size)337 bool SetObjectU32Test(const uint8_t *data, size_t size)
338 {
339 int numPara32 = 2;
340 if (data == nullptr || size <= MIN_SIZE + sizeof(uint32_t const) * numPara32 + sizeof(LIBMTP_property_t const)) {
341 return false;
342 }
343 LIBMTP_mtpdevice_t mtpDevice;
344 int pos = ConstructMtpDevice(data, size, &mtpDevice);
345 uint32_t const objectId = TypeCast<uint32_t const>(data + pos);
346 LIBMTP_property_t const attributeId = TypeCast<LIBMTP_property_t const>(data + pos);
347 uint32_t const value = TypeCast<uint32_t const>(data + pos);
348
349 int ret = LIBMTP_Set_Object_u32(&mtpDevice, objectId, attributeId, value);
350 if (ret != 0) {
351 return false;
352 }
353 return true;
354 }
355
SetObjectStringTest(const uint8_t * data,size_t size)356 bool SetObjectStringTest(const uint8_t *data, size_t size)
357 {
358 if (data == nullptr || size <= MIN_SIZE + sizeof(uint32_t const) +
359 sizeof(LIBMTP_property_t const) + sizeof(char const *const)) {
360 return false;
361 }
362 LIBMTP_mtpdevice_t mtpDevice;
363 int pos = ConstructMtpDevice(data, size, &mtpDevice);
364 uint32_t const objectId = TypeCast<uint32_t const>(data + pos);
365 LIBMTP_property_t const attributeId = TypeCast<LIBMTP_property_t const>(data + pos);
366 char const * const string = TypeCast<char const * const>(data + pos);
367
368 int ret = LIBMTP_Set_Object_String(&mtpDevice, objectId, attributeId, string);
369 if (ret != 0) {
370 return false;
371 }
372 return true;
373 }
374
GetPartialObjectTest(const uint8_t * data,size_t size)375 bool GetPartialObjectTest(const uint8_t *data, size_t size)
376 {
377 int numPara32 = 2;
378 size_t sizeReq = MIN_SIZE + sizeof(uint32_t const) * numPara32 +
379 sizeof(uint64_t const) + sizeof(unsigned int) + sizeof(unsigned char*);
380 if (data == nullptr || size <= sizeReq) {
381 return false;
382 }
383 LIBMTP_mtpdevice_t mtpDevice;
384 int pos = ConstructMtpDevice(data, size, &mtpDevice);
385 uint32_t const id = TypeCast<uint32_t const>(data + pos);
386 uint64_t offset = TypeCast<uint64_t>(data + pos);
387 uint32_t maxbytes = TypeCast<uint32_t>(data + pos);
388 unsigned char* paraData = TypeCast<unsigned char*>(data + pos);
389 unsigned int paraSize = TypeCast<unsigned int>(data + pos);
390
391 int ret = LIBMTP_GetPartialObject(&mtpDevice, id, offset, maxbytes, ¶Data, ¶Size);
392 if (ret == -1) {
393 return false;
394 }
395 return true;
396 }
397
SendPartialObjectTest(const uint8_t * data,size_t size)398 bool SendPartialObjectTest(const uint8_t *data, size_t size)
399 {
400 size_t sizeReq = MIN_SIZE + sizeof(uint32_t const) + sizeof(uint64_t const) +
401 sizeof(unsigned int) + sizeof(unsigned char);
402 if (data == nullptr || size <= sizeReq) {
403 return false;
404 }
405 LIBMTP_mtpdevice_t mtpDevice;
406 int pos = ConstructMtpDevice(data, size, &mtpDevice);
407 uint32_t const id = TypeCast<uint32_t const>(data + pos);
408 uint64_t offset = TypeCast<uint64_t>(data + pos);
409 unsigned char paraData = TypeCast<unsigned char>(data + pos);
410 unsigned int paraSize = TypeCast<unsigned int>(data + pos);
411
412 int ret = LIBMTP_SendPartialObject(&mtpDevice, id, offset, ¶Data, paraSize);
413 if (ret == -1) {
414 return false;
415 }
416 return true;
417 }
418
GetStorageTest(const uint8_t * data,size_t size)419 bool GetStorageTest(const uint8_t *data, size_t size)
420 {
421 if (data == nullptr || size <= MIN_SIZE + sizeof(int)) {
422 return false;
423 }
424 LIBMTP_mtpdevice_t mtpDevice;
425 int pos = ConstructMtpDevice(data, size, &mtpDevice);
426 int sortby = TypeCast<int>(data + pos);
427 int ret = LIBMTP_Get_Storage(&mtpDevice, sortby);
428 if (ret == -1) {
429 return false;
430 }
431 return true;
432 }
433
CheckCapabilityTest(const uint8_t * data,size_t size)434 bool CheckCapabilityTest(const uint8_t *data, size_t size)
435 {
436 if (data == nullptr || size <= MIN_SIZE) {
437 return false;
438 }
439 LIBMTP_mtpdevice_t mtpDevice;
440 LIBMTP_devicecap_t cap;
441 ConstructMtpDevice(data, size, &mtpDevice);
442 if (&mtpDevice == NULL || mtpDevice.params == NULL) {
443 return true;
444 } else {
445 cap = LIBMTP_DEVICECAP_GetPartialObject;
446 LIBMTP_Check_Capability(&mtpDevice, cap);
447 cap = LIBMTP_DEVICECAP_SendPartialObject;
448 LIBMTP_Check_Capability(&mtpDevice, cap);
449 cap = LIBMTP_DEVICECAP_EditObjects;
450 LIBMTP_Check_Capability(&mtpDevice, cap);
451 cap = LIBMTP_DEVICECAP_MoveObject;
452 LIBMTP_Check_Capability(&mtpDevice, cap);
453 cap = LIBMTP_DEVICECAP_CopyObject;
454 LIBMTP_Check_Capability(&mtpDevice, cap);
455 }
456 return true;
457 }
458
DumpErrorstackTest(const uint8_t * data,size_t size)459 bool DumpErrorstackTest(const uint8_t *data, size_t size)
460 {
461 if (data == nullptr || size <= MIN_SIZE) {
462 return false;
463 }
464 LIBMTP_mtpdevice_t mtpDevice;
465 ConstructMtpDevice(data, size, &mtpDevice);
466 LIBMTP_Dump_Errorstack(&mtpDevice);
467 return true;
468 }
469
ClearErrorstackTest(const uint8_t * data,size_t size)470 bool ClearErrorstackTest(const uint8_t *data, size_t size)
471 {
472 if (data == nullptr || size <= MIN_SIZE) {
473 return false;
474 }
475 LIBMTP_mtpdevice_t mtpDevice;
476 ConstructMtpDevice(data, size, &mtpDevice);
477 LIBMTP_Clear_Errorstack(&mtpDevice);
478 return true;
479 }
480 } // namespace OHOS
481
482 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)483 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
484 {
485 /* Run your code on data */
486 OHOS::CheckSpecificDeviceFuzzTest(data, size);
487 OHOS::OpenRawDeviceUncachedTest(data, size);
488 OHOS::DetectRawDevicesTest(data, size);
489 OHOS::ReleaseDeviceTest(data, size);
490 OHOS::GetFilesAndFoldersTest(data, size);
491 OHOS::CreateFolderTest(data, size);
492 OHOS::SetFolderNameTest(data, size);
493 OHOS::GetFileToFileTest(data, size);
494 OHOS::SendFileFromFileTest(data, size);
495 OHOS::SetFileNameTest(data, size);
496 OHOS::DeleteObjectTest(data, size);
497 OHOS::SetObjectU32Test(data, size);
498 OHOS::SetObjectStringTest(data, size);
499 OHOS::GetPartialObjectTest(data, size);
500 OHOS::SendPartialObjectTest(data, size);
501 OHOS::GetStorageTest(data, size);
502 OHOS::CheckCapabilityTest(data, size);
503 OHOS::DumpErrorstackTest(data, size);
504 OHOS::ClearErrorstackTest(data, size);
505 return 0;
506 }