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