1 /******************************************************************************
2 *
3 * Copyright (C) 2021 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
21 #include <ServiceLog.h>
22 #include <aidl/android/media/BnResourceManagerClient.h>
23 #include <media/MediaResource.h>
24 #include <media/MediaResourcePolicy.h>
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <mediautils/ProcessInfoInterface.h>
27 #include "ResourceManagerService.h"
28 #include "fuzzer/FuzzedDataProvider.h"
29
30 using namespace std;
31 using namespace android;
32 using Status = ::ndk::ScopedAStatus;
33 using ::aidl::android::media::BnResourceManagerClient;
34 using ::aidl::android::media::IResourceManagerClient;
35 using ::aidl::android::media::IResourceManagerService;
36 using MedResType = aidl::android::media::MediaResourceType;
37 using MedResSubType = aidl::android::media::MediaResourceSubType;
38
39 const size_t kMaxStringLength = 100;
40 const int32_t kMaxServiceLog = 100;
41 const int32_t kMinServiceLog = 1;
42 const int32_t kMinResourceType = 0;
43 const int32_t kMaxResourceType = 10;
44 const int32_t kMinThreadPairs = 1;
45 const int32_t kMaxThreadPairs = 3;
46
47 const string kPolicyType[] = {IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
48 IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec};
49
50 struct resourceThreadArgs {
51 int32_t pid;
52 int32_t uid;
53 int64_t testClientId;
54 shared_ptr<ResourceManagerService> service;
55 shared_ptr<IResourceManagerClient> testClient;
56 vector<MediaResourceParcel> mediaResource;
57 };
58
getId(const shared_ptr<IResourceManagerClient> & client)59 static int64_t getId(const shared_ptr<IResourceManagerClient>& client) {
60 return (int64_t)client.get();
61 }
62
63 struct TestProcessInfo : public ProcessInfoInterface {
TestProcessInfoTestProcessInfo64 TestProcessInfo() {}
~TestProcessInfoTestProcessInfo65 virtual ~TestProcessInfo() {}
66
getPriorityTestProcessInfo67 virtual bool getPriority(int pid, int* priority) {
68 // For testing, use pid as priority.
69 // Lower the value higher the priority.
70 *priority = pid;
71 return true;
72 }
73
isPidTrustedTestProcessInfo74 virtual bool isPidTrusted(int /* pid */) { return true; }
isPidUidTrustedTestProcessInfo75 virtual bool isPidUidTrusted(int /* pid */, int /* uid */) { return true; }
overrideProcessInfoTestProcessInfo76 virtual bool overrideProcessInfo(int /* pid */, int /*procState*/, int /*oomScore*/) {
77 return true;
78 }
removeProcessInfoOverrideTestProcessInfo79 virtual void removeProcessInfoOverride(int /* pid */) { return; }
80
81 private:
82 DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
83 };
84
85 struct TestSystemCallback : public ResourceManagerService::SystemCallbackInterface {
TestSystemCallbackTestSystemCallback86 TestSystemCallback() : mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
87
88 enum EventType {
89 INVALID = -1,
90 VIDEO_ON = 0,
91 VIDEO_OFF = 1,
92 VIDEO_RESET = 2,
93 CPUSET_ENABLE = 3,
94 CPUSET_DISABLE = 4,
95 };
96
97 struct EventEntry {
98 EventType type;
99 int arg;
100 };
101
noteStartVideoTestSystemCallback102 virtual void noteStartVideo(int uid) override {
103 mLastEvent = {EventType::VIDEO_ON, uid};
104 ++mEventCount;
105 }
106
noteStopVideoTestSystemCallback107 virtual void noteStopVideo(int uid) override {
108 mLastEvent = {EventType::VIDEO_OFF, uid};
109 ++mEventCount;
110 }
111
noteResetVideoTestSystemCallback112 virtual void noteResetVideo() override {
113 mLastEvent = {EventType::VIDEO_RESET, 0};
114 ++mEventCount;
115 }
116
requestCpusetBoostTestSystemCallback117 virtual bool requestCpusetBoost(bool enable) override {
118 mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
119 ++mEventCount;
120 return true;
121 }
122
eventCountTestSystemCallback123 size_t eventCount() { return mEventCount; }
lastEventTypeTestSystemCallback124 EventType lastEventType() { return mLastEvent.type; }
lastEventTestSystemCallback125 EventEntry lastEvent() { return mLastEvent; }
126
127 protected:
~TestSystemCallbackTestSystemCallback128 virtual ~TestSystemCallback() {}
129
130 private:
131 EventEntry mLastEvent;
132 size_t mEventCount;
133
134 DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
135 };
136
137 struct TestClient : public BnResourceManagerClient {
TestClientTestClient138 TestClient(int pid, int uid, const shared_ptr<ResourceManagerService>& service)
139 : mReclaimed(false), mPid(pid), mUid(uid), mService(service) {}
140
reclaimResourceTestClient141 Status reclaimResource(bool* aidlReturn) override {
142 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
143 .uid = static_cast<int32_t>(mUid),
144 .id = getId(ref<TestClient>()),
145 .name = ""};
146 mService->removeClient(clientInfo);
147 mReclaimed = true;
148 *aidlReturn = true;
149 return Status::ok();
150 }
151
getNameTestClient152 Status getName(string* aidlReturn) override {
153 *aidlReturn = "test_client";
154 return Status::ok();
155 }
156
~TestClientTestClient157 virtual ~TestClient() {}
158
159 private:
160 bool mReclaimed;
161 int mPid;
162 int mUid;
163 shared_ptr<ResourceManagerService> mService;
164 DISALLOW_EVIL_CONSTRUCTORS(TestClient);
165 };
166
167 class ResourceManagerServiceFuzzer {
168 public:
169 ResourceManagerServiceFuzzer() = default;
~ResourceManagerServiceFuzzer()170 ~ResourceManagerServiceFuzzer() {
171 mService = nullptr;
172 delete mFuzzedDataProvider;
173 }
174 void process(const uint8_t* data, size_t size);
175
176 private:
177 void setConfig();
178 void setResources();
179 void setServiceLog();
180
addResource(void * arg)181 static void* addResource(void* arg) {
182 resourceThreadArgs* tArgs = (resourceThreadArgs*)arg;
183 if (tArgs) {
184 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(tArgs->pid),
185 .uid = static_cast<int32_t>(tArgs->uid),
186 .id = tArgs->testClientId,
187 .name = ""};
188 (tArgs->service)
189 ->addResource(clientInfo, tArgs->testClient, tArgs->mediaResource);
190 }
191 return nullptr;
192 }
193
removeResource(void * arg)194 static void* removeResource(void* arg) {
195 resourceThreadArgs* tArgs = (resourceThreadArgs*)arg;
196 if (tArgs) {
197 bool result;
198 ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(tArgs->pid),
199 .uid = static_cast<int32_t>(tArgs->uid),
200 .id = tArgs->testClientId,
201 .name = ""};
202 (tArgs->service)->markClientForPendingRemoval(clientInfo);
203 (tArgs->service)->removeResource(clientInfo, tArgs->mediaResource);
204 (tArgs->service)->reclaimResource(clientInfo, tArgs->mediaResource, &result);
205 (tArgs->service)->removeClient(clientInfo);
206 (tArgs->service)->overridePid(tArgs->pid, tArgs->pid - 1);
207 }
208 return nullptr;
209 }
210
211 shared_ptr<ResourceManagerService> mService = ResourceManagerService::Create(
212 new TestProcessInfo(),
213 new TestSystemCallback());
214 FuzzedDataProvider* mFuzzedDataProvider = nullptr;
215 };
216
process(const uint8_t * data,size_t size)217 void ResourceManagerServiceFuzzer::process(const uint8_t* data, size_t size) {
218 mFuzzedDataProvider = new FuzzedDataProvider(data, size);
219 setConfig();
220 setResources();
221 setServiceLog();
222 }
223
setConfig()224 void ResourceManagerServiceFuzzer::setConfig() {
225 bool policyTypeIndex = mFuzzedDataProvider->ConsumeBool();
226 string policyValue = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxStringLength);
227 if (mService) {
228 vector<MediaResourcePolicyParcel> policies;
229 policies.push_back(MediaResourcePolicy(kPolicyType[policyTypeIndex], policyValue));
230 mService->config(policies);
231 }
232 }
233
setResources()234 void ResourceManagerServiceFuzzer::setResources() {
235 if (!mService) {
236 return;
237 }
238 size_t numThreadPairs =
239 mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinThreadPairs, kMaxThreadPairs);
240 // Make even number of threads
241 size_t numThreads = numThreadPairs * 2;
242 resourceThreadArgs threadArgs[numThreadPairs];
243 vector<MediaResourceParcel> mediaResource[numThreadPairs];
244 pthread_t pt[numThreads];
245 for (int k = 0; k < numThreadPairs; ++k) {
246 threadArgs[k].pid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
247 threadArgs[k].uid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
248 int32_t mediaResourceType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
249 kMinResourceType, kMaxResourceType);
250 int32_t mediaResourceSubType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
251 kMinResourceType, kMaxResourceType);
252 uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
253 threadArgs[k].service = mService;
254 shared_ptr<IResourceManagerClient> testClient =
255 ::ndk::SharedRefBase::make<TestClient>(threadArgs[k].pid, threadArgs[k].uid,
256 mService);
257 threadArgs[k].testClient = testClient;
258 threadArgs[k].testClientId = getId(testClient);
259 mediaResource[k].push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
260 static_cast<MedResSubType>(mediaResourceSubType),
261 mediaResourceValue));
262 threadArgs[k].mediaResource = mediaResource[k];
263 pthread_create(&pt[2 * k], nullptr, addResource, &threadArgs[k]);
264 pthread_create(&pt[2 * k + 1], nullptr, removeResource, &threadArgs[k]);
265 }
266
267 for (int i = 0; i < numThreads; ++i) {
268 pthread_join(pt[i], nullptr);
269 }
270
271 // No resource was added with pid = 0
272 int32_t pidZero = 0;
273 shared_ptr<IResourceManagerClient> testClient =
274 ::ndk::SharedRefBase::make<TestClient>(pidZero, 0, mService);
275 int32_t mediaResourceType =
276 mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinResourceType, kMaxResourceType);
277 int32_t mediaResourceSubType =
278 mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinResourceType, kMaxResourceType);
279 uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
280 vector<MediaResourceParcel> mediaRes;
281 mediaRes.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
282 static_cast<MedResSubType>(mediaResourceSubType),
283 mediaResourceValue));
284 bool result;
285 ClientInfoParcel pidZeroClient{.pid = static_cast<int32_t>(pidZero),
286 .uid = static_cast<int32_t>(0),
287 .id = getId(testClient),
288 .name = ""};
289 mService->reclaimResource(pidZeroClient, mediaRes, &result);
290 mService->removeResource(pidZeroClient, mediaRes);
291 mService->removeClient(pidZeroClient);
292 }
293
setServiceLog()294 void ResourceManagerServiceFuzzer::setServiceLog() {
295 size_t maxNum =
296 mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinServiceLog, kMaxServiceLog);
297 sp<ServiceLog> serviceLog = new ServiceLog(maxNum);
298 if (serviceLog) {
299 serviceLog->add(String8("log"));
300 serviceLog->toString();
301 }
302 }
303
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)304 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
305 if (size < 1) {
306 return 0;
307 }
308 ResourceManagerServiceFuzzer* rmFuzzer = new ResourceManagerServiceFuzzer();
309 if (!rmFuzzer) {
310 return 0;
311 }
312 rmFuzzer->process(data, size);
313 delete rmFuzzer;
314 return 0;
315 }
316