1 /******************************************************************************
2  *
3  * Copyright (C) 2020 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19  */
20 #include <binder/IPCThreadState.h>
21 #include <fuzzer/FuzzedDataProvider.h>
22 #include <media/MediaMetricsItem.h>
23 #include <mediametricsservice/AudioTypes.h>
24 #include <mediametricsservice/MediaMetricsService.h>
25 #include <mediametricsservice/StringUtils.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <utils/Log.h>
29 #include <algorithm>
30 #include <set>
31 
32 using namespace android;
33 static constexpr size_t STATSD_LOG_LINES_MAX = 48;
34 static unsigned long long kPackedCallingUid = (unsigned long long)AID_SYSTEM << 32;
35 constexpr int8_t kMaxBytes = 100;
36 constexpr int8_t kMinBytes = 0;
37 constexpr size_t kMaxItemLength = 16;
38 
39 // low water mark
40 constexpr size_t kLogItemsLowWater = 1;
41 // high water mark
42 constexpr size_t kLogItemsHighWater = 2;
43 
44 /*
45  * Concatenating strings to generate keys in such a way that the
46  * lambda function inside AudioAnalytics() added in the 'mAction' object is covered
47  */
48 
49 std::string keyMediaValues[] = {
50         "metrics.manager",
51         "mediadrm",
52         "audio.device.a2dp",
53         AMEDIAMETRICS_KEY_AUDIO_MIDI,
54         AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*",
55         AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*",
56         AMEDIAMETRICS_KEY_AUDIO_FLINGER,
57         AMEDIAMETRICS_KEY_AUDIO_POLICY,
58         AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*",
59         AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*",
60         AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*",
61         AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
62         "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent",
63 };
64 
65 std::string keyMediaAction[] = {
66         "createAudioPatch",
67         "connected",
68         AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE,
69         AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT,
70         AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR,
71         AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM,
72         AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED,
73         AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME,
74         AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE,
75         AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP,
76 };
77 
78 class MediaMetricsServiceFuzzer {
79   public:
MediaMetricsServiceFuzzer(const uint8_t * data,size_t size)80     MediaMetricsServiceFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
81     void process();
82     void invokeStartsWith();
83     void invokeInstantiate();
84     void invokePackageInstallerCheck();
85     void invokeTimeMachineStorage();
86     void invokeTransactionLog();
87     void invokeAnalyticsAction();
88     void invokeAudioAnalytics();
89     void invokeTimedAction();
90     void setKeyValues(std::shared_ptr<mediametrics::Item>& item, std::string keyValue);
91     std::shared_ptr<mediametrics::Item> CreateItem();
92     sp<MediaMetricsService> mMediaMetricsService;
93     FuzzedDataProvider mFdp;
94     std::atomic_int mValue = 0;
95 };
96 
setKeyValues(std::shared_ptr<mediametrics::Item> & item,std::string keyValue)97 void MediaMetricsServiceFuzzer::setKeyValues(std::shared_ptr<mediametrics::Item>& item,
98                                              std::string keyValue) {
99     auto invokeActionAPIs = mFdp.PickValueInArray<const std::function<void()>>({
100             [&]() { item->setInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
101             [&]() { item->addInt32(keyValue.c_str(), mFdp.ConsumeIntegral<int32_t>()); },
102             [&]() { item->setInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
103             [&]() { item->addInt64(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>()); },
104             [&]() { item->setDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
105             [&]() { item->addDouble(keyValue.c_str(), mFdp.ConsumeFloatingPoint<double>()); },
106             [&]() { item->setTimestamp(mFdp.ConsumeIntegral<int64_t>()); },
107             [&]() {
108                 std::string value = mFdp.ConsumeBool()
109                                             ? mFdp.ConsumeRandomLengthString(kMaxBytes)
110                                             : mFdp.PickValueInArray<std::string>(keyMediaAction);
111                 item->setCString(keyValue.c_str(), value.c_str());
112             },
113             [&]() {
114                 item->setRate(keyValue.c_str(), mFdp.ConsumeIntegral<int64_t>(),
115                               mFdp.ConsumeIntegral<int64_t>());
116             },
117             [&]() {
118                 mediametrics::LogItem<1> itemTemp(mFdp.ConsumeRandomLengthString(kMaxBytes));
119                 itemTemp.setPid(mFdp.ConsumeIntegral<int16_t>())
120                         .setUid(mFdp.ConsumeIntegral<int16_t>());
121 
122                 int32_t i = mFdp.ConsumeIntegral<int32_t>();
123                 itemTemp.set(std::to_string(i).c_str(), (int32_t)i);
124                 itemTemp.updateHeader();
125                 (void)item->readFromByteString(itemTemp.getBuffer(), itemTemp.getLength());
126             },
127 
128     });
129     invokeActionAPIs();
130 }
131 
CreateItem()132 std::shared_ptr<mediametrics::Item> MediaMetricsServiceFuzzer::CreateItem() {
133     std::string key;
134     if (mFdp.ConsumeBool()) {
135         key = mFdp.ConsumeRandomLengthString(kMaxItemLength);
136     } else {
137         key = mFdp.PickValueInArray<std::string>(keyMediaValues);
138     }
139 
140     std::shared_ptr<mediametrics::Item> item = std::make_shared<mediametrics::Item>(key.c_str());
141     size_t numKeys = mFdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes);
142     std::set<std::string> keySet;
143     for (size_t i = 0; i < numKeys; ++i) {
144         std::string keyValue;
145         if (mFdp.ConsumeBool()) {
146             keyValue = mFdp.ConsumeRandomLengthString(kMaxBytes);
147         } else {
148             keyValue = mFdp.PickValueInArray<std::string>(
149                     {AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_STATE, "logSessionIkeyd"});
150         }
151         if (keySet.find(keyValue) == keySet.end()) {
152             setKeyValues(item, keyValue);
153             keySet.insert(keyValue);
154         }
155     }
156     return item;
157 }
158 
invokeStartsWith()159 void MediaMetricsServiceFuzzer::invokeStartsWith() {
160     android::mediametrics::startsWith(mFdp.ConsumeRandomLengthString(kMaxBytes),
161                                       mFdp.ConsumeRandomLengthString(kMaxBytes));
162 }
163 
invokeInstantiate()164 void MediaMetricsServiceFuzzer::invokeInstantiate() {
165     auto item = CreateItem();
166     mMediaMetricsService->submit(item.get());
167 }
168 
invokePackageInstallerCheck()169 void MediaMetricsServiceFuzzer::invokePackageInstallerCheck() {
170     MediaMetricsService::useUidForPackage(mFdp.ConsumeRandomLengthString(kMaxBytes).c_str(),
171                                           mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
172 }
173 
invokeTimeMachineStorage()174 void MediaMetricsServiceFuzzer::invokeTimeMachineStorage() {
175     auto item = CreateItem();
176     int32_t i32 = mFdp.ConsumeIntegral<int32_t>();
177     int64_t i64 = mFdp.ConsumeIntegral<int64_t>();
178     double d = mFdp.ConsumeFloatingPoint<double>();
179     std::string str = mFdp.ConsumeRandomLengthString(kMaxBytes);
180     std::pair<int64_t, int64_t> pair(mFdp.ConsumeIntegral<int64_t>(),
181                                      mFdp.ConsumeIntegral<int64_t>());
182     (*item).set("i32", i32).set("i64", i64).set("double", d).set("string", str).set("rate", pair);
183 
184     android::mediametrics::TimeMachine timeMachine;
185     timeMachine.put(item, true);
186 
187     timeMachine.get("Key", "i32", &i32, -1);
188 
189     timeMachine.get("Key", "i64", &i64, -1);
190 
191     timeMachine.get("Key", "double", &d, -1);
192 
193     timeMachine.get("Key", "string", &str, -1);
194 
195     timeMachine.get("Key.i32", &i32, -1);
196 
197     timeMachine.get("Key.i64", &i64, -1);
198 
199     timeMachine.get("Key.double", &d, -1);
200 
201     str.clear();
202     timeMachine.get("Key.string", &str, -1);
203 }
204 
invokeTransactionLog()205 void MediaMetricsServiceFuzzer::invokeTransactionLog() {
206     auto item = CreateItem();
207 
208     android::mediametrics::TransactionLog transactionLog(
209         kLogItemsLowWater, kLogItemsHighWater);  // keep at most 2 items
210     transactionLog.size();
211 
212     transactionLog.put(item);
213 }
214 
invokeAnalyticsAction()215 void MediaMetricsServiceFuzzer::invokeAnalyticsAction() {
216     mediametrics::AnalyticsActions analyticsActions;
217     bool action = false;
218 
219     analyticsActions.addAction(
220             (mFdp.ConsumeRandomLengthString(kMaxBytes) + std::string(".event")).c_str(),
221             mFdp.ConsumeRandomLengthString(kMaxBytes),
222             std::make_shared<mediametrics::AnalyticsActions::Function>(
223                     [&](const std::shared_ptr<const android::mediametrics::Item>&) {
224                         action = true;
225                     }));
226 
227     // make a test item
228     auto item = CreateItem();
229     (*item).set("event", mFdp.ConsumeRandomLengthString(kMaxBytes).c_str());
230 
231     // get the actions and execute them
232     auto actions = analyticsActions.getActionsForItem(item);
233     for (const auto& action : actions) {
234         action->operator()(item);
235         }
236 }
237 
invokeAudioAnalytics()238 void MediaMetricsServiceFuzzer::invokeAudioAnalytics() {
239     int32_t maxLogLine = mFdp.ConsumeIntegralInRange<int32_t>(0, STATSD_LOG_LINES_MAX);
240     std::shared_ptr<android::mediametrics::StatsdLog> statsdLog =
241             std::make_shared<android::mediametrics::StatsdLog>(maxLogLine);
242     android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
243 
244     auto item = CreateItem();
245     Parcel parcel;
246     item->writeToParcel(&parcel);
247     parcel.setDataPosition(0);
248     if (mFdp.ConsumeBool()) {
249         item->readFromParcel(parcel);
250     }
251     audioAnalytics.submit(item, mFdp.ConsumeBool());
252 }
253 
invokeTimedAction()254 void MediaMetricsServiceFuzzer::invokeTimedAction() {
255     android::mediametrics::TimedAction timedAction;
256     timedAction.postIn(std::chrono::seconds(mFdp.ConsumeIntegral<uint32_t>()),
257                        [this] { ++mValue; });
258     timedAction.size();
259 }
260 
process()261 void MediaMetricsServiceFuzzer::process() {
262     mMediaMetricsService = sp<MediaMetricsService>::make();
263 
264     if (mFdp.ConsumeBool()) {
265         IPCThreadState::self()->restoreCallingIdentity(kPackedCallingUid);
266     } else {
267         IPCThreadState::self()->restoreCallingIdentity(mFdp.ConsumeIntegral<size_t>());
268     }
269     while (mFdp.remaining_bytes()) {
270         auto invokeAPIs = mFdp.PickValueInArray<const std::function<void()>>({
271                 [&]() { invokeStartsWith(); },
272                 [&]() { invokeInstantiate(); },
273                 [&]() { invokePackageInstallerCheck(); },
274                 [&]() { invokeTimeMachineStorage(); },
275                 [&]() { invokeTransactionLog(); },
276                 [&]() { invokeAudioAnalytics(); },
277                 [&]() { invokeTimedAction(); },
278         });
279         invokeAPIs();
280     }
281 }
282 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)283 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
284     if (size < 1) {
285         return 0;
286     }
287     MediaMetricsServiceFuzzer mediaMetricsServiceFuzzer(data, size);
288     mediaMetricsServiceFuzzer.process();
289     return 0;
290 }
291