1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ressched_fuzzer.h"
17 
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <securec.h>
22 #include <vector>
23 #include <unordered_set>
24 #include <random>
25 
26 #include "iremote_stub.h"
27 #include "ires_sched_service.h"
28 #include "iservice_registry.h"
29 #include "oobe_datashare_utils.h"
30 #include "oobe_manager.h"
31 #include "ioobe_task.h"
32 #include "plugin_mgr.h"
33 #include "res_sched_service.h"
34 #include "singleton.h"
35 #include "system_ability_definition.h"
36 #include "slide_recognizer.h"
37 #include "ffrt_inner.h"
38 #include "res_sched_client.h"
39 #include "res_sched_service_stub.h"
40 #include "res_sched_systemload_notifier_client.h"
41 #include "res_sched_systemload_notifier_proxy.h"
42 #include "notifier_mgr.h"
43 #include "res_type.h"
44 #include "accesstoken_kit.h"
45 #include "token_setproc.h"
46 
47 #define private public
48 #define protected public
49 
50 #ifndef errno_t
51 typedef int errno_t;
52 #endif
53 
54 #ifndef EOK
55 #define EOK 0
56 #endif
57 
58 namespace OHOS {
59 namespace ResourceSchedule {
60 namespace {
61     static const int32_t TWO_PARAMETERS = 2;
62 
63     static const std::unordered_set<uint32_t> THIRDPARTY_RES = {
64         ResType::RES_TYPE_CLICK_RECOGNIZE,
65         ResType::RES_TYPE_PUSH_PAGE,
66         ResType::RES_TYPE_SLIDE_RECOGNIZE,
67         ResType::RES_TYPE_POP_PAGE,
68         ResType::RES_TYPE_LOAD_PAGE,
69         ResType::RES_TYPE_WEB_GESTURE,
70         ResType::RES_TYPE_REPORT_KEY_THREAD,
71         ResType::RES_TYPE_REPORT_WINDOW_STATE,
72         ResType::RES_TYPE_REPORT_SCENE_SCHED,
73         ResType::RES_TYPE_WEB_GESTURE_MOVE,
74         ResType::RES_TYPE_WEB_SLIDE_NORMAL,
75         ResType::RES_TYPE_LOAD_URL,
76         ResType::RES_TYPE_MOUSEWHEEL,
77         ResType::RES_TYPE_WEBVIEW_AUDIO_STATUS_CHANGE,
78         ResType::RES_TYPE_REPORT_RENDER_THREAD,
79         ResType::RES_TYPE_LONG_FRAME,
80         ResType::RES_TYPE_AUDIO_SILENT_PLAYBACK,
81         ResType::RES_TYPE_REPORT_DISTRIBUTE_TID,
82         ResType::RES_TYPE_WEBVIEW_SCREEN_CAPTURE,
83         ResType::RES_TYPE_WEBVIEW_VIDEO_STATUS_CHANGE,
84         ResType::RES_TYPE_BT_SERVICE_EVENT
85     };
86 
87     static const std::unordered_map<uint32_t, std::vector<std::string>> RESTYPE_TO_PARAMS = {
88         {ResType::RES_TYPE_CLICK_RECOGNIZE, {"clientPid", "name"}},
89         {ResType::RES_TYPE_PUSH_PAGE, {"pageUrl"}},
90         {ResType::RES_TYPE_SLIDE_RECOGNIZE, {"clientPid"}},
91         {ResType::RES_TYPE_POP_PAGE, {}},
92         {ResType::RES_TYPE_LOAD_PAGE, {}},
93         {ResType::RES_TYPE_WEB_GESTURE, {}},
94         {ResType::RES_TYPE_REPORT_KEY_THREAD, {"uid", "pid", "tid", "role"}},
95         {ResType::RES_TYPE_REPORT_WINDOW_STATE, {"uid", "pid", "windowId", "serialNum", "state"}},
96         {ResType::RES_TYPE_REPORT_SCENE_SCHED, {"uid", "sceneId"}},
97         {ResType::RES_TYPE_WEB_GESTURE_MOVE, {}},
98         {ResType::RES_TYPE_WEB_SLIDE_NORMAL, {}},
99         {ResType::RES_TYPE_LOAD_URL, {}},
100         {ResType::RES_TYPE_MOUSEWHEEL, {}},
101         {ResType::RES_TYPE_WEBVIEW_AUDIO_STATUS_CHANGE, {"uid", "pid", "tid"}},
102         {ResType::RES_TYPE_REPORT_RENDER_THREAD, {"uid", "pid"}},
103         {ResType::RES_TYPE_LONG_FRAME, {"pid", "uid", "bundleName", "abilityName"}},
104         {ResType::RES_TYPE_AUDIO_SILENT_PLAYBACK, {"uid"}},
105         {ResType::RES_TYPE_REPORT_DISTRIBUTE_TID, {"uid", "pid"}},
106         {ResType::RES_TYPE_WEBVIEW_SCREEN_CAPTURE, {"uid", "pid"}},
107         {ResType::RES_TYPE_WEBVIEW_VIDEO_STATUS_CHANGE, {"uid", "pid"}},
108         {ResType::RES_TYPE_BT_SERVICE_EVENT, {"ADDRESS", "STATE", "ROLE", "CONNECTIF", "STATUS"}}
109     };
110 
111     static const int32_t DEFAULT_API_VERSION = 11;
112     static const int32_t PAYLOAD_MAX_SIZE = 3500;
113 
114     Security::AccessToken::PermissionStateFull HapState = {
115         .permissionName = "",
116         .isGeneral = true,
117         .resDeviceID = {"local"},
118         .grantStatus = {Security::AccessToken::PermissionState::PERMISSION_GRANTED},
119         .grantFlags = {1}
120     };
121 
122     Security::AccessToken::HapPolicyParams HapPolicyParams = {
123         .apl = Security::AccessToken::APL_SYSTEM_BASIC,
124         .domain = "test.domain.ressched",
125         .permList = {},
126         .permStateList = {HapState}
127     };
128 
129     Security::AccessToken::HapInfoParams info = {
130         .userID = 100,
131         .bundleName = "com.hos.ressched",
132         .instIndex = 0,
133         .appIDDesc = "thirdParty",
134         .apiVersion = DEFAULT_API_VERSION,
135         .isSystemApp = false
136     };
137 }
138 
139     constexpr int32_t MAX_CODE = 5;
140     constexpr int32_t MIN_LEN = 4;
141     std::mutex mutexLock;
142     sptr<IRemoteObject> remoteObj;
143     const uint8_t* g_data = nullptr;
144     size_t g_size = 0;
145     size_t g_pos;
146 
147     /**
148      * describe: get data from outside untrusted data(g_data) which size is according to sizeof(T)
149      * tips: only support basic type
150      */
151     template<class T>
GetData()152     T GetData()
153     {
154         T object {};
155         size_t objectSize = sizeof(object);
156         if (g_data == nullptr || objectSize > g_size - g_pos) {
157             return object;
158         }
159         errno_t ret = memcpy_s(&object, objectSize, g_data + g_pos, objectSize);
160         if (ret != EOK) {
161             return {};
162         }
163         g_pos += objectSize;
164         return object;
165     }
166 
GetStringFromData(int strlen)167     std::string GetStringFromData(int strlen)
168     {
169         if (strlen <= 0) {
170             return "";
171         }
172         char cstr[strlen];
173         cstr[strlen - 1] = '\0';
174         for (int i = 0; i < strlen - 1; i++) {
175             char tmp = GetData<char>();
176             if (tmp == '\0') {
177                 tmp = '1';
178             }
179             cstr[i] = tmp;
180         }
181         std::string str(cstr);
182         return str;
183     }
184 
DoInit()185     bool DoInit()
186     {
187         std::lock_guard<std::mutex> lock(mutexLock);
188         if (remoteObj) {
189             return true;
190         }
191         auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
192         if (!samgr) {
193             return false;
194         }
195         remoteObj = samgr->GetSystemAbility(RES_SCHED_SYS_ABILITY_ID);
196         if (!remoteObj) {
197             return false;
198         }
199         return true;
200     }
201 
onRemoteRequest(uint32_t code, MessageParcel& data)202     int32_t onRemoteRequest(uint32_t code, MessageParcel& data)
203     {
204         if (!DoInit()) {
205             return -1;
206         }
207         MessageParcel reply;
208         MessageOption option;
209         return remoteObj->SendRequest(code, data, reply, option);
210     }
211 
DoSomethingInterestingWithMyAPI(const uint8_t* data, size_t size)212     bool DoSomethingInterestingWithMyAPI(const uint8_t* data, size_t size)
213     {
214         if (size <= MIN_LEN) {
215             return false;
216         }
217 
218         MessageParcel dataMessageParcel;
219         if (!dataMessageParcel.WriteInterfaceToken(IRemoteStub<IResSchedService>::GetDescriptor())) {
220             return false;
221         }
222 
223         uint32_t code = *(reinterpret_cast<const uint32_t*>(data));
224         size -= sizeof(uint32_t);
225 
226         dataMessageParcel.WriteBuffer(data + sizeof(uint32_t), size);
227         dataMessageParcel.RewindRead(0);
228 
229         onRemoteRequest(code, dataMessageParcel);
230         return true;
231     }
232 
OnRemoteRequest(const uint8_t* data, size_t size)233     bool OnRemoteRequest(const uint8_t* data, size_t size)
234     {
235         if (data == nullptr) {
236             return false;
237         }
238 
239         if (size <= MIN_LEN) {
240             return false;
241         }
242 
243         // initialize
244         g_data = data;
245         g_size = size;
246         g_pos = 0;
247 
248         // getdata
249         uint32_t fuzzCode = GetData<uint32_t>();
250         MessageParcel fuzzData;
251         fuzzData.WriteInterfaceToken(ResSchedServiceStub::GetDescriptor());
252         fuzzData.WriteBuffer(g_data + g_pos, g_size - g_pos);
253         fuzzData.RewindRead(0);
254         MessageParcel fuzzReply;
255         MessageOption fuzzOption;
256         DelayedSingleton<ResSchedService>::GetInstance()->OnRemoteRequest(fuzzCode % MAX_CODE,
257             fuzzData, fuzzReply, fuzzOption);
258         return true;
259     }
260 
SyncEventFuzzTest(const uint8_t* data, size_t size)261     bool SyncEventFuzzTest(const uint8_t* data, size_t size)
262     {
263         if (data == nullptr) {
264             return false;
265         }
266 
267         if (size <= MIN_LEN) {
268             return false;
269         }
270 
271         // initialize
272         g_data = data;
273         g_size = size;
274         g_pos = 0;
275 
276         // getdata
277         MessageParcel fuzzData;
278         fuzzData.WriteInterfaceToken(ResSchedServiceStub::GetDescriptor());
279         fuzzData.WriteBuffer(g_data + g_pos, g_size - g_pos);
280         fuzzData.RewindRead(0);
281         MessageParcel fuzzReply;
282         DelayedSingleton<ResSchedService>::GetInstance()->ReportSyncEventInner(fuzzData, fuzzReply);
283         return true;
284     }
285 
ResSchedClientFuzzTest(const uint8_t* data, size_t size)286     bool ResSchedClientFuzzTest(const uint8_t* data, size_t size)
287     {
288         if (data == nullptr) {
289             return false;
290         }
291 
292         if (size <= sizeof(uint32_t) + sizeof(int64_t) + TWO_PARAMETERS * sizeof(std::string)) {
293             return false;
294         }
295 
296         // initialize
297         g_data = data;
298         g_size = size;
299         g_pos = 0;
300 
301         uint32_t resType = GetData<uint32_t>();
302         int64_t value = GetData<int64_t>();
303         std::unordered_map<std::string, std::string> mapPayload;
304         mapPayload["pid"] = GetStringFromData(int(size) - sizeof(uint32_t) - sizeof(int64_t));
305         mapPayload["processName"] = GetStringFromData(int(size) - sizeof(std::string) -
306         sizeof(uint32_t) - sizeof(int64_t));
307 
308         ResSchedClient::GetInstance().ReportData(resType, value, mapPayload);
309         ResSchedClient::GetInstance().KillProcess(mapPayload);
310         ResSchedClient::GetInstance().StopRemoteObject();
311 
312         sptr<ResSchedSystemloadNotifierClient> callbackObj;
313         ResSchedClient::GetInstance().RegisterSystemloadNotifier(callbackObj);
314         ResSchedClient::GetInstance().UnRegisterSystemloadNotifier(callbackObj);
315         ResSchedClient::GetInstance().GetSystemloadLevel();
316         return true;
317     }
318 
OnSystemloadLevelFuzzTest(const uint8_t* data, size_t size)319     bool OnSystemloadLevelFuzzTest(const uint8_t* data, size_t size)
320     {
321         if (data == nullptr) {
322             return false;
323         }
324 
325         // initialize
326         g_data = data;
327         g_size = size;
328         g_pos = 0;
329 
330         int32_t level = GetData<int32_t>();
331         if (!DoInit()) {
332             return false;
333         }
334         auto resSchedSystemloadNotifierProxy = std::make_unique<ResSchedSystemloadNotifierProxy>(remoteObj);
335         resSchedSystemloadNotifierProxy->OnSystemloadLevel(level);
336         return true;
337     }
338 
NotifierMgrFuzzTest(const uint8_t* data, size_t size)339     bool NotifierMgrFuzzTest(const uint8_t* data, size_t size)
340     {
341         if (data == nullptr) {
342             return false;
343         }
344 
345         // initialize
346         g_data = data;
347         g_size = size;
348         g_pos = 0;
349 
350         int32_t pid = GetData<int32_t>();
351         int32_t type = GetData<int32_t>();
352         int32_t level = GetData<int32_t>();
353         int32_t state = GetData<int32_t>();
354         if (!DoInit()) {
355             return false;
356         }
357 
358         NotifierMgr::GetInstance().Init();
359         NotifierMgr::GetInstance().RegisterNotifier(pid, remoteObj);
360         NotifierMgr::GetInstance().UnRegisterNotifier(pid);
361         NotifierMgr::GetInstance().OnRemoteNotifierDied(remoteObj);
362         NotifierMgr::GetInstance().OnDeviceLevelChanged(type, level);
363         NotifierMgr::GetInstance().OnApplicationStateChange(state, level);
364         NotifierMgr::GetInstance().GetSystemloadLevel();
365         NotifierMgr::GetInstance().DumpRegisterInfo();
366         NotifierMgr::GetInstance().Deinit();
367         return true;
368     }
369 
SlideRecognizerFuzzTest(const uint8_t* data, size_t size)370     bool SlideRecognizerFuzzTest(const uint8_t* data, size_t size)
371     {
372         if (data == nullptr) {
373             return false;
374         }
375 
376         if (size <= sizeof(uint32_t) + sizeof(int64_t)) {
377             return false;
378         }
379 
380         uint32_t resType = GetData<uint32_t>();
381         int64_t value = GetData<int64_t>();
382         nlohmann::json payload;
383         auto slideRecognizer = std::make_shared<SlideRecognizer>();
384         slideRecognizer->SetListFlingTimeoutTime(0);
385         slideRecognizer->SetListFlingEndTime(0);
386         slideRecognizer->OnDispatchResource(resType, value, payload);
387         slideRecognizer->HandleSlideDetecting(payload);
388         slideRecognizer->HandleSlideEvent(value, payload);
389         slideRecognizer->HandleListFlingStart(payload);
390         slideRecognizer->HandleSendFrameEvent(payload);
391         slideRecognizer->HandleClickEvent(value, payload);
392         slideRecognizer->HandleSlideOFFEvent();
393         if (slideRecognizer->listFlingEndTask_) {
394             ffrt::skip(slideRecognizer->listFlingEndTask_);
395         }
396         if (slideRecognizer->listFlingTimeOutTask_) {
397             ffrt::skip(slideRecognizer->listFlingTimeOutTask_);
398         }
399         return true;
400     }
401 
OOBEManagerFuzzTest(const uint8_t* data, size_t size)402     bool OOBEManagerFuzzTest(const uint8_t* data, size_t size)
403     {
404         if (data == nullptr) {
405             return false;
406         }
407 
408         if (size <= sizeof(std::string)) {
409             return false;
410         }
411 
412         std::string key = GetStringFromData(int(size));
413         OOBEManager::ResDataAbilityObserver::UpdateFunc updateFunc = [&]() {};
414         if (!DoInit()) {
415             return false;
416         }
417 
418         OOBEManager::GetInstance().GetOOBValue();
419         OOBEManager::GetInstance().RegisterObserver(key, updateFunc);
420         OOBEManager::GetInstance().UnregisterObserver();
421         sptr<OOBEManager::ResDataAbilityObserver> oobeObserver = new OOBEManager::ResDataAbilityObserver();
422         oobeObserver->OnChange();
423         oobeObserver->SetUpdateFunc(updateFunc);
424         OOBEManager::GetInstance().Initialize();
425         OOBEManager::GetInstance().StartListen();
426         return true;
427     }
428 
OOBEDatashareUtilsFuzzTest(const uint8_t* data, size_t size)429     bool OOBEDatashareUtilsFuzzTest(const uint8_t* data, size_t size)
430     {
431         if (data == nullptr) {
432             return false;
433         }
434 
435         if (size <= TWO_PARAMETERS * sizeof(std::string)) {
436             return false;
437         }
438 
439         std::string key = GetStringFromData(int(size));
440         std::string value = GetStringFromData(int(size));
441         if (!DoInit()) {
442             return false;
443         }
444 
445         DataShareUtils::GetInstance().GetValue(key, value);
446         DataShareUtils::GetInstance().GetStringValue(key, value);
447         std::shared_ptr<DataShare::DataShareHelper> helper = DataShareUtils::GetInstance().CreateDataShareHelper();
448         DataShareUtils::GetInstance().ReleaseDataShareHelper(helper);
449         DataShareUtils::GetInstance().InitSystemAbilityManager();
450         DataShareUtils::GetInstance().AssembleUri(key);
451         DataShareUtils::GetInstance().GetDataShareReadyFlag();
452         DataShareUtils::GetInstance().SetDataShareReadyFlag(true);
453         return true;
454     }
455 
SetHapToken()456     void SetHapToken()
457     {
458         Security::AccessToken::AccessTokenIDEx tokenIdEx = {0};
459         tokenIdEx = Security::AccessToken::AccessTokenKit::AllocHapToken(info, HapPolicyParams);
460         SetSelfTokenID(tokenIdEx.tokenIDEx);
461     }
462 
DeleteHapToken()463     void DeleteHapToken()
464     {
465         Security::AccessToken::AccessTokenID tokenId =
466             Security::AccessToken::AccessTokenKit::GetHapTokenID(info.userID, info.bundleName, info.instIndex);
467         Security::AccessToken::AccessTokenKit::DeleteToken(tokenId);
468     }
469 
GetPayload(uint32_t resType)470     std::unordered_map<std::string, std::string> GetPayload(uint32_t resType)
471     {
472         std::unordered_map<std::string, std::string> payload;
473         const auto &params = RESTYPE_TO_PARAMS.at(resType);
474         size_t paramSize = params.size();
475         if (paramSize == 0) {
476             return payload;
477         }
478         size_t maxLen = PAYLOAD_MAX_SIZE / paramSize;
479         size_t minLen = sizeof(int32_t);
480         if (minLen > maxLen) {
481             minLen = maxLen;
482         }
483         std::mt19937_64 gen(std::random_device{}());
484         std::uniform_int_distribution<size_t> dis(minLen, maxLen);
485         for (const auto &param : params) {
486             payload[param] = GetStringFromData(dis(gen));
487         }
488         return payload;
489     }
490 
ResSchedThirdPartyFuzzTest(const uint8_t* data, size_t size)491     bool ResSchedThirdPartyFuzzTest(const uint8_t* data, size_t size)
492     {
493         if (data == nullptr || size < sizeof(uint32_t)) {
494             return false;
495         }
496         uint32_t selfToken = GetSelfTokenID();
497         SetHapToken();
498         g_data = data;
499         g_size = size;
500         g_pos = 0;
501 
502         uint32_t resType = GetData<uint32_t>() % ResType::RES_TYPE_LAST;
503         if (THIRDPARTY_RES.find(resType) == THIRDPARTY_RES.end()) {
504             return false;
505         }
506 
507         int64_t value = GetData<int64_t>();
508         auto mapPayload = GetPayload(resType);
509         ResSchedClient::GetInstance().ReportData(resType, value, mapPayload);
510 
511         DeleteHapToken();
512         SetSelfTokenID(selfToken);
513         return true;
514     }
515 } // namespace ResourceSchedule
516 } // namespace OHOS
517 
518 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)519 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
520 {
521     /* Run your code on data */
522     OHOS::ResourceSchedule::DoSomethingInterestingWithMyAPI(data, size);
523     OHOS::ResourceSchedule::OnRemoteRequest(data, size);
524     OHOS::ResourceSchedule::SyncEventFuzzTest(data, size);
525     OHOS::ResourceSchedule::ResSchedClientFuzzTest(data, size);
526     OHOS::ResourceSchedule::ResSchedThirdPartyFuzzTest(data, size);
527     OHOS::ResourceSchedule::OnSystemloadLevelFuzzTest(data, size);
528     OHOS::ResourceSchedule::NotifierMgrFuzzTest(data, size);
529     OHOS::ResourceSchedule::OOBEManagerFuzzTest(data, size);
530     OHOS::ResourceSchedule::OOBEDatashareUtilsFuzzTest(data, size);
531     OHOS::ResourceSchedule::SlideRecognizerFuzzTest(data, size);
532     return 0;
533 }
534