| /****************************************************************************** |
| * |
| * Copyright (C) 2020 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. |
| * |
| ***************************************************************************** |
| * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore |
| */ |
| #include <fuzzer/FuzzedDataProvider.h> |
| #include <media/MediaMetricsItem.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <utils/Log.h> |
| #include <algorithm> |
| |
| #include "AudioTypes.h" |
| #include "MediaMetricsService.h" |
| #include "StringUtils.h" |
| |
| using namespace android; |
| |
| // low water mark |
| constexpr size_t kLogItemsLowWater = 1; |
| // high water mark |
| constexpr size_t kLogItemsHighWater = 2; |
| |
| class MediaMetricsServiceFuzzer { |
| public: |
| void invokeStartsWith(const uint8_t *data, size_t size); |
| void invokeInstantiate(const uint8_t *data, size_t size); |
| void invokePackageInstallerCheck(const uint8_t *data, size_t size); |
| void invokeItemManipulation(const uint8_t *data, size_t size); |
| void invokeItemExpansion(const uint8_t *data, size_t size); |
| void invokeTimeMachineStorage(const uint8_t *data, size_t size); |
| void invokeTransactionLog(const uint8_t *data, size_t size); |
| void invokeAnalyticsAction(const uint8_t *data, size_t size); |
| void invokeAudioAnalytics(const uint8_t *data, size_t size); |
| void invokeTimedAction(const uint8_t *data, size_t size); |
| void process(const uint8_t *data, size_t size); |
| }; |
| |
| void MediaMetricsServiceFuzzer::invokeStartsWith(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| while (fdp.remaining_bytes()) { |
| android::mediametrics::startsWith(fdp.ConsumeRandomLengthString(), |
| fdp.ConsumeRandomLengthString()); |
| } |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeInstantiate(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| sp mediaMetricsService = new MediaMetricsService(); |
| |
| while (fdp.remaining_bytes()) { |
| std::unique_ptr<mediametrics::Item> random_key( |
| mediametrics::Item::create(fdp.ConsumeRandomLengthString())); |
| mediaMetricsService->submit(random_key.get()); |
| random_key->setInt32(fdp.ConsumeRandomLengthString().c_str(), |
| fdp.ConsumeIntegral<int32_t>()); |
| mediaMetricsService->submit(random_key.get()); |
| |
| std::unique_ptr<mediametrics::Item> audiotrack_key( |
| mediametrics::Item::create("audiotrack")); |
| mediaMetricsService->submit(audiotrack_key.get()); |
| audiotrack_key->addInt32(fdp.ConsumeRandomLengthString().c_str(), |
| fdp.ConsumeIntegral<int32_t>()); |
| mediaMetricsService->submit(audiotrack_key.get()); |
| } |
| } |
| |
| void MediaMetricsServiceFuzzer::invokePackageInstallerCheck(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| while (fdp.remaining_bytes()) { |
| MediaMetricsService::useUidForPackage(fdp.ConsumeRandomLengthString().c_str(), |
| fdp.ConsumeRandomLengthString().c_str()); |
| } |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeItemManipulation(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| |
| mediametrics::Item item(fdp.ConsumeRandomLengthString().c_str()); |
| while (fdp.remaining_bytes()) { |
| const uint8_t action = fdp.ConsumeIntegralInRange<uint8_t>(0, 16); |
| const std::string key = fdp.ConsumeRandomLengthString(); |
| if (fdp.remaining_bytes() < 1 || key.length() < 1) { |
| break; |
| } |
| switch (action) { |
| case 0: { |
| item.setInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>()); |
| break; |
| } |
| case 1: { |
| item.addInt32(key.c_str(), fdp.ConsumeIntegral<int32_t>()); |
| break; |
| } |
| case 2: { |
| int32_t i32 = 0; |
| item.getInt32(key.c_str(), &i32); |
| break; |
| } |
| case 3: { |
| item.setInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>()); |
| break; |
| } |
| case 4: { |
| item.addInt64(key.c_str(), fdp.ConsumeIntegral<int64_t>()); |
| break; |
| } |
| case 5: { |
| int64_t i64 = 0; |
| item.getInt64(key.c_str(), &i64); |
| break; |
| } |
| case 6: { |
| item.setDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>()); |
| break; |
| } |
| case 7: { |
| item.addDouble(key.c_str(), fdp.ConsumeFloatingPoint<double>()); |
| break; |
| } |
| case 8: { |
| double d = 0; |
| item.getDouble(key.c_str(), &d); |
| break; |
| } |
| case 9: { |
| item.setCString(key.c_str(), fdp.ConsumeRandomLengthString().c_str()); |
| break; |
| } |
| case 10: { |
| char *s = nullptr; |
| item.getCString(key.c_str(), &s); |
| if (s) free(s); |
| break; |
| } |
| case 11: { |
| std::string s; |
| item.getString(key.c_str(), &s); |
| break; |
| } |
| case 12: { |
| item.setRate(key.c_str(), fdp.ConsumeIntegral<int64_t>(), |
| fdp.ConsumeIntegral<int64_t>()); |
| break; |
| } |
| case 13: { |
| int64_t b = 0, h = 0; |
| double d = 0; |
| item.getRate(key.c_str(), &b, &h, &d); |
| break; |
| } |
| case 14: { |
| (void)item.filter(key.c_str()); |
| break; |
| } |
| case 15: { |
| const char *arr[1] = {""}; |
| arr[0] = const_cast<char *>(key.c_str()); |
| (void)item.filterNot(1, arr); |
| break; |
| } |
| case 16: { |
| (void)item.toString().c_str(); |
| break; |
| } |
| } |
| } |
| |
| Parcel p; |
| mediametrics::Item item2; |
| |
| (void)item.writeToParcel(&p); |
| p.setDataPosition(0); // rewind for reading |
| (void)item2.readFromParcel(p); |
| |
| char *byteData = nullptr; |
| size_t length = 0; |
| (void)item.writeToByteString(&byteData, &length); |
| (void)item2.readFromByteString(byteData, length); |
| if (byteData) { |
| free(byteData); |
| } |
| |
| sp mediaMetricsService = new MediaMetricsService(); |
| mediaMetricsService->submit(&item2); |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeItemExpansion(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| |
| mediametrics::LogItem<1> item("FuzzItem"); |
| item.setPid(fdp.ConsumeIntegral<int16_t>()).setUid(fdp.ConsumeIntegral<int16_t>()); |
| |
| while (fdp.remaining_bytes()) { |
| int32_t i = fdp.ConsumeIntegral<int32_t>(); |
| item.set(std::to_string(i).c_str(), (int32_t)i); |
| } |
| item.updateHeader(); |
| |
| mediametrics::Item item2; |
| (void)item2.readFromByteString(item.getBuffer(), item.getLength()); |
| |
| sp mediaMetricsService = new MediaMetricsService(); |
| mediaMetricsService->submit(&item2); |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeTimeMachineStorage(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| |
| auto item = std::make_shared<mediametrics::Item>("FuzzKey"); |
| int32_t i32 = fdp.ConsumeIntegral<int32_t>(); |
| int64_t i64 = fdp.ConsumeIntegral<int64_t>(); |
| double d = fdp.ConsumeFloatingPoint<double>(); |
| std::string str = fdp.ConsumeRandomLengthString(); |
| std::pair<int64_t, int64_t> pair(fdp.ConsumeIntegral<int64_t>(), |
| fdp.ConsumeIntegral<int64_t>()); |
| (*item).set("i32", i32).set("i64", i64).set("double", d).set("string", str).set("rate", pair); |
| |
| android::mediametrics::TimeMachine timeMachine; |
| timeMachine.put(item, true); |
| |
| timeMachine.get("Key", "i32", &i32, -1); |
| |
| timeMachine.get("Key", "i64", &i64, -1); |
| |
| timeMachine.get("Key", "double", &d, -1); |
| |
| timeMachine.get("Key", "string", &str, -1); |
| |
| timeMachine.get("Key.i32", &i32, -1); |
| |
| timeMachine.get("Key.i64", &i64, -1); |
| |
| timeMachine.get("Key.double", &d, -1); |
| |
| str.clear(); |
| timeMachine.get("Key.string", &str, -1); |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeTransactionLog(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| |
| auto item = std::make_shared<mediametrics::Item>("Key1"); |
| (*item) |
| .set("one", fdp.ConsumeIntegral<int32_t>()) |
| .set("two", fdp.ConsumeIntegral<int32_t>()) |
| .setTimestamp(fdp.ConsumeIntegral<int32_t>()); |
| |
| android::mediametrics::TransactionLog transactionLog( |
| kLogItemsLowWater, kLogItemsHighWater); // keep at most 2 items |
| transactionLog.size(); |
| |
| transactionLog.put(item); |
| transactionLog.size(); |
| |
| auto item2 = std::make_shared<mediametrics::Item>("Key2"); |
| (*item2) |
| .set("three", fdp.ConsumeIntegral<int32_t>()) |
| .set("[Key1]three", fdp.ConsumeIntegral<int32_t>()) |
| .setTimestamp(fdp.ConsumeIntegral<int32_t>()); |
| |
| transactionLog.put(item2); |
| transactionLog.size(); |
| |
| auto item3 = std::make_shared<mediametrics::Item>("Key3"); |
| (*item3) |
| .set("six", fdp.ConsumeIntegral<int32_t>()) |
| .set("[Key1]four", fdp.ConsumeIntegral<int32_t>()) // affects Key1 |
| .set("[Key1]five", fdp.ConsumeIntegral<int32_t>()) // affects key1 |
| .setTimestamp(fdp.ConsumeIntegral<int32_t>()); |
| |
| transactionLog.put(item3); |
| transactionLog.size(); |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeAnalyticsAction(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| |
| mediametrics::AnalyticsActions analyticsActions; |
| bool action = false; |
| |
| while (fdp.remaining_bytes()) { |
| analyticsActions.addAction( |
| (fdp.ConsumeRandomLengthString() + std::string(".event")).c_str(), |
| fdp.ConsumeRandomLengthString(), |
| std::make_shared<mediametrics::AnalyticsActions::Function>( |
| [&](const std::shared_ptr<const android::mediametrics::Item> &) { |
| action = true; |
| })); |
| } |
| |
| FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size); |
| |
| while (fdp2.remaining_bytes()) { |
| // make a test item |
| auto item = std::make_shared<mediametrics::Item>(fdp2.ConsumeRandomLengthString().c_str()); |
| (*item).set("event", fdp2.ConsumeRandomLengthString().c_str()); |
| |
| // get the actions and execute them |
| auto actions = analyticsActions.getActionsForItem(item); |
| for (const auto &action : actions) { |
| action->operator()(item); |
| } |
| } |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeAudioAnalytics(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| std::shared_ptr<android::mediametrics::StatsdLog> statsdLog = |
| std::make_shared<android::mediametrics::StatsdLog>(10); |
| android::mediametrics::AudioAnalytics audioAnalytics{statsdLog}; |
| |
| while (fdp.remaining_bytes()) { |
| auto item = std::make_shared<mediametrics::Item>(fdp.ConsumeRandomLengthString().c_str()); |
| int32_t transactionUid = fdp.ConsumeIntegral<int32_t>(); // arbitrary |
| (*item) |
| .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>()) |
| .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral<int32_t>()) |
| .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid) |
| .setUid(transactionUid) |
| .setTimestamp(fdp.ConsumeIntegral<int32_t>()); |
| audioAnalytics.submit(item, fdp.ConsumeBool()); |
| } |
| |
| audioAnalytics.dump(1000); |
| } |
| |
| void MediaMetricsServiceFuzzer::invokeTimedAction(const uint8_t *data, size_t size) { |
| FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| android::mediametrics::TimedAction timedAction; |
| std::atomic_int value = 0; |
| |
| while (fdp.remaining_bytes()) { |
| timedAction.postIn(std::chrono::seconds(fdp.ConsumeIntegral<int32_t>()), |
| [&value] { ++value; }); |
| timedAction.size(); |
| } |
| } |
| |
| void MediaMetricsServiceFuzzer::process(const uint8_t *data, size_t size) { |
| invokeStartsWith(data, size); |
| invokeInstantiate(data, size); |
| invokePackageInstallerCheck(data, size); |
| invokeItemManipulation(data, size); |
| invokeItemExpansion(data, size); |
| invokeTimeMachineStorage(data, size); |
| invokeTransactionLog(data, size); |
| invokeAnalyticsAction(data, size); |
| invokeAudioAnalytics(data, size); |
| invokeTimedAction(data, size); |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
| if (size < 1) { |
| return 0; |
| } |
| MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer; |
| mediaMetricsServiceFuzzer.process(data, size); |
| return 0; |
| } |