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