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