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