/****************************************************************************** * * 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 #include #include #include #include #include #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 random_key( mediametrics::Item::create(fdp.ConsumeRandomLengthString())); mediaMetricsService->submit(random_key.get()); random_key->setInt32(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral()); mediaMetricsService->submit(random_key.get()); std::unique_ptr audiotrack_key( mediametrics::Item::create("audiotrack")); mediaMetricsService->submit(audiotrack_key.get()); audiotrack_key->addInt32(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral()); 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(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()); break; } case 1: { item.addInt32(key.c_str(), fdp.ConsumeIntegral()); break; } case 2: { int32_t i32 = 0; item.getInt32(key.c_str(), &i32); break; } case 3: { item.setInt64(key.c_str(), fdp.ConsumeIntegral()); break; } case 4: { item.addInt64(key.c_str(), fdp.ConsumeIntegral()); break; } case 5: { int64_t i64 = 0; item.getInt64(key.c_str(), &i64); break; } case 6: { item.setDouble(key.c_str(), fdp.ConsumeFloatingPoint()); break; } case 7: { item.addDouble(key.c_str(), fdp.ConsumeFloatingPoint()); 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(), fdp.ConsumeIntegral()); 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(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()).setUid(fdp.ConsumeIntegral()); while (fdp.remaining_bytes()) { int32_t i = fdp.ConsumeIntegral(); 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("FuzzKey"); int32_t i32 = fdp.ConsumeIntegral(); int64_t i64 = fdp.ConsumeIntegral(); double d = fdp.ConsumeFloatingPoint(); std::string str = fdp.ConsumeRandomLengthString(); std::pair pair(fdp.ConsumeIntegral(), fdp.ConsumeIntegral()); (*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("Key1"); (*item) .set("one", fdp.ConsumeIntegral()) .set("two", fdp.ConsumeIntegral()) .setTimestamp(fdp.ConsumeIntegral()); android::mediametrics::TransactionLog transactionLog( kLogItemsLowWater, kLogItemsHighWater); // keep at most 2 items transactionLog.size(); transactionLog.put(item); transactionLog.size(); auto item2 = std::make_shared("Key2"); (*item2) .set("three", fdp.ConsumeIntegral()) .set("[Key1]three", fdp.ConsumeIntegral()) .setTimestamp(fdp.ConsumeIntegral()); transactionLog.put(item2); transactionLog.size(); auto item3 = std::make_shared("Key3"); (*item3) .set("six", fdp.ConsumeIntegral()) .set("[Key1]four", fdp.ConsumeIntegral()) // affects Key1 .set("[Key1]five", fdp.ConsumeIntegral()) // affects key1 .setTimestamp(fdp.ConsumeIntegral()); 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( [&](const std::shared_ptr &) { action = true; })); } FuzzedDataProvider fdp2 = FuzzedDataProvider(data, size); while (fdp2.remaining_bytes()) { // make a test item auto item = std::make_shared(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 statsdLog = std::make_shared(10); android::mediametrics::AudioAnalytics audioAnalytics{statsdLog}; while (fdp.remaining_bytes()) { auto item = std::make_shared(fdp.ConsumeRandomLengthString().c_str()); int32_t transactionUid = fdp.ConsumeIntegral(); // arbitrary (*item) .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral()) .set(fdp.ConsumeRandomLengthString().c_str(), fdp.ConsumeIntegral()) .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid) .setUid(transactionUid) .setTimestamp(fdp.ConsumeIntegral()); 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()), [&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; }