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/ProcessInfoInterface.h>
26 #include <media/stagefright/foundation/ADebug.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
isValidPidTestProcessInfo74 virtual bool isValidPid(int /* pid */) { return true; }
overrideProcessInfoTestProcessInfo75 virtual bool overrideProcessInfo(int /* pid */, int /*procState*/, int /*oomScore*/) {
76 return true;
77 }
removeProcessInfoOverrideTestProcessInfo78 virtual void removeProcessInfoOverride(int /* pid */) { return; }
79
80 private:
81 DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
82 };
83
84 struct TestSystemCallback : public ResourceManagerService::SystemCallbackInterface {
TestSystemCallbackTestSystemCallback85 TestSystemCallback() : mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
86
87 enum EventType {
88 INVALID = -1,
89 VIDEO_ON = 0,
90 VIDEO_OFF = 1,
91 VIDEO_RESET = 2,
92 CPUSET_ENABLE = 3,
93 CPUSET_DISABLE = 4,
94 };
95
96 struct EventEntry {
97 EventType type;
98 int arg;
99 };
100
noteStartVideoTestSystemCallback101 virtual void noteStartVideo(int uid) override {
102 mLastEvent = {EventType::VIDEO_ON, uid};
103 ++mEventCount;
104 }
105
noteStopVideoTestSystemCallback106 virtual void noteStopVideo(int uid) override {
107 mLastEvent = {EventType::VIDEO_OFF, uid};
108 ++mEventCount;
109 }
110
noteResetVideoTestSystemCallback111 virtual void noteResetVideo() override {
112 mLastEvent = {EventType::VIDEO_RESET, 0};
113 ++mEventCount;
114 }
115
requestCpusetBoostTestSystemCallback116 virtual bool requestCpusetBoost(bool enable) override {
117 mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
118 ++mEventCount;
119 return true;
120 }
121
eventCountTestSystemCallback122 size_t eventCount() { return mEventCount; }
lastEventTypeTestSystemCallback123 EventType lastEventType() { return mLastEvent.type; }
lastEventTestSystemCallback124 EventEntry lastEvent() { return mLastEvent; }
125
126 protected:
~TestSystemCallbackTestSystemCallback127 virtual ~TestSystemCallback() {}
128
129 private:
130 EventEntry mLastEvent;
131 size_t mEventCount;
132
133 DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
134 };
135
136 struct TestClient : public BnResourceManagerClient {
TestClientTestClient137 TestClient(int pid, const shared_ptr<ResourceManagerService>& service)
138 : mReclaimed(false), mPid(pid), mService(service) {}
139
reclaimResourceTestClient140 Status reclaimResource(bool* aidlReturn) override {
141 mService->removeClient(mPid, getId(ref<TestClient>()));
142 mReclaimed = true;
143 *aidlReturn = true;
144 return Status::ok();
145 }
146
getNameTestClient147 Status getName(string* aidlReturn) override {
148 *aidlReturn = "test_client";
149 return Status::ok();
150 }
151
~TestClientTestClient152 virtual ~TestClient() {}
153
154 private:
155 bool mReclaimed;
156 int mPid;
157 shared_ptr<ResourceManagerService> mService;
158 DISALLOW_EVIL_CONSTRUCTORS(TestClient);
159 };
160
161 class ResourceManagerServiceFuzzer {
162 public:
163 ResourceManagerServiceFuzzer() = default;
~ResourceManagerServiceFuzzer()164 ~ResourceManagerServiceFuzzer() {
165 mService = nullptr;
166 delete mFuzzedDataProvider;
167 }
168 void process(const uint8_t* data, size_t size);
169
170 private:
171 void setConfig();
172 void setResources();
173 void setServiceLog();
174
addResource(void * arg)175 static void* addResource(void* arg) {
176 resourceThreadArgs* tArgs = (resourceThreadArgs*)arg;
177 if (tArgs) {
178 (tArgs->service)
179 ->addResource(tArgs->pid, tArgs->uid, tArgs->testClientId, tArgs->testClient,
180 tArgs->mediaResource);
181 }
182 return nullptr;
183 }
184
removeResource(void * arg)185 static void* removeResource(void* arg) {
186 resourceThreadArgs* tArgs = (resourceThreadArgs*)arg;
187 if (tArgs) {
188 bool result;
189 (tArgs->service)->markClientForPendingRemoval(tArgs->pid, tArgs->testClientId);
190 (tArgs->service)->removeResource(tArgs->pid, tArgs->testClientId, tArgs->mediaResource);
191 (tArgs->service)->reclaimResource(tArgs->pid, tArgs->mediaResource, &result);
192 (tArgs->service)->removeClient(tArgs->pid, tArgs->testClientId);
193 (tArgs->service)->overridePid(tArgs->pid, tArgs->pid - 1);
194 }
195 return nullptr;
196 }
197
198 shared_ptr<ResourceManagerService> mService =
199 ::ndk::SharedRefBase::make<ResourceManagerService>(new TestProcessInfo(),
200 new TestSystemCallback());
201 FuzzedDataProvider* mFuzzedDataProvider = nullptr;
202 };
203
process(const uint8_t * data,size_t size)204 void ResourceManagerServiceFuzzer::process(const uint8_t* data, size_t size) {
205 mFuzzedDataProvider = new FuzzedDataProvider(data, size);
206 setConfig();
207 setResources();
208 setServiceLog();
209 }
210
setConfig()211 void ResourceManagerServiceFuzzer::setConfig() {
212 bool policyTypeIndex = mFuzzedDataProvider->ConsumeBool();
213 string policyValue = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxStringLength);
214 if (mService) {
215 vector<MediaResourcePolicyParcel> policies;
216 policies.push_back(MediaResourcePolicy(kPolicyType[policyTypeIndex], policyValue));
217 mService->config(policies);
218 }
219 }
220
setResources()221 void ResourceManagerServiceFuzzer::setResources() {
222 if (!mService) {
223 return;
224 }
225 size_t numThreadPairs =
226 mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinThreadPairs, kMaxThreadPairs);
227 // Make even number of threads
228 size_t numThreads = numThreadPairs * 2;
229 resourceThreadArgs threadArgs;
230 vector<MediaResourceParcel> mediaResource;
231 pthread_t pt[numThreads];
232 int i;
233 for (i = 0; i < numThreads - 1; i += 2) {
234 threadArgs.pid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
235 threadArgs.uid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
236 int32_t mediaResourceType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
237 kMinResourceType, kMaxResourceType);
238 int32_t mediaResourceSubType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
239 kMinResourceType, kMaxResourceType);
240 uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
241 threadArgs.service = mService;
242 shared_ptr<IResourceManagerClient> testClient =
243 ::ndk::SharedRefBase::make<TestClient>(threadArgs.pid, mService);
244 threadArgs.testClient = testClient;
245 threadArgs.testClientId = getId(testClient);
246 mediaResource.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
247 static_cast<MedResSubType>(mediaResourceSubType),
248 mediaResourceValue));
249 threadArgs.mediaResource = mediaResource;
250 pthread_create(&pt[i], nullptr, addResource, &threadArgs);
251 pthread_create(&pt[i + 1], nullptr, removeResource, &threadArgs);
252 mediaResource.clear();
253 }
254
255 for (i = 0; i < numThreads; ++i) {
256 pthread_join(pt[i], nullptr);
257 }
258
259 // No resource was added with pid = 0
260 int32_t pidZero = 0;
261 shared_ptr<IResourceManagerClient> testClient =
262 ::ndk::SharedRefBase::make<TestClient>(pidZero, mService);
263 int32_t mediaResourceType =
264 mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinResourceType, kMaxResourceType);
265 int32_t mediaResourceSubType =
266 mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinResourceType, kMaxResourceType);
267 uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
268 mediaResource.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
269 static_cast<MedResSubType>(mediaResourceSubType),
270 mediaResourceValue));
271 bool result;
272 mService->reclaimResource(pidZero, mediaResource, &result);
273 mService->removeResource(pidZero, getId(testClient), mediaResource);
274 mService->removeClient(pidZero, getId(testClient));
275 mediaResource.clear();
276 }
277
setServiceLog()278 void ResourceManagerServiceFuzzer::setServiceLog() {
279 size_t maxNum =
280 mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinServiceLog, kMaxServiceLog);
281 sp<ServiceLog> serviceLog = new ServiceLog(maxNum);
282 if (serviceLog) {
283 serviceLog->add(String8("log"));
284 serviceLog->toString();
285 }
286 }
287
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)288 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
289 if (size < 1) {
290 return 0;
291 }
292 ResourceManagerServiceFuzzer* rmFuzzer = new ResourceManagerServiceFuzzer();
293 if (!rmFuzzer) {
294 return 0;
295 }
296 rmFuzzer->process(data, size);
297 delete rmFuzzer;
298 return 0;
299 }
300