1 /*
2  * Copyright (c) 2022 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 "quick_fix_checker.h"
17 
18 #include "app_log_tag_wrapper.h"
19 #include "bundle_install_checker.h"
20 
21 namespace OHOS {
22 namespace AppExecFwk {
23 size_t QuickFixChecker::QUICK_FIX_MAP_SIZE = 1;
24 
CheckMultipleHqfsSignInfo(const std::vector<std::string> & bundlePaths,std::vector<Security::Verify::HapVerifyResult> & hapVerifyRes)25 ErrCode QuickFixChecker::CheckMultipleHqfsSignInfo(
26     const std::vector<std::string> &bundlePaths,
27     std::vector<Security::Verify::HapVerifyResult> &hapVerifyRes)
28 {
29     LOG_D(BMS_TAG_DEFAULT, "Check multiple hqfs signInfo");
30     BundleInstallChecker checker;
31     return checker.CheckMultipleHapsSignInfo(bundlePaths, hapVerifyRes);
32 }
33 
CheckAppQuickFixInfos(const std::unordered_map<std::string,AppQuickFix> & infos)34 ErrCode QuickFixChecker::CheckAppQuickFixInfos(const std::unordered_map<std::string, AppQuickFix> &infos)
35 {
36     LOG_D(BMS_TAG_DEFAULT, "Check quick fix files start");
37     if (infos.size() <= QUICK_FIX_MAP_SIZE) {
38         return ERR_OK;
39     }
40     const AppQuickFix &appQuickFix = infos.begin()->second;
41     std::set<std::string> moduleNames;
42     for (const auto &info : infos) {
43         if (appQuickFix.bundleName != info.second.bundleName) {
44             LOG_E(BMS_TAG_DEFAULT, "error: appQuickFix bundleName not same");
45             return ERR_BUNDLEMANAGER_QUICK_FIX_BUNDLE_NAME_NOT_SAME;
46         }
47         if (appQuickFix.versionCode != info.second.versionCode) {
48             LOG_E(BMS_TAG_DEFAULT, "error: appQuickFix versionCode not same");
49             return ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_NOT_SAME;
50         }
51         if (appQuickFix.deployingAppqfInfo.versionCode != info.second.deployingAppqfInfo.versionCode) {
52             LOG_E(BMS_TAG_DEFAULT, "error: appQuickFix patchVersionCode not same");
53             return ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_VERSION_CODE_NOT_SAME;
54         }
55         if (appQuickFix.deployingAppqfInfo.type != info.second.deployingAppqfInfo.type) {
56             LOG_E(BMS_TAG_DEFAULT, "error: QuickFixType not same");
57             return ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_TYPE_NOT_SAME;
58         }
59         if (info.second.deployingAppqfInfo.hqfInfos.empty()) {
60             LOG_E(BMS_TAG_DEFAULT, "error: hqfInfo is empty, moduleName does not exist");
61             return ERR_BUNDLEMANAGER_QUICK_FIX_PROFILE_PARSE_FAILED;
62         }
63         const std::string &moduleName = info.second.deployingAppqfInfo.hqfInfos[0].moduleName;
64         if (moduleNames.find(moduleName) != moduleNames.end()) {
65             LOG_E(BMS_TAG_DEFAULT, "error: moduleName %{public}s is already exist", moduleName.c_str());
66             return ERR_BUNDLEMANAGER_QUICK_FIX_MODULE_NAME_SAME;
67         }
68         moduleNames.insert(moduleName);
69     }
70     LOG_D(BMS_TAG_DEFAULT, "Check quick fix files end");
71     return ERR_OK;
72 }
73 
CheckPatchWithInstalledBundle(const AppQuickFix & appQuickFix,const BundleInfo & bundleInfo,const Security::Verify::ProvisionInfo & provisionInfo)74 ErrCode QuickFixChecker::CheckPatchWithInstalledBundle(const AppQuickFix &appQuickFix,
75     const BundleInfo &bundleInfo, const Security::Verify::ProvisionInfo &provisionInfo)
76 {
77     ErrCode ret = CheckCommonWithInstalledBundle(appQuickFix, bundleInfo);
78     if (ret != ERR_OK) {
79         LOG_E(BMS_TAG_DEFAULT, "error: CheckCommonWithInstalledBundle failed");
80         return ret;
81     }
82     bool isDebug = bundleInfo.applicationInfo.debug &&
83         (bundleInfo.applicationInfo.appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG);
84     LOG_D(BMS_TAG_DEFAULT, "application isDebug: %{public}d", isDebug);
85     if (isDebug && (bundleInfo.applicationInfo.appQuickFix.deployedAppqfInfo.type == QuickFixType::HOT_RELOAD)) {
86         // patch and hot reload can not both exist
87         LOG_E(BMS_TAG_DEFAULT, "hot reload type already existed, hot reload and patch type can not both exist");
88         return ERR_BUNDLEMANAGER_QUICK_FIX_HOT_RELOAD_ALREADY_EXISTED;
89     }
90 
91     const auto &qfInfo = appQuickFix.deployingAppqfInfo;
92     ret = CheckPatchNativeSoWithInstalledBundle(bundleInfo, qfInfo);
93     if (ret != ERR_OK) {
94         LOG_E(BMS_TAG_DEFAULT, "error: CheckPatchNativeSoWithInstalledBundle failed");
95         return ret;
96     }
97 
98     ret = CheckSignatureInfo(bundleInfo, provisionInfo);
99     if (ret != ERR_OK) {
100         LOG_E(BMS_TAG_DEFAULT, "error: CheckSignatureInfo failed, appId or apl not same");
101         return ret;
102     }
103     return ERR_OK;
104 }
105 
CheckPatchNativeSoWithInstalledBundle(const BundleInfo & bundleInfo,const AppqfInfo & qfInfo)106 ErrCode QuickFixChecker::CheckPatchNativeSoWithInstalledBundle(
107     const BundleInfo &bundleInfo, const AppqfInfo &qfInfo)
108 {
109     bool hasAppLib =
110         (!qfInfo.nativeLibraryPath.empty() && !bundleInfo.applicationInfo.nativeLibraryPath.empty());
111     if (hasAppLib) {
112         if (qfInfo.cpuAbi != bundleInfo.applicationInfo.cpuAbi) {
113             LOG_E(BMS_TAG_DEFAULT, "qfInfo.cpuAbi: %{public}s, applicationInfo.cpuAbi: %{public}s",
114                 qfInfo.cpuAbi.c_str(), bundleInfo.applicationInfo.cpuAbi.c_str());
115             return ERR_BUNDLEMANAGER_QUICK_FIX_SO_INCOMPATIBLE;
116         }
117 
118         if (qfInfo.nativeLibraryPath != bundleInfo.applicationInfo.nativeLibraryPath) {
119             LOG_E(BMS_TAG_DEFAULT, "qfInfo path: %{public}s, applicationInfo path: %{public}s",
120                 qfInfo.nativeLibraryPath.c_str(), bundleInfo.applicationInfo.nativeLibraryPath.c_str());
121             return ERR_BUNDLEMANAGER_QUICK_FIX_SO_INCOMPATIBLE;
122         }
123     }
124 
125     for (const auto &hqfInfo : qfInfo.hqfInfos) {
126         auto iter = std::find_if(bundleInfo.hapModuleInfos.begin(), bundleInfo.hapModuleInfos.end(),
127             [moduleName = hqfInfo.moduleName](const auto &hapModuleInfo) {
128                 return hapModuleInfo.moduleName == moduleName;
129             });
130         if (iter == bundleInfo.hapModuleInfos.end()) {
131             continue;
132         }
133 
134         auto &hapModuleInfoNativeLibraryPath = iter->nativeLibraryPath;
135         auto &hqfInfoNativeLibraryPath = hqfInfo.nativeLibraryPath;
136         if (!hapModuleInfoNativeLibraryPath.empty() && !hqfInfoNativeLibraryPath.empty()) {
137             if ((hapModuleInfoNativeLibraryPath.find(hqfInfoNativeLibraryPath) == std::string::npos) &&
138                 (hapModuleInfoNativeLibraryPath.find(hqfInfo.cpuAbi) == std::string::npos)) {
139                 LOG_E(BMS_TAG_DEFAULT, "hqfNativeLibraryPath: %{public}s, moduleNativeLibraryPath: %{public}s",
140                     hqfInfoNativeLibraryPath.c_str(), hapModuleInfoNativeLibraryPath.c_str());
141                 return ERR_BUNDLEMANAGER_QUICK_FIX_SO_INCOMPATIBLE;
142             }
143         }
144     }
145 
146     return ERR_OK;
147 }
148 
CheckHotReloadWithInstalledBundle(const AppQuickFix & appQuickFix,const BundleInfo & bundleInfo)149 ErrCode QuickFixChecker::CheckHotReloadWithInstalledBundle(const AppQuickFix &appQuickFix, const BundleInfo &bundleInfo)
150 {
151     ErrCode ret = CheckCommonWithInstalledBundle(appQuickFix, bundleInfo);
152     if (ret != ERR_OK) {
153         LOG_E(BMS_TAG_DEFAULT, "error: CheckCommonWithInstalledBundle failed");
154         return ret;
155     }
156     bool isDebug = bundleInfo.applicationInfo.debug &&
157         (bundleInfo.applicationInfo.appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG);
158     LOG_D(BMS_TAG_DEFAULT, "application isDebug: %{public}d", isDebug);
159     if (!isDebug) {
160         LOG_E(BMS_TAG_DEFAULT, "error: hot reload type does not support release bundle");
161         return ERR_BUNDLEMANAGER_QUICK_FIX_HOT_RELOAD_NOT_SUPPORT_RELEASE_BUNDLE;
162     }
163     if (bundleInfo.applicationInfo.appQuickFix.deployedAppqfInfo.type == QuickFixType::PATCH) {
164         // patch and hot reload can not both exist
165         LOG_E(BMS_TAG_DEFAULT, "error: patch type already existed, hot reload and patch can not both exist");
166         return ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_ALREADY_EXISTED;
167     }
168     return ERR_OK;
169 }
170 
CheckCommonWithInstalledBundle(const AppQuickFix & appQuickFix,const BundleInfo & bundleInfo)171 ErrCode QuickFixChecker::CheckCommonWithInstalledBundle(const AppQuickFix &appQuickFix, const BundleInfo &bundleInfo)
172 {
173     // check bundleName
174     if (appQuickFix.bundleName != bundleInfo.name) {
175         LOG_E(BMS_TAG_DEFAULT, "appQuickBundleName:%{public}s, bundleInfo name:%{public}s not same",
176             appQuickFix.bundleName.c_str(), bundleInfo.name.c_str());
177         return ERR_BUNDLEMANAGER_QUICK_FIX_BUNDLE_NAME_NOT_EXIST;
178     }
179     // check versionCode
180     if (bundleInfo.versionCode != appQuickFix.versionCode) {
181         LOG_E(BMS_TAG_DEFAULT, "error: versionCode not same, appQuickFix: %{public}u, bundleInfo: %{public}u",
182             appQuickFix.versionCode, bundleInfo.versionCode);
183         return ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_NOT_SAME;
184     }
185     const auto &deployedAppqfInfo = bundleInfo.applicationInfo.appQuickFix.deployedAppqfInfo;
186     if (deployedAppqfInfo.hqfInfos.empty()) {
187         LOG_D(BMS_TAG_DEFAULT, "no patch used in bundleName: %{public}s", bundleInfo.name.c_str());
188         return ERR_OK;
189     }
190     const auto &qfInfo = appQuickFix.deployingAppqfInfo;
191     if (qfInfo.versionCode <= deployedAppqfInfo.versionCode) {
192         LOG_E(BMS_TAG_DEFAULT, "qhf version code %{public}u should be greater than the original %{public}u",
193             qfInfo.versionCode, deployedAppqfInfo.versionCode);
194         return ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_ERROR;
195     }
196     return ERR_OK;
197 }
198 
CheckModuleNameExist(const BundleInfo & bundleInfo,const std::unordered_map<std::string,AppQuickFix> & infos)199 ErrCode QuickFixChecker::CheckModuleNameExist(const BundleInfo &bundleInfo,
200     const std::unordered_map<std::string, AppQuickFix> &infos)
201 {
202     for (const auto &info : infos) {
203         if (info.second.deployingAppqfInfo.hqfInfos.empty()) {
204             LOG_E(BMS_TAG_DEFAULT, "info is empty");
205             return ERR_BUNDLEMANAGER_QUICK_FIX_MODULE_NAME_NOT_EXIST;
206         }
207         auto iter = std::find(bundleInfo.moduleNames.begin(), bundleInfo.moduleNames.end(),
208             info.second.deployingAppqfInfo.hqfInfos[0].moduleName);
209         if (iter == bundleInfo.moduleNames.end()) {
210             LOG_E(BMS_TAG_DEFAULT, "error: moduleName %{public}s does not exist",
211                 info.second.deployingAppqfInfo.hqfInfos[0].moduleName.c_str());
212             return ERR_BUNDLEMANAGER_QUICK_FIX_MODULE_NAME_NOT_EXIST;
213         }
214     }
215     return ERR_OK;
216 }
217 
CheckSignatureInfo(const BundleInfo & bundleInfo,const Security::Verify::ProvisionInfo & provisionInfo)218 ErrCode QuickFixChecker::CheckSignatureInfo(const BundleInfo &bundleInfo,
219     const Security::Verify::ProvisionInfo &provisionInfo)
220 {
221 #ifndef X86_EMULATOR_MODE
222     std::string quickFixAppId = bundleInfo.name + Constants::FILE_UNDERLINE + provisionInfo.appId;
223     if (bundleInfo.applicationInfo.appPrivilegeLevel != provisionInfo.bundleInfo.apl) {
224         LOG_E(BMS_TAG_DEFAULT, "Quick fix signature info is different with installed bundle : %{public}s",
225             bundleInfo.name.c_str());
226         return ERR_BUNDLEMANAGER_QUICK_FIX_SIGNATURE_INFO_NOT_SAME;
227     }
228     if (bundleInfo.signatureInfo.appIdentifier.empty() || provisionInfo.bundleInfo.appIdentifier.empty()) {
229         if (bundleInfo.appId != quickFixAppId) {
230             LOG_E(BMS_TAG_DEFAULT, "Quick fix signature info is different with installed bundle : %{public}s",
231                 bundleInfo.name.c_str());
232             return ERR_BUNDLEMANAGER_QUICK_FIX_SIGNATURE_INFO_NOT_SAME;
233         }
234     } else if (bundleInfo.signatureInfo.appIdentifier != provisionInfo.bundleInfo.appIdentifier) {
235         LOG_E(BMS_TAG_DEFAULT, "Quick fix appIdentifier info is different with installed bundle : %{public}s",
236             bundleInfo.name.c_str());
237         return ERR_BUNDLEMANAGER_QUICK_FIX_SIGNATURE_INFO_NOT_SAME;
238     }
239     if (bundleInfo.name != provisionInfo.bundleInfo.bundleName) {
240         LOG_E(BMS_TAG_DEFAULT, "CheckSignatureInfo failed provisionBundleName:%{public}s, bundleName:%{public}s",
241             provisionInfo.bundleInfo.bundleName.c_str(), bundleInfo.name.c_str());
242         return ERR_BUNDLEMANAGER_QUICK_FIX_SIGNATURE_INFO_NOT_SAME;
243     }
244 #endif
245     return ERR_OK;
246 }
247 
CheckMultiNativeSo(std::unordered_map<std::string,AppQuickFix> & infos)248 ErrCode QuickFixChecker::CheckMultiNativeSo(
249     std::unordered_map<std::string, AppQuickFix> &infos)
250 {
251     if (infos.size() <= QUICK_FIX_MAP_SIZE) {
252         return ERR_OK;
253     }
254     const AppqfInfo &appqfInfo = (infos.begin()->second).deployingAppqfInfo;
255     std::string nativeLibraryPath = appqfInfo.nativeLibraryPath;
256     std::string cpuAbi = appqfInfo.cpuAbi;
257     for (const auto &info : infos) {
258         const AppqfInfo &qfInfo = info.second.deployingAppqfInfo;
259         if (qfInfo.nativeLibraryPath.empty()) {
260             continue;
261         }
262         if (nativeLibraryPath.empty()) {
263             nativeLibraryPath = qfInfo.nativeLibraryPath;
264             cpuAbi = qfInfo.cpuAbi;
265             continue;
266         }
267         if (!qfInfo.nativeLibraryPath.empty()) {
268             if ((nativeLibraryPath != qfInfo.nativeLibraryPath) || (cpuAbi != qfInfo.cpuAbi)) {
269                 LOG_E(BMS_TAG_DEFAULT, "check native so with installed bundle failed");
270                 return ERR_BUNDLEMANAGER_QUICK_FIX_SO_INCOMPATIBLE;
271             }
272         }
273     }
274 
275     // Ensure the so is consistent in multiple haps
276     if (!nativeLibraryPath.empty()) {
277         for (auto &info : infos) {
278             info.second.deployingAppqfInfo.nativeLibraryPath = nativeLibraryPath;
279             info.second.deployingAppqfInfo.cpuAbi = cpuAbi;
280         }
281     }
282 
283     return ERR_OK;
284 }
285 
GetAppDistributionType(const Security::Verify::AppDistType & type)286 std::string QuickFixChecker::GetAppDistributionType(const Security::Verify::AppDistType &type)
287 {
288     auto typeIter = APP_DISTRIBUTION_TYPE_MAPS.find(type);
289     if (typeIter == APP_DISTRIBUTION_TYPE_MAPS.end()) {
290         LOG_E(BMS_TAG_DEFAULT, "wrong AppDistType");
291         return Constants::APP_DISTRIBUTION_TYPE_NONE;
292     }
293 
294     return typeIter->second;
295 }
296 
GetAppProvisionType(const Security::Verify::ProvisionType & type)297 std::string QuickFixChecker::GetAppProvisionType(const Security::Verify::ProvisionType &type)
298 {
299     if (type == Security::Verify::ProvisionType::DEBUG) {
300         return Constants::APP_PROVISION_TYPE_DEBUG;
301     }
302 
303     return Constants::APP_PROVISION_TYPE_RELEASE;
304 }
305 } // AppExecFwk
306 } // OHOS
307