1 /*
2 * Copyright (c) 2021-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 "hiappevent_verify.h"
17
18 #include <cctype>
19 #include <iterator>
20 #include <regex>
21 #include <unordered_set>
22
23 #include "hiappevent_base.h"
24 #include "hiappevent_config.h"
25 #include "hilog/log.h"
26
27 using namespace OHOS::HiviewDFX::ErrorCode;
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 static constexpr HiLogLabel LABEL = { LOG_CORE, HIAPPEVENT_DOMAIN, "HiAppEvent_verify" };
33
34 constexpr size_t MAX_LEN_OF_WATCHER = 32;
35 constexpr size_t MAX_LEN_OF_DOMAIN = 16;
36 static constexpr int MAX_LENGTH_OF_EVENT_NAME = 48;
37 static constexpr int MAX_LENGTH_OF_PARAM_NAME = 16;
38 static constexpr unsigned int MAX_NUM_OF_PARAMS = 32;
39 static constexpr size_t MAX_LENGTH_OF_STR_PARAM = 8 * 1024;
40 static constexpr size_t MAX_LENGTH_OF_SPECIAL_STR_PARAM = 1024 * 1024;
41 static constexpr int MAX_SIZE_OF_LIST_PARAM = 100;
42 static constexpr int MAX_LENGTH_OF_USER_INFO_NAME = 256;
43 static constexpr int MAX_LENGTH_OF_USER_ID_VALUE = 256;
44 static constexpr int MAX_LENGTH_OF_USER_PROPERTY_VALUE = 1024;
45 static constexpr int MAX_LENGTH_OF_PROCESSOR_NAME = 256;
46 static constexpr int MAX_LEN_OF_BATCH_REPORT = 1000;
47
IsValidName(const std::string & name,size_t maxSize)48 bool IsValidName(const std::string& name, size_t maxSize)
49 {
50 if (name.empty() || name.length() > maxSize) {
51 return false;
52 }
53 // start char is [$a-zA-Z]
54 if (!isalpha(name[0]) && name[0] != '$') {
55 return false;
56 }
57 // end char is [a-zA-Z0-9]
58 if (name.length() > 1 && (!isalnum(name.back()))) {
59 return false;
60 }
61 // middle char is [a-zA-Z0-9_]
62 for (size_t i = 1; i < name.length() - 1; ++i) {
63 if (!isalnum(name[i]) && name[i] != '_') {
64 return false;
65 }
66 }
67 return true;
68 }
69
CheckParamName(const std::string & paramName)70 bool CheckParamName(const std::string& paramName)
71 {
72 return IsValidName(paramName, MAX_LENGTH_OF_PARAM_NAME);
73 }
74
EscapeStringValue(std::string & value)75 void EscapeStringValue(std::string &value)
76 {
77 std::string escapeValue;
78 for (auto it = value.begin(); it != value.end(); it++) {
79 switch (*it) {
80 case '\\':
81 escapeValue.append("\\\\");
82 break;
83 case '\"':
84 escapeValue.append("\\\"");
85 break;
86 case '\b':
87 escapeValue.append("\\b");
88 break;
89 case '\f':
90 escapeValue.append("\\f");
91 break;
92 case '\n':
93 escapeValue.append("\\n");
94 break;
95 case '\r':
96 escapeValue.append("\\r");
97 break;
98 case '\t':
99 escapeValue.append("\\t");
100 break;
101 default:
102 escapeValue.push_back(*it);
103 break;
104 }
105 }
106 value = escapeValue;
107 }
108
CheckStrParamLength(std::string & strParamValue,size_t maxLen=MAX_LENGTH_OF_STR_PARAM)109 bool CheckStrParamLength(std::string& strParamValue, size_t maxLen = MAX_LENGTH_OF_STR_PARAM)
110 {
111 if (strParamValue.empty()) {
112 HiLog::Warn(LABEL, "str param value is empty.");
113 return true;
114 }
115
116 if (strParamValue.length() > maxLen) {
117 return false;
118 }
119
120 EscapeStringValue(strParamValue);
121 return true;
122 }
123
CheckListValueSize(AppEventParamType type,AppEventParamValue::ValueUnion & vu)124 bool CheckListValueSize(AppEventParamType type, AppEventParamValue::ValueUnion& vu)
125 {
126 if (type == AppEventParamType::BVECTOR && vu.bs_.size() > MAX_SIZE_OF_LIST_PARAM) {
127 vu.bs_.resize(MAX_SIZE_OF_LIST_PARAM);
128 } else if (type == AppEventParamType::CVECTOR && vu.cs_.size() > MAX_SIZE_OF_LIST_PARAM) {
129 vu.cs_.resize(MAX_SIZE_OF_LIST_PARAM);
130 } else if (type == AppEventParamType::SHVECTOR && vu.shs_.size() > MAX_SIZE_OF_LIST_PARAM) {
131 vu.shs_.resize(MAX_SIZE_OF_LIST_PARAM);
132 } else if (type == AppEventParamType::IVECTOR && vu.is_.size() > MAX_SIZE_OF_LIST_PARAM) {
133 vu.is_.resize(MAX_SIZE_OF_LIST_PARAM);
134 } else if (type == AppEventParamType::LLVECTOR && vu.lls_.size() > MAX_SIZE_OF_LIST_PARAM) {
135 vu.lls_.resize(MAX_SIZE_OF_LIST_PARAM);
136 } else if (type == AppEventParamType::FVECTOR && vu.fs_.size() > MAX_SIZE_OF_LIST_PARAM) {
137 vu.fs_.resize(MAX_SIZE_OF_LIST_PARAM);
138 } else if (type == AppEventParamType::DVECTOR && vu.ds_.size() > MAX_SIZE_OF_LIST_PARAM) {
139 vu.ds_.resize(MAX_SIZE_OF_LIST_PARAM);
140 } else if (type == AppEventParamType::STRVECTOR && vu.strs_.size() > MAX_SIZE_OF_LIST_PARAM) {
141 vu.strs_.resize(MAX_SIZE_OF_LIST_PARAM);
142 } else {
143 return true;
144 }
145
146 return false;
147 }
148
CheckStringLengthOfList(std::vector<std::string> & strs)149 bool CheckStringLengthOfList(std::vector<std::string>& strs)
150 {
151 if (strs.empty()) {
152 return true;
153 }
154
155 for (auto it = strs.begin(); it != strs.end(); it++) {
156 if (!CheckStrParamLength(*it)) {
157 return false;
158 }
159 }
160
161 return true;
162 }
163
CheckParamsNum(std::list<AppEventParam> & baseParams)164 bool CheckParamsNum(std::list<AppEventParam>& baseParams)
165 {
166 if (baseParams.size() == 0) {
167 return true;
168 }
169
170 auto listSize = baseParams.size();
171 if (listSize > MAX_NUM_OF_PARAMS) {
172 auto delStartPtr = baseParams.begin();
173 std::advance(delStartPtr, MAX_NUM_OF_PARAMS);
174 baseParams.erase(delStartPtr, baseParams.end());
175 return false;
176 }
177
178 return true;
179 }
180
VerifyAppEventParam(AppEventParam & param,std::unordered_set<std::string> & paramNames,int & verifyRes)181 bool VerifyAppEventParam(AppEventParam& param, std::unordered_set<std::string>& paramNames, int& verifyRes)
182 {
183 std::string name = param.name;
184 if (paramNames.find(name) != paramNames.end()) {
185 HiLog::Warn(LABEL, "param=%{public}s is discarded because param is duplicate.", name.c_str());
186 verifyRes = ERROR_DUPLICATE_PARAM;
187 return false;
188 }
189
190 if (!CheckParamName(name)) {
191 HiLog::Warn(LABEL, "param=%{public}s is discarded because the paramName is invalid.", name.c_str());
192 verifyRes = ERROR_INVALID_PARAM_NAME;
193 return false;
194 }
195
196 const std::unordered_set<std::string> tempTrueNames = {"crash", "anr"};
197 size_t maxLen = tempTrueNames.find(name) == tempTrueNames.end() ? MAX_LENGTH_OF_STR_PARAM :
198 MAX_LENGTH_OF_SPECIAL_STR_PARAM;
199 if (param.type == AppEventParamType::STRING && !CheckStrParamLength(param.value.valueUnion.str_, maxLen)) {
200 HiLog::Warn(LABEL, "param=%{public}s is discarded because the string length exceeds %{public}zu.",
201 name.c_str(), maxLen);
202 verifyRes = ERROR_INVALID_PARAM_VALUE_LENGTH;
203 return false;
204 }
205
206 if (param.type == AppEventParamType::STRVECTOR && !CheckStringLengthOfList(param.value.valueUnion.strs_)) {
207 HiLog::Warn(LABEL, "param=%{public}s is discarded because the string length of list exceeds 8192.",
208 name.c_str());
209 verifyRes = ERROR_INVALID_PARAM_VALUE_LENGTH;
210 return false;
211 }
212
213 if (param.type > AppEventParamType::STRING && !CheckListValueSize(param.type, param.value.valueUnion)) {
214 HiLog::Warn(LABEL, "list param=%{public}s is truncated because the list size exceeds 100.", name.c_str());
215 verifyRes = ERROR_INVALID_LIST_PARAM_SIZE;
216 return true;
217 }
218 return true;
219 }
220
221 using VerifyReportConfigFunc = int (*)(ReportConfig& config);
VerifyNameOfReportConfig(ReportConfig & config)222 int VerifyNameOfReportConfig(ReportConfig& config)
223 {
224 if (!IsValidProcessorName(config.name)) {
225 HiLog::Error(LABEL, "invalid name=%{public}s", config.name.c_str());
226 return -1;
227 }
228 return 0;
229 }
230
VerifyRouteInfoOfReportConfig(ReportConfig & config)231 int VerifyRouteInfoOfReportConfig(ReportConfig& config)
232 {
233 if (!IsValidRouteInfo(config.routeInfo)) {
234 HiLog::Warn(LABEL, "invalid routeInfo=%{public}s", config.routeInfo.c_str());
235 config.routeInfo = "";
236 }
237 return 0;
238 }
239
VerifyAppIdOfReportConfig(ReportConfig & config)240 int VerifyAppIdOfReportConfig(ReportConfig& config)
241 {
242 if (!IsValidAppId(config.appId)) {
243 HiLog::Warn(LABEL, "invalid appId=%{public}s", config.appId.c_str());
244 config.appId = "";
245 }
246 return 0;
247 }
248
VerifyTriggerCondOfReportConfig(ReportConfig & config)249 int VerifyTriggerCondOfReportConfig(ReportConfig& config)
250 {
251 if (!IsValidBatchReport(config.triggerCond.row)) {
252 HiLog::Warn(LABEL, "invalid triggerCond.row=%{public}d", config.triggerCond.row);
253 config.triggerCond.row = 0;
254 }
255 if (!IsValidPeriodReport(config.triggerCond.timeout)) {
256 HiLog::Warn(LABEL, "invalid triggerCond.timeout=%{public}d", config.triggerCond.row);
257 config.triggerCond.timeout = 0;
258 }
259 // processor does not support the size
260 config.triggerCond.size = 0;
261 return 0;
262 }
263
VerifyUserIdNamesOfReportConfig(ReportConfig & config)264 int VerifyUserIdNamesOfReportConfig(ReportConfig& config)
265 {
266 for (const auto& name : config.userIdNames) {
267 if (!IsValidUserIdName(name)) {
268 HiLog::Warn(LABEL, "invalid user id name=%{public}s", name.c_str());
269 config.userIdNames.clear();
270 break;
271 }
272 }
273 return 0;
274 }
275
VerifyUserPropertyNamesOfReportConfig(ReportConfig & config)276 int VerifyUserPropertyNamesOfReportConfig(ReportConfig& config)
277 {
278 for (const auto& name : config.userPropertyNames) {
279 if (!IsValidUserIdName(name)) {
280 HiLog::Warn(LABEL, "invalid user property name=%{public}s", name.c_str());
281 config.userPropertyNames.clear();
282 break;
283 }
284 }
285 return 0;
286 }
287
VerifyEventConfigsOfReportConfig(ReportConfig & reportConfig)288 int VerifyEventConfigsOfReportConfig(ReportConfig& reportConfig)
289 {
290 for (const auto& eventConfig : reportConfig.eventConfigs) {
291 if (!IsValidEventConfig(eventConfig)) {
292 HiLog::Warn(LABEL, "invalid event configs, domain=%{public}s, name=%{public}s",
293 eventConfig.domain.c_str(), eventConfig.name.c_str());
294 reportConfig.eventConfigs.clear();
295 break;
296 }
297 }
298 return 0;
299 }
300 }
301
IsValidDomain(const std::string & eventDomain)302 bool IsValidDomain(const std::string& eventDomain)
303 {
304 if (eventDomain.empty() || eventDomain.length() > MAX_LEN_OF_DOMAIN) {
305 return false;
306 }
307 if (eventDomain != "OS" && !std::regex_match(eventDomain, std::regex("^[a-z]([a-z0-9_]*[a-z0-9])*$"))) {
308 return false;
309 }
310 return true;
311 }
312
IsValidEventName(const std::string & eventName)313 bool IsValidEventName(const std::string& eventName)
314 {
315 const std::string eventPrefix = "hiappevent.";
316 return eventName.find(eventPrefix) == 0 ?
317 IsValidName(eventName.substr(eventPrefix.length()), MAX_LENGTH_OF_EVENT_NAME - eventPrefix.length()) :
318 IsValidName(eventName, MAX_LENGTH_OF_EVENT_NAME);
319 }
320
IsValidWatcherName(const std::string & watcherName)321 bool IsValidWatcherName(const std::string& watcherName)
322 {
323 if (watcherName.empty() || watcherName.length() > MAX_LEN_OF_WATCHER) {
324 return false;
325 }
326 return std::regex_match(watcherName, std::regex("^[a-z]([a-z0-9_]*[a-z0-9])*$"));
327 }
328
IsValidEventType(int eventType)329 bool IsValidEventType(int eventType)
330 {
331 return eventType >= 1 && eventType <= 4; // 1-4: value range of event type
332 }
333
VerifyAppEvent(std::shared_ptr<AppEventPack> event)334 int VerifyAppEvent(std::shared_ptr<AppEventPack> event)
335 {
336 if (HiAppEventConfig::GetInstance().GetDisable()) {
337 HiLog::Error(LABEL, "the HiAppEvent function is disabled.");
338 return ERROR_HIAPPEVENT_DISABLE;
339 }
340 if (!IsValidDomain(event->GetDomain())) {
341 HiLog::Error(LABEL, "eventDomain=%{public}s is invalid.", event->GetDomain().c_str());
342 return ERROR_INVALID_EVENT_DOMAIN;
343 }
344 if (!IsValidEventName(event->GetName())) {
345 HiLog::Error(LABEL, "eventName=%{public}s is invalid.", event->GetName().c_str());
346 return ERROR_INVALID_EVENT_NAME;
347 }
348
349 int verifyRes = HIAPPEVENT_VERIFY_SUCCESSFUL;
350 std::list<AppEventParam>& baseParams = event->baseParams_;
351 std::unordered_set<std::string> paramNames;
352 for (auto it = baseParams.begin(); it != baseParams.end();) {
353 if (!VerifyAppEventParam(*it, paramNames, verifyRes)) {
354 baseParams.erase(it++);
355 continue;
356 }
357 paramNames.emplace(it->name);
358 it++;
359 }
360
361 if (!CheckParamsNum(baseParams)) {
362 HiLog::Warn(LABEL, "params that exceed 32 are discarded because the number of params cannot exceed 32.");
363 verifyRes = ERROR_INVALID_PARAM_NUM;
364 }
365
366 return verifyRes;
367 }
368
IsValidPropName(const std::string & name,size_t maxSize)369 bool IsValidPropName(const std::string& name, size_t maxSize)
370 {
371 if (name.empty() || name.length() > maxSize) {
372 return false;
373 }
374 // start char is [a-zA-Z_$]
375 if (!isalpha(name[0]) && name[0] != '_' && name[0] != '$') {
376 return false;
377 }
378 // other char is [a-zA-Z0-9_$]
379 for (size_t i = 1; i < name.length(); ++i) {
380 if (!isalnum(name[i]) && name[i] != '_' && name[i] != '$') {
381 return false;
382 }
383 }
384 return true;
385 }
386
IsValidPropValue(const std::string & val,size_t maxSize)387 bool IsValidPropValue(const std::string& val, size_t maxSize)
388 {
389 return !val.empty() && val.length() <= maxSize;
390 }
391
IsValidProcessorName(const std::string & name)392 bool IsValidProcessorName(const std::string& name)
393 {
394 return IsValidPropName(name, MAX_LENGTH_OF_PROCESSOR_NAME);
395 }
396
IsValidRouteInfo(const std::string & name)397 bool IsValidRouteInfo(const std::string& name)
398 {
399 return name.length() <= MAX_LENGTH_OF_STR_PARAM;
400 }
401
IsValidAppId(const std::string & name)402 bool IsValidAppId(const std::string& name)
403 {
404 return name.length() <= MAX_LENGTH_OF_STR_PARAM;
405 }
406
IsValidPeriodReport(int timeout)407 bool IsValidPeriodReport(int timeout)
408 {
409 return timeout >= 0;
410 }
411
IsValidBatchReport(int count)412 bool IsValidBatchReport(int count)
413 {
414 return count >= 0 && count <= MAX_LEN_OF_BATCH_REPORT;
415 }
416
IsValidUserIdName(const std::string & name)417 bool IsValidUserIdName(const std::string& name)
418 {
419 return IsValidPropName(name, MAX_LENGTH_OF_USER_INFO_NAME);
420 }
421
IsValidUserIdValue(const std::string & value)422 bool IsValidUserIdValue(const std::string& value)
423 {
424 return IsValidPropValue(value, MAX_LENGTH_OF_USER_ID_VALUE);
425 }
426
IsValidUserPropName(const std::string & name)427 bool IsValidUserPropName(const std::string& name)
428 {
429 return IsValidPropName(name, MAX_LENGTH_OF_USER_INFO_NAME);
430 }
431
IsValidUserPropValue(const std::string & value)432 bool IsValidUserPropValue(const std::string& value)
433 {
434 return IsValidPropValue(value, MAX_LENGTH_OF_USER_PROPERTY_VALUE);
435 }
436
IsValidEventConfig(const EventConfig & eventCfg)437 bool IsValidEventConfig(const EventConfig& eventCfg)
438 {
439 if (eventCfg.domain.empty() && eventCfg.name.empty()) {
440 return false;
441 }
442 if (!eventCfg.domain.empty() && !IsValidDomain(eventCfg.domain)) {
443 return false;
444 }
445 if (!eventCfg.name.empty() && !IsValidEventName(eventCfg.name)) {
446 return false;
447 }
448 return true;
449 }
450
VerifyReportConfig(ReportConfig & config)451 int VerifyReportConfig(ReportConfig& config)
452 {
453 const VerifyReportConfigFunc verifyFuncs[] = {
454 VerifyNameOfReportConfig,
455 VerifyRouteInfoOfReportConfig,
456 VerifyAppIdOfReportConfig,
457 VerifyTriggerCondOfReportConfig,
458 VerifyUserIdNamesOfReportConfig,
459 VerifyUserPropertyNamesOfReportConfig,
460 VerifyEventConfigsOfReportConfig,
461 };
462 for (const auto verifyFunc : verifyFuncs) {
463 if (verifyFunc(config) != 0) {
464 return -1;
465 }
466 }
467 return 0;
468 }
469 } // namespace HiviewDFX
470 } // namespace OHOS
471