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