1 /*
2  * Copyright (c) 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 "data_collection.h"
17 #include <cinttypes>
18 #include "json_cfg.h"
19 #include "security_collector_log.h"
20 #include "collector_cfg_marshalling.h"
21 #include "i_collector.h"
22 
23 namespace OHOS::Security::SecurityCollector {
24 namespace {
25     const char* SA_CONFIG_PATH = "/system/etc/security_audit.cfg";
26 }
27 
GetInstance()28 DataCollection &DataCollection::GetInstance()
29 {
30     static DataCollection instance;
31     return instance;
32 }
33 
StartCollectors(const std::vector<int64_t>& eventIds, std::shared_ptr<ICollectorFwk> api)34 bool DataCollection::StartCollectors(const std::vector<int64_t>& eventIds, std::shared_ptr<ICollectorFwk> api)
35 {
36     LOGI("StartCollectors start");
37     if (eventIds.empty() || !api) {
38         LOGE("Invalid input parameter");
39         return false;
40     }
41     std::vector<int64_t> loadedEventIds_;
42     for (int64_t eventId : eventIds) {
43         LOGI("StartCollectors eventId is 0x%{public}" PRIx64, eventId);
44         if (IsCollectorStarted(eventId)) {
45             LOGI("Collector already started, eventId is 0x%{public}" PRIx64, eventId);
46             continue;
47         }
48         std::string collectorPath;
49         ErrorCode ret = GetCollectorPath(eventId, collectorPath);
50         if (ret != SUCCESS) {
51             LOGE("GetCollectorPath failed, eventId is 0x%{public}" PRIx64, eventId);
52             StopCollectors(loadedEventIds_);
53             return false;
54         }
55         ret = LoadCollector(eventId, collectorPath, api);
56         if (ret != SUCCESS) {
57             LOGE("Load collector failed, eventId is 0x%{public}" PRIx64, eventId);
58             StopCollectors(loadedEventIds_);
59             return false;
60         }
61         loadedEventIds_.push_back(eventId);
62     }
63     LOGI("StartCollectors finish");
64     return true;
65 }
66 
SecurityGuardSubscribeCollector(const std::vector<int64_t>& eventIds)67 bool DataCollection::SecurityGuardSubscribeCollector(const std::vector<int64_t>& eventIds)
68 {
69     LOGI("Start to subscribe collectors start");
70     for (int64_t eventId : eventIds) {
71         LOGI("StartCollectors eventId is 0x%{public}" PRIx64, eventId);
72         if (IsCollectorStarted(eventId)) {
73             LOGI("Collector already started, eventId is 0x%{public}" PRIx64, eventId);
74             continue;
75         }
76         std::string collectorPath;
77         ErrorCode ret = GetCollectorPath(eventId, collectorPath);
78         if (ret != SUCCESS) {
79             LOGE("GetCollectorPath failed, eventId is 0x%{public}" PRIx64, eventId);
80             continue;
81         }
82         ret = LoadCollector(eventId, collectorPath, nullptr);
83         if (ret != SUCCESS) {
84             LOGE("GetCollectorPath failed, eventId is 0x%{public}" PRIx64, eventId);
85             continue;
86         }
87     }
88     LOGI("StartCollectors finish");
89     return true;
90 }
91 
IsCollectorStarted(int64_t eventId)92 bool DataCollection::IsCollectorStarted(int64_t eventId)
93 {
94     std::lock_guard<std::mutex> lock(mutex_);
95     auto it = eventIdToLoaderMap_.find(eventId);
96     return it != eventIdToLoaderMap_.end();
97 }
98 
StopCollectors(const std::vector<int64_t>& eventIds)99 bool DataCollection::StopCollectors(const std::vector<int64_t>& eventIds)
100 {
101     LOGI("StopCollectors start");
102     if (eventIds.empty()) {
103         LOGW("The eventId list is empty");
104         return true;
105     }
106     bool ret = true;
107     std::lock_guard<std::mutex> lock(mutex_);
108     for (int64_t eventId : eventIds) {
109         LOGI("StopCollectors eventId is 0x%{public}" PRIx64, eventId);
110         auto loader = eventIdToLoaderMap_.find(eventId);
111         if (loader == eventIdToLoaderMap_.end()) {
112             LOGI("Collector not found, eventId is 0x%{public}" PRIx64, eventId);
113             continue;
114         }
115         ICollector* collector = loader->second.CallGetCollector();
116         if (collector == nullptr) {
117             LOGE("CallGetCollector error");
118             ret = false;
119         } else {
120             int result = collector->Stop();
121             int isStartWithSub = collector->IsStartWithSub();
122             if (isStartWithSub == 1) {
123                 result = collector->Unsubscribe(eventId);
124             }
125             if (result != 0) {
126                 LOGE("Failed to stop collector, eventId is 0x%{public}" PRIx64, eventId);
127                 ret = false;
128             }
129             LOGI("Stop collector");
130             eventIdToLoaderMap_.erase(loader);
131         }
132     }
133     LOGI("StopCollectors finish");
134     return ret;
135 }
136 
CloseLib()137 void DataCollection::CloseLib()
138 {
139     std::lock_guard<std::mutex> lock(closeLibmutex_);
140     for (auto &it : needCloseLibMap_) {
141         it.second.UnLoadLib();
142     }
143     needCloseLibMap_.clear();
144 }
LoadCollector(int64_t eventId, std::string path, std::shared_ptr<ICollectorFwk> api)145 ErrorCode DataCollection::LoadCollector(int64_t eventId, std::string path, std::shared_ptr<ICollectorFwk> api)
146 {
147     LOGI("Start LoadCollector");
148     LibLoader loader(path);
149     ErrorCode ret = loader.LoadLib();
150     if (ret != SUCCESS) {
151         LOGE("LoadLib error, ret=%{public}d, path : %{public}s", ret, path.c_str());
152         return FAILED;
153     }
154     {
155         std::lock_guard<std::mutex> lock(closeLibmutex_);
156         needCloseLibMap_.emplace(eventId, loader);
157     }
158     ICollector* collector = loader.CallGetCollector();
159     if (collector == nullptr) {
160         LOGE("CallGetCollector error");
161         return FAILED;
162     }
163     int result = collector->Start(api);
164     int isStartWithSub = collector->IsStartWithSub();
165     if (isStartWithSub == 1) {
166         result = collector->Subscribe(eventId);
167     }
168     if (result != 0) {
169         LOGE("Failed to start collector");
170         return FAILED;
171     }
172     std::lock_guard<std::mutex> lock(mutex_);
173     eventIdToLoaderMap_.emplace(eventId, loader);
174     LOGI("End LoadCollector");
175     return SUCCESS;
176 }
177 
GetCollectorPath(int64_t eventId, std::string& path)178 ErrorCode DataCollection::GetCollectorPath(int64_t eventId, std::string& path)
179 {
180     LOGI("Start GetCollectorPath");
181     std::ifstream stream(SA_CONFIG_PATH, std::ios::in);
182     if (!stream.is_open()) {
183         LOGE("Stream error, %{public}s", strerror(errno));
184         return STREAM_ERROR;
185     }
186     ErrorCode ret = CheckFileStream(stream);
187     if (ret != SUCCESS) {
188         LOGE("check file stream error, ret=%{public}d", ret);
189         stream.close();
190         return ret;
191     }
192     nlohmann::json json = nlohmann::json::parse(stream, nullptr, false);
193     stream.close();
194 
195     if (json.is_discarded()) {
196         LOGE("json is discarded");
197         return JSON_ERR;
198     }
199 
200     std::vector<ModuleCfgSt> moduleCfgs;
201     if (!SecurityGuard::JsonCfg::Unmarshal<ModuleCfgSt>(moduleCfgs, json, MODULES)) {
202         LOGE("Unmarshal moduleCfgs error");
203         return JSON_ERR;
204     }
205 
206     auto it = std::find_if(moduleCfgs.begin(), moduleCfgs.end(),
207         [eventId] (const ModuleCfgSt &module) {
208             auto ifIt = std::find(module.eventId.begin(), module.eventId.end(), eventId);
209             if (ifIt != module.eventId.end()) {
210                 LOGI("success to find the event id: 0x%{public}" PRIx64, eventId);
211                 return true;
212             } else {
213                 return false;
214             }
215         });
216     if (it != moduleCfgs.end()) {
217         path = it->modulePath + it->moduleName;
218         return SUCCESS;
219     }
220 
221     LOGE("The eventId does not exist");
222     return FAILED;
223 }
224 
GetCollectorType(int64_t eventId, int32_t& collectorType)225 ErrorCode DataCollection::GetCollectorType(int64_t eventId, int32_t& collectorType)
226 {
227     LOGI("Start GetCollectorType");
228     std::ifstream stream(SA_CONFIG_PATH, std::ios::in);
229     if (!stream.is_open()) {
230         LOGE("Stream error, %{public}s", strerror(errno));
231         return STREAM_ERROR;
232     }
233 
234     ErrorCode ret = CheckFileStream(stream);
235     if (ret != SUCCESS) {
236         LOGE("check file stream error, ret=%{public}d", ret);
237         stream.close();
238         return ret;
239     }
240 
241     nlohmann::json json = nlohmann::json::parse(stream, nullptr, false);
242     stream.close();
243 
244     if (json.is_discarded()) {
245         LOGE("json is discarded");
246         return JSON_ERR;
247     }
248 
249     std::vector<ModuleCfgSt> moduleCfgs;
250     if (!SecurityGuard::JsonCfg::Unmarshal<ModuleCfgSt>(moduleCfgs, json, MODULES)) {
251         LOGE("Unmarshal moduleCfgs error");
252         return JSON_ERR;
253     }
254 
255     auto it = std::find_if(moduleCfgs.begin(), moduleCfgs.end(),
256         [eventId] (const ModuleCfgSt &module) {
257             auto ifIt = std::find(module.eventId.begin(), module.eventId.end(), eventId);
258             if (ifIt != module.eventId.end()) {
259                 return true;
260             } else {
261                 return false;
262             }
263         });
264     if (it != moduleCfgs.end()) {
265         collectorType = it->collectorType;
266         LOGI("get event 0x%{public}" PRIx64 "collector type is %{public}d.", eventId, collectorType);
267         return SUCCESS;
268     }
269 
270     LOGE("The eventId does not exist");
271     return FAILED;
272 }
273 
CheckFileStream(std::ifstream &stream)274 ErrorCode DataCollection::CheckFileStream(std::ifstream &stream)
275 {
276     if (!stream.is_open()) {
277         LOGE("stream open error, %{public}s", strerror(errno));
278         return STREAM_ERROR;
279     }
280 
281     stream.seekg(0, std::ios::end);
282     std::ios::pos_type len = stream.tellg();
283     if (len == 0) {
284         LOGE("stream is empty");
285         return STREAM_ERROR;
286     }
287     stream.seekg(0, std::ios::beg);
288     return SUCCESS;
289 }
290 
LoadCollector(std::string path, const SecurityEventRuler &ruler, std::vector<SecurityEvent> &events)291 ErrorCode DataCollection::LoadCollector(std::string path, const SecurityEventRuler &ruler,
292     std::vector<SecurityEvent> &events)
293 {
294     LOGI("Start LoadCollector");
295     LibLoader loader(path);
296     ErrorCode ret = loader.LoadLib();
297     if (ret != SUCCESS) {
298         LOGE("LoadLib error, ret=%{public}d", ret);
299         return FAILED;
300     }
301     {
302         std::lock_guard<std::mutex> lock(closeLibmutex_);
303         needCloseLibMap_.emplace(ruler.GetEventId(), loader);
304     }
305     ICollector* collector = loader.CallGetCollector();
306     if (collector == nullptr) {
307         LOGE("CallGetCollector error");
308         return FAILED;
309     }
310     int result = collector->Query(ruler, events);
311     if (result != 0) {
312         LOGE("Failed to start collector");
313         return FAILED;
314     }
315     LOGI("End LoadCollector");
316     return SUCCESS;
317 }
318 
QuerySecurityEvent(const std::vector<SecurityEventRuler> rulers, std::vector<SecurityEvent> &events)319 int32_t DataCollection::QuerySecurityEvent(const std::vector<SecurityEventRuler> rulers,
320     std::vector<SecurityEvent> &events)
321 {
322     LOGI("QuerySecurityEvent start");
323     if (rulers.empty()) {
324         LOGE("Invalid input parameter");
325         return false;
326     }
327     for (const auto &ruler : rulers) {
328         LOGI("QuerySecurityEvent eventId is 0x%{public}" PRIx64, ruler.GetEventId());
329         std::string collectorPath;
330         ErrorCode ret = GetCollectorPath(ruler.GetEventId(), collectorPath);
331         if (ret != SUCCESS) {
332             LOGE("GetCollectorPath failed, eventId is 0x%{public}" PRIx64, ruler.GetEventId());
333             return false;
334         }
335         ret = LoadCollector(collectorPath, ruler, events);
336         if (ret != SUCCESS) {
337             LOGE("Load collector failed, eventId is 0x%{public}" PRIx64, ruler.GetEventId());
338             return false;
339         }
340     }
341     LOGI("StartCollectors finish");
342     return true;
343 }
344 }