• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <thread>
17 #include <chrono>
18 #include <cinttypes>
19 
20 #include "file_util.h"
21 #include "json_util.h"
22 #include "security_guard_utils.h"
23 #include "data_collect_manager.h"
24 #include "ffrt.h"
25 #include "directory_ex.h"
26 #include "detect_plugin_manager.h"
27 
28 namespace OHOS::Security::SecurityGuard {
29 namespace {
30     constexpr int32_t MAX_RETRY_INTERVAL = 60;
31     constexpr int32_t RETRY_INTERVAL_INCREMENT = 10;
32     constexpr int32_t MAX_PLUGIN_SIZE = 20;
33     constexpr const char *PLUGIN_PREFIX_PATH = "/system/lib64/";
34 }
35 
getInstance()36 DetectPluginManager& DetectPluginManager::getInstance()
37 {
38     static DetectPluginManager instance;
39     return instance;
40 }
41 
42 // LCOV_EXCL_START
LoadAllPlugins()43 void DetectPluginManager::LoadAllPlugins()
44 {
45     SGLOGI("Start LoadAllPlugins.");
46     const std::string fileName = "/system/etc/detect_plugin.json";
47     if (!ParsePluginConfig(fileName)) {
48         return;
49     }
50     for (const auto &plugin : plugins_) {
51         LoadPlugin(plugin);
52     }
53     if (!isFailedEventStartRetry_) {
54         isFailedEventStartRetry_ = true;
55         ffrt::submit([this] { RetrySubscriptionTask(); });
56     }
57     SGLOGI("LoadAllPlugins finished");
58 }
59 
LoadPlugin(const PluginCfg & pluginCfg)60 void DetectPluginManager::LoadPlugin(const PluginCfg &pluginCfg)
61 {
62     void *handle = dlopen(pluginCfg.pluginPath.c_str(), RTLD_LAZY);
63     if (handle == nullptr) {
64         SGLOGE("Plugin open failed, pluginName: %{public}s, reason: %{public}s",
65             pluginCfg.pluginName.c_str(), dlerror());
66         return;
67     }
68     std::shared_ptr<DetectPluginAttrs> detectPluginAttrs = std::make_shared<DetectPluginAttrs>();
69     detectPluginAttrs->SetPluginName(pluginCfg.pluginName);
70     detectPluginAttrs->SetHandle(handle);
71     auto createDetectPlugin = (CreateDetectPlugin)dlsym(handle, "CreateDetectPlugin");
72     if (createDetectPlugin == nullptr) {
73         SGLOGE("createDetectPlugin func is nullptr");
74         return;
75     }
76     IDetectPlugin *instance = createDetectPlugin();
77     if (instance == nullptr) {
78         SGLOGE("IDetectPlugin instance is nullptr");
79         return;
80     }
81     detectPluginAttrs->SetInstance(instance);
82     if (!instance->Init()) {
83         SGLOGE("Plugin init failed, pluginName: %{public}s", pluginCfg.pluginName.c_str());
84         return;
85     }
86     for (const int64_t& eventId : pluginCfg.depEventIds) {
87         size_t count = 0;
88         {
89             std::lock_guard<ffrt::mutex> lock(mutex_);
90             count = eventIdMap_.count(eventId);
91         }
92         if (count == 0) {
93             SubscribeEvent(eventId);
94         }
95         std::lock_guard<ffrt::mutex> lock(mutex_);
96         eventIdMap_[eventId].emplace_back(detectPluginAttrs);
97     }
98     if (pluginCfg.depEventIds.empty()) {
99         const int64_t sepcialId = -1;
100         std::lock_guard<ffrt::mutex> lock(mutex_);
101         eventIdMap_[sepcialId].emplace_back(detectPluginAttrs);
102     }
103     SGLOGI("Load plugin success, pluginName: %{public}s", pluginCfg.pluginName.c_str());
104 }
105 // LCOV_EXCL_STOP
106 
SubscribeEvent(int64_t eventId)107 void DetectPluginManager::SubscribeEvent(int64_t eventId)
108 {
109     SecurityCollector::Event sgEvent {};
110     sgEvent.eventId = eventId;
111     auto subscriber = std::make_shared<DetectPluginManagerSubscriber>(sgEvent);
112     int32_t code = SecurityGuard::DataCollectManager::GetInstance().Subscribe(subscriber);
113     if (code != SecurityGuard::SUCCESS) {
114         SGLOGE("Subscribe failed, code: %{public}d, eventId: 0x%{public}" PRIx64 "in retry list", code, eventId);
115         failedEventIdset_.insert(eventId);
116         return;
117     }
118     SGLOGI("DetectPluginManager subscribe success, eventId: 0x%{public}" PRIx64, eventId);
119 }
120 
RetrySubscriptionTask()121 void DetectPluginManager::RetrySubscriptionTask()
122 {
123     int32_t retryInterval = 10;
124     while (!failedEventIdset_.empty()) {
125         auto tmpSet = failedEventIdset_;
126         for (const auto eventId : tmpSet) {
127             SGLOGI("Retry subscription event: 0x%{public}" PRIx64, eventId);
128             failedEventIdset_.erase(eventId);
129             SubscribeEvent(eventId);
130         }
131         if (failedEventIdset_.empty()) {
132             break;
133         }
134         ffrt::this_task::sleep_for(std::chrono::seconds(retryInterval));
135         retryInterval = std::min(retryInterval + RETRY_INTERVAL_INCREMENT, MAX_RETRY_INTERVAL);
136     }
137 }
138 
ParsePluginConfig(const std::string & fileName)139 bool DetectPluginManager::ParsePluginConfig(const std::string &fileName)
140 {
141     std::ios::pos_type pluginCfgFileMaxSize = 1 * 1024 * 1024;  // byte
142     std::string jsonStr;
143     if (!FileUtil::ReadFileToStr(fileName, pluginCfgFileMaxSize, jsonStr)) {
144         SGLOGE("Read plugin cfg file error.");
145         return false;
146     }
147     cJSON *inJson = cJSON_Parse(jsonStr.c_str());
148     if (inJson == nullptr) {
149         SGLOGE("Parse json error.");
150         return false;
151     }
152     cJSON *plugins = cJSON_GetObjectItem(inJson, "plugins");
153     if (plugins == nullptr || !cJSON_IsArray(plugins)) {
154         SGLOGE("Json Parse Error: plugins is null or not an array.");
155         cJSON_Delete(inJson);
156         inJson = nullptr;
157         return false;
158     }
159     ParsePluginConfigObjArray(plugins);
160     cJSON_Delete(inJson);
161     inJson = nullptr;
162     return true;
163 }
164 
ParsePluginConfigObjArray(const cJSON * plugins)165 void DetectPluginManager::ParsePluginConfigObjArray(const cJSON *plugins)
166 {
167     int size = cJSON_GetArraySize(plugins);
168     for (int i = 0; i < size; i++) {
169         cJSON *item = cJSON_GetArrayItem(plugins, i);
170         PluginCfg pluginCfg;
171         if (!JsonUtil::GetString(item, "pluginName", pluginCfg.pluginName) ||
172             !JsonUtil::GetString(item, "version", pluginCfg.version) ||
173             !ParsePluginDepEventIds(item, pluginCfg.depEventIds)) {
174             SGLOGE("Json Parse Error: pluginName or version or depEventIds not correct.");
175             continue;
176         }
177         if (!CheckPluginNameAndSize(pluginCfg)) {
178             continue;
179         }
180         plugins_.emplace_back(pluginCfg);
181     }
182 }
183 
CheckPluginNameAndSize(PluginCfg & newPlugin)184 bool DetectPluginManager::CheckPluginNameAndSize(PluginCfg &newPlugin)
185 {
186     if (plugins_.size() >= MAX_PLUGIN_SIZE) {
187         SGLOGE("The number of managed plugins exceeds the specification");
188         return false;
189     }
190 
191     const std::string path = PLUGIN_PREFIX_PATH + newPlugin.pluginName;
192     if (!PathToRealPath(path, newPlugin.pluginPath) || newPlugin.pluginPath.find(PLUGIN_PREFIX_PATH) != 0) {
193         SGLOGE("Check plugin path failed, pluginName: %{public}s", newPlugin.pluginName.c_str());
194         return false;
195     }
196     auto it = std::find_if(plugins_.begin(), plugins_.end(),
197         [&](const PluginCfg &plugin) {return plugin.pluginName == newPlugin.pluginName;});
198     if (it != plugins_.end()) {
199         SGLOGE("Duplicate plugin names are not allowed.");
200         return false;
201     }
202     return true;
203 }
204 
ParsePluginDepEventIds(const cJSON * plugin,std::unordered_set<int64_t> & depEventIds)205 bool DetectPluginManager::ParsePluginDepEventIds(const cJSON *plugin,
206     std::unordered_set<int64_t> &depEventIds)
207 {
208     cJSON *depEventIdsJson = cJSON_GetObjectItem(plugin, "depEventIds");
209     int size = cJSON_GetArraySize(depEventIdsJson);
210     if (depEventIdsJson == nullptr || !cJSON_IsArray(depEventIdsJson)) {
211         SGLOGE("Json Parse Error: depEventIds not correct.");
212         return false;
213     }
214     for (int i = 0; i < size; i++) {
215         cJSON *eventIdJson = cJSON_GetArrayItem(depEventIdsJson, i);
216         std::string eventId;
217         if (!JsonUtil::GetStringNoKey(eventIdJson, eventId)) {
218             SGLOGE("Json Parse Error: eventId not correct.");
219             return false;
220         }
221         int64_t tmp = 0;
222         if (!SecurityGuardUtils::StrToI64Hex(eventId, tmp)) {
223             SGLOGE("Json Parse Error: eventId not int_64.");
224             return false;
225         }
226         depEventIds.insert(tmp);
227     }
228     return true;
229 }
230 
DispatchEvent(const SecurityCollector::Event & event)231 void DetectPluginManager::DispatchEvent(const SecurityCollector::Event &event)
232 {
233     SGLOGD("Start distributing events, eventId: 0x%{public}" PRIx64, event.eventId);
234     std::lock_guard<ffrt::mutex> lock(mutex_);
235     auto it = eventIdMap_.find(event.eventId);
236     if (it == eventIdMap_.end()) {
237         SGLOGE("No Plugin is available to process th event, eventId: 0x%{public}" PRIx64,
238              event.eventId);
239         return;
240     }
241     for (auto& detectPlugin : it->second) {
242         detectPlugin->GetInstance()->HandleEvent(event.eventId, event.content,
243             AssembleMetadata(event));
244         SGLOGD("Event distributed successfully, eventId: 0x%{public}" PRIx64 ", pluginName: %{public}s",
245             event.eventId, detectPlugin->GetPluginName().c_str());
246     }
247 }
248 
AssembleMetadata(const SecurityCollector::Event & event)249 std::string DetectPluginManager::AssembleMetadata(const SecurityCollector::Event &event)
250 {
251     std::string metadata = "";
252     cJSON* jsonObj = cJSON_CreateObject();
253     if (jsonObj == nullptr) {
254         SGLOGE("cJSON_CreateObject nullptr");
255         return metadata;
256     }
257     if (!JsonUtil::AddString(jsonObj, "version", event.version)) {
258         SGLOGE("AddString version failed");
259         cJSON_Delete(jsonObj);
260         jsonObj = nullptr;
261         return metadata;
262     }
263         if (!JsonUtil::AddString(jsonObj, "timestamp", event.timestamp)) {
264         SGLOGE("AddString timestamp failed");
265         cJSON_Delete(jsonObj);
266         jsonObj = nullptr;
267         return metadata;
268     }
269     auto charPtr = cJSON_PrintUnformatted(jsonObj);
270     if (charPtr == nullptr) {
271         SGLOGE("cJSON_PrintUnformatted nullptr");
272         cJSON_Delete(jsonObj);
273         jsonObj = nullptr;
274         return metadata;
275     }
276     metadata = charPtr;
277     cJSON_free(charPtr);
278     charPtr= nullptr;
279     cJSON_Delete(jsonObj);
280     jsonObj = nullptr;
281     return metadata;
282 }
283 } // namespace OHOS::Security::SecurityGuard