Loading media/mtp/tests/MtpFuzzer/Android.bp +34 −15 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import Loading @@ -6,29 +22,20 @@ package { // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["frameworks_av_media_mtp_license"], } cc_fuzz { name: "mtp_fuzzer", srcs: [ "mtp_fuzzer.cpp", "MtpMockDatabase.cpp", ], cc_defaults { name: "mtp_fuzzer_defaults", shared_libs: [ "libmtp", "libbase", "liblog", "libutils", ], static_libs: ["libc++fs",], cflags: [ "-Wall", "-Wextra", "-Werror", "-DMTP_DEVICE", "-Wno-unused-parameter", ], dictionary: "mtp_fuzzer.dict", corpus: ["corpus/*"], fuzz_config: { cc: ["jameswei@google.com"], Loading @@ -38,3 +45,15 @@ cc_fuzz { ], }, } cc_fuzz { name: "mtp_fuzzer", srcs: [ "mtp_fuzzer.cpp", "MtpMockDatabase.cpp", ], cflags: ["-DMTP_DEVICE",], shared_libs: ["libmtp",], defaults: ["mtp_fuzzer_defaults"], dictionary: "mtp_fuzzer.dict", corpus: ["corpus/*"], } media/mtp/tests/MtpFuzzer/README.md 0 → 100644 +24 −0 Original line number Diff line number Diff line # Fuzzers for libmtp ## Table of contents + [mtp_fuzzer](#MtpServer) # <a name="MtpServer"></a> Fuzzer for MtpServer MtpServer supports the following parameters: 1. PacketData (parameter name: "packetData") | Parameter| Valid Values |Configured Value| |-------------|----------|----- | |`packetData`| `String` |Value obtained from FuzzedDataProvider| #### Steps to run 1. Build the fuzzer ``` $ mm -j$(nproc) mtp_fuzzer ``` 2. Run on device ``` $ adb sync data $ adb shell /data/fuzz/arm64/mtp_fuzzer/mtp_fuzzer corpus/ -dict=mtp_fuzzer.dict ``` media/mtp/tests/MtpFuzzer/corpus/6-mtp-open_session_send_object_info.pkt 0 → 100644 +37 B File added.No diff preview for this file type. View file media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp +106 −43 Original line number Diff line number Diff line Loading @@ -14,12 +14,15 @@ * limitations under the License. */ #include <android-base/properties.h> #include <android-base/unique_fd.h> #include <fuzzer/FuzzedDataProvider.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <filesystem> #include <fstream> #include <string> #define LOG_TAG "MtpFuzzer" Loading @@ -32,38 +35,40 @@ #include "MtpStorage.h" #include "MtpUtils.h" const char* storage_desc = "Fuzz Storage"; constexpr int32_t kMinFiles = 0; constexpr int32_t kMaxFiles = 5; constexpr int32_t kMaxBytes = 128; constexpr float kMinDataSizeFactor = 0.8; // prefer tmpfs for file operations to avoid wearing out flash const char* storage_path = "/storage/fuzzer/0"; const char* source_database = "srcdb/"; const char* source_database = "/data/local/tmp/srcdb/"; const std::string test_path = std::string(source_database) + "TestDir/"; const std::string kPropertyKey = "sys.fuse.transcode_mtp"; namespace android { class MtpMockServer { public: std::unique_ptr<MtpMockHandle> mHandle; std::unique_ptr<MtpStorage> mStorage; std::unique_ptr<MtpMockDatabase> mDatabase; std::unique_ptr<MtpServer> mMtp; int mStorageId; MtpMockServer(const char* storage_path) : mStorageId(0) { bool ptp = false; const char* manu = "Google"; const char* model = "Pixel 3XL"; const char* version = "1.0"; const char* serial = "ABDEF1231"; MtpMockServer(const uint8_t* data, size_t size) : mFdp(data, size) { // This is unused in our harness int controlFd = -1; mHandle = std::make_unique<MtpMockHandle>(); mStorage = std::make_unique<MtpStorage>(mStorageId, storage_path, storage_desc, true, 0x200000000L); mStorage = std::make_unique<MtpStorage>( mFdp.ConsumeIntegral<uint32_t>() /* storageId */, storage_path, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* descriptor */, mFdp.ConsumeBool() /* removable */, mFdp.ConsumeIntegral<uint64_t>() /* maxFileSize */); mDatabase = std::make_unique<MtpMockDatabase>(); mDatabase->addStorage(mStorage.get()); mMtp = std::make_unique<MtpServer>(mDatabase.get(), controlFd, ptp, manu, model, version, serial); init(data, size); mMtp = std::make_unique<MtpServer>( mDatabase.get(), controlFd, mFdp.ConsumeBool() /* ptp */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* manu */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* model */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* version */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* serial */); mMtp->addStorage(mStorage.get()); // clear the old handle first, so we don't leak memory Loading @@ -71,7 +76,76 @@ public: mMtp->mHandle = mHandle.get(); } void run() { mMtp->run(); } void process() { if (mFdp.ConsumeBool()) { createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT); } while (mFdp.remaining_bytes()) { MtpStorage storage(mFdp.ConsumeIntegral<uint32_t>() /* id */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* filePath */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* description */, mFdp.ConsumeBool() /* removable */, mFdp.ConsumeIntegral<uint64_t>() /* maxFileSize */); auto invokeMtpServerAPI = mFdp.PickValueInArray<const std::function<void()>>({ [&]() { mMtp->run(); }, [&]() { mMtp->sendObjectAdded(mFdp.ConsumeIntegral<uint32_t>()); }, [&]() { mMtp->sendObjectRemoved(mFdp.ConsumeIntegral<uint32_t>()); }, [&]() { mMtp->sendObjectInfoChanged(mFdp.ConsumeIntegral<uint32_t>()); }, [&]() { mMtp->sendDevicePropertyChanged(mFdp.ConsumeIntegral<uint16_t>()); }, [&]() { mMtp->addStorage(&storage); }, [&]() { mMtp->removeStorage(&storage); }, }); invokeMtpServerAPI(); } std::filesystem::remove_all(source_database); } private: void createFiles(std::string path, size_t fileCount) { std::ofstream file; for (size_t idx = 0; idx < fileCount; ++idx) { file.open(path.append(std::to_string(idx))); file.close(); } } void addPackets(const uint8_t* data, size_t size) { size_t off = 0; for (size_t i = 0; i < size; ++i) { // A longer delimiter could be used, but this worked in practice if (data[i] == '@') { size_t pktsz = i - off; if (pktsz > 0) { packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i); // insert into packet buffer mHandle->add_packet(pkt); off = i; } } } } void init(const uint8_t* data, size_t size) { std::vector<uint8_t> packetData = mFdp.ConsumeBytes<uint8_t>( mFdp.ConsumeIntegralInRange<int32_t>(kMinDataSizeFactor * size, size)); // Packetize the input stream addPackets(packetData.data(), packetData.size()); // Setting the property to true/false to randomly fuzz the PoC depended on it base::SetProperty(kPropertyKey, mFdp.ConsumeBool() ? "true" : "false"); std::filesystem::create_directories(source_database); if (mFdp.ConsumeBool()) { std::filesystem::create_directories(test_path); createFiles(test_path, mFdp.ConsumeIntegralInRange<size_t>(kMinFiles, kMaxFiles)); } createFiles(source_database, mFdp.ConsumeIntegralInRange<size_t>(kMinFiles, kMaxFiles)); } int createDatabaseFromSourceDir(const char* fromPath, const char* toPath, MtpObjectHandle parentHandle) { Loading Loading @@ -130,6 +204,12 @@ public: closedir(dir); return ret; } FuzzedDataProvider mFdp; std::unique_ptr<MtpMockHandle> mHandle; std::unique_ptr<MtpStorage> mStorage; std::unique_ptr<MtpMockDatabase> mDatabase; std::unique_ptr<MtpServer> mMtp; }; }; // namespace android Loading @@ -140,26 +220,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) __attrib android::makeFolder(storage_path); std::unique_ptr<android::MtpMockServer> mtp = std::make_unique<android::MtpMockServer>(storage_path); size_t off = 0; // Packetize the input stream for (size_t i = 0; i < size; i++) { // A longer delimiter could be used, but this worked in practice if (data[i] == '@') { size_t pktsz = i - off; if (pktsz > 0) { packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i); // insert into packet buffer mtp->mHandle->add_packet(pkt); off = i; } } } mtp->createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT); mtp->run(); std::make_unique<android::MtpMockServer>(data, size); mtp->process(); std::filesystem::remove_all("/storage/fuzzer"); return 0; } Loading
media/mtp/tests/MtpFuzzer/Android.bp +34 −15 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import Loading @@ -6,29 +22,20 @@ package { // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["frameworks_av_media_mtp_license"], } cc_fuzz { name: "mtp_fuzzer", srcs: [ "mtp_fuzzer.cpp", "MtpMockDatabase.cpp", ], cc_defaults { name: "mtp_fuzzer_defaults", shared_libs: [ "libmtp", "libbase", "liblog", "libutils", ], static_libs: ["libc++fs",], cflags: [ "-Wall", "-Wextra", "-Werror", "-DMTP_DEVICE", "-Wno-unused-parameter", ], dictionary: "mtp_fuzzer.dict", corpus: ["corpus/*"], fuzz_config: { cc: ["jameswei@google.com"], Loading @@ -38,3 +45,15 @@ cc_fuzz { ], }, } cc_fuzz { name: "mtp_fuzzer", srcs: [ "mtp_fuzzer.cpp", "MtpMockDatabase.cpp", ], cflags: ["-DMTP_DEVICE",], shared_libs: ["libmtp",], defaults: ["mtp_fuzzer_defaults"], dictionary: "mtp_fuzzer.dict", corpus: ["corpus/*"], }
media/mtp/tests/MtpFuzzer/README.md 0 → 100644 +24 −0 Original line number Diff line number Diff line # Fuzzers for libmtp ## Table of contents + [mtp_fuzzer](#MtpServer) # <a name="MtpServer"></a> Fuzzer for MtpServer MtpServer supports the following parameters: 1. PacketData (parameter name: "packetData") | Parameter| Valid Values |Configured Value| |-------------|----------|----- | |`packetData`| `String` |Value obtained from FuzzedDataProvider| #### Steps to run 1. Build the fuzzer ``` $ mm -j$(nproc) mtp_fuzzer ``` 2. Run on device ``` $ adb sync data $ adb shell /data/fuzz/arm64/mtp_fuzzer/mtp_fuzzer corpus/ -dict=mtp_fuzzer.dict ```
media/mtp/tests/MtpFuzzer/corpus/6-mtp-open_session_send_object_info.pkt 0 → 100644 +37 B File added.No diff preview for this file type. View file
media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp +106 −43 Original line number Diff line number Diff line Loading @@ -14,12 +14,15 @@ * limitations under the License. */ #include <android-base/properties.h> #include <android-base/unique_fd.h> #include <fuzzer/FuzzedDataProvider.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <filesystem> #include <fstream> #include <string> #define LOG_TAG "MtpFuzzer" Loading @@ -32,38 +35,40 @@ #include "MtpStorage.h" #include "MtpUtils.h" const char* storage_desc = "Fuzz Storage"; constexpr int32_t kMinFiles = 0; constexpr int32_t kMaxFiles = 5; constexpr int32_t kMaxBytes = 128; constexpr float kMinDataSizeFactor = 0.8; // prefer tmpfs for file operations to avoid wearing out flash const char* storage_path = "/storage/fuzzer/0"; const char* source_database = "srcdb/"; const char* source_database = "/data/local/tmp/srcdb/"; const std::string test_path = std::string(source_database) + "TestDir/"; const std::string kPropertyKey = "sys.fuse.transcode_mtp"; namespace android { class MtpMockServer { public: std::unique_ptr<MtpMockHandle> mHandle; std::unique_ptr<MtpStorage> mStorage; std::unique_ptr<MtpMockDatabase> mDatabase; std::unique_ptr<MtpServer> mMtp; int mStorageId; MtpMockServer(const char* storage_path) : mStorageId(0) { bool ptp = false; const char* manu = "Google"; const char* model = "Pixel 3XL"; const char* version = "1.0"; const char* serial = "ABDEF1231"; MtpMockServer(const uint8_t* data, size_t size) : mFdp(data, size) { // This is unused in our harness int controlFd = -1; mHandle = std::make_unique<MtpMockHandle>(); mStorage = std::make_unique<MtpStorage>(mStorageId, storage_path, storage_desc, true, 0x200000000L); mStorage = std::make_unique<MtpStorage>( mFdp.ConsumeIntegral<uint32_t>() /* storageId */, storage_path, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* descriptor */, mFdp.ConsumeBool() /* removable */, mFdp.ConsumeIntegral<uint64_t>() /* maxFileSize */); mDatabase = std::make_unique<MtpMockDatabase>(); mDatabase->addStorage(mStorage.get()); mMtp = std::make_unique<MtpServer>(mDatabase.get(), controlFd, ptp, manu, model, version, serial); init(data, size); mMtp = std::make_unique<MtpServer>( mDatabase.get(), controlFd, mFdp.ConsumeBool() /* ptp */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* manu */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* model */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* version */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* serial */); mMtp->addStorage(mStorage.get()); // clear the old handle first, so we don't leak memory Loading @@ -71,7 +76,76 @@ public: mMtp->mHandle = mHandle.get(); } void run() { mMtp->run(); } void process() { if (mFdp.ConsumeBool()) { createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT); } while (mFdp.remaining_bytes()) { MtpStorage storage(mFdp.ConsumeIntegral<uint32_t>() /* id */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* filePath */, mFdp.ConsumeRandomLengthString(kMaxBytes).c_str() /* description */, mFdp.ConsumeBool() /* removable */, mFdp.ConsumeIntegral<uint64_t>() /* maxFileSize */); auto invokeMtpServerAPI = mFdp.PickValueInArray<const std::function<void()>>({ [&]() { mMtp->run(); }, [&]() { mMtp->sendObjectAdded(mFdp.ConsumeIntegral<uint32_t>()); }, [&]() { mMtp->sendObjectRemoved(mFdp.ConsumeIntegral<uint32_t>()); }, [&]() { mMtp->sendObjectInfoChanged(mFdp.ConsumeIntegral<uint32_t>()); }, [&]() { mMtp->sendDevicePropertyChanged(mFdp.ConsumeIntegral<uint16_t>()); }, [&]() { mMtp->addStorage(&storage); }, [&]() { mMtp->removeStorage(&storage); }, }); invokeMtpServerAPI(); } std::filesystem::remove_all(source_database); } private: void createFiles(std::string path, size_t fileCount) { std::ofstream file; for (size_t idx = 0; idx < fileCount; ++idx) { file.open(path.append(std::to_string(idx))); file.close(); } } void addPackets(const uint8_t* data, size_t size) { size_t off = 0; for (size_t i = 0; i < size; ++i) { // A longer delimiter could be used, but this worked in practice if (data[i] == '@') { size_t pktsz = i - off; if (pktsz > 0) { packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i); // insert into packet buffer mHandle->add_packet(pkt); off = i; } } } } void init(const uint8_t* data, size_t size) { std::vector<uint8_t> packetData = mFdp.ConsumeBytes<uint8_t>( mFdp.ConsumeIntegralInRange<int32_t>(kMinDataSizeFactor * size, size)); // Packetize the input stream addPackets(packetData.data(), packetData.size()); // Setting the property to true/false to randomly fuzz the PoC depended on it base::SetProperty(kPropertyKey, mFdp.ConsumeBool() ? "true" : "false"); std::filesystem::create_directories(source_database); if (mFdp.ConsumeBool()) { std::filesystem::create_directories(test_path); createFiles(test_path, mFdp.ConsumeIntegralInRange<size_t>(kMinFiles, kMaxFiles)); } createFiles(source_database, mFdp.ConsumeIntegralInRange<size_t>(kMinFiles, kMaxFiles)); } int createDatabaseFromSourceDir(const char* fromPath, const char* toPath, MtpObjectHandle parentHandle) { Loading Loading @@ -130,6 +204,12 @@ public: closedir(dir); return ret; } FuzzedDataProvider mFdp; std::unique_ptr<MtpMockHandle> mHandle; std::unique_ptr<MtpStorage> mStorage; std::unique_ptr<MtpMockDatabase> mDatabase; std::unique_ptr<MtpServer> mMtp; }; }; // namespace android Loading @@ -140,26 +220,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) __attrib android::makeFolder(storage_path); std::unique_ptr<android::MtpMockServer> mtp = std::make_unique<android::MtpMockServer>(storage_path); size_t off = 0; // Packetize the input stream for (size_t i = 0; i < size; i++) { // A longer delimiter could be used, but this worked in practice if (data[i] == '@') { size_t pktsz = i - off; if (pktsz > 0) { packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i); // insert into packet buffer mtp->mHandle->add_packet(pkt); off = i; } } } mtp->createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT); mtp->run(); std::make_unique<android::MtpMockServer>(data, size); mtp->process(); std::filesystem::remove_all("/storage/fuzzer"); return 0; }