• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = hqfInfo.nativeLibraryPath;
150         if (!hapModuleInfoNativeLibraryPath.empty() && !hqfInfoNativeLibraryPath.empty()) {
151             if ((hapModuleInfoNativeLibraryPath.find(hqfInfoNativeLibraryPath) == std::string::npos) &&
152                 (hapModuleInfoNativeLibraryPath.find(hqfInfo.cpuAbi) == std::string::npos)) {
153                 APP_LOGE("hqfInfoNativeLibraryPath: %{public}s, hapModuleInfoNativeLibraryPath: %{public}s",
154                     hqfInfoNativeLibraryPath.c_str(), hapModuleInfoNativeLibraryPath.c_str());
155                 return ERR_BUNDLEMANAGER_QUICK_FIX_SO_INCOMPATIBLE;
156             }
157         }
158     }
159 
160     return ERR_OK;
161 }
162 
CheckHotReloadWithInstalledBundle(const AppQuickFix & appQuickFix,const BundleInfo & bundleInfo)163 ErrCode QuickFixChecker::CheckHotReloadWithInstalledBundle(const AppQuickFix &appQuickFix, const BundleInfo &bundleInfo)
164 {
165     ErrCode ret = CheckCommonWithInstalledBundle(appQuickFix, bundleInfo);
166     if (ret != ERR_OK) {
167         return ret;
168     }
169     bool isDebug = bundleInfo.applicationInfo.debug &&
170         (bundleInfo.applicationInfo.appProvisionType == Constants::APP_PROVISION_TYPE_DEBUG);
171     APP_LOGD("application isDebug: %{public}d", isDebug);
172     if (!isDebug) {
173         APP_LOGE("error: hot reload type does not support release bundle");
174         return ERR_BUNDLEMANAGER_QUICK_FIX_HOT_RELOAD_NOT_SUPPORT_RELEASE_BUNDLE;
175     }
176     if (bundleInfo.applicationInfo.appQuickFix.deployedAppqfInfo.type == QuickFixType::PATCH) {
177         // patch and hot reload can not both exist
178         APP_LOGE("error: patch type already existed, hot reload and patch can not both exist");
179         return ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_ALREADY_EXISTED;
180     }
181     return ERR_OK;
182 }
183 
CheckCommonWithInstalledBundle(const AppQuickFix & appQuickFix,const BundleInfo & bundleInfo)184 ErrCode QuickFixChecker::CheckCommonWithInstalledBundle(const AppQuickFix &appQuickFix, const BundleInfo &bundleInfo)
185 {
186     // check bundleName
187     if (appQuickFix.bundleName != bundleInfo.name) {
188         APP_LOGE("error: bundleName not same, appQuickBundleName: %{public}s, bundleInfo name: %{public}s",
189             appQuickFix.bundleName.c_str(), bundleInfo.name.c_str());
190         return ERR_BUNDLEMANAGER_QUICK_FIX_BUNDLE_NAME_NOT_EXIST;
191     }
192     // check versionCode
193     if (bundleInfo.versionCode != appQuickFix.versionCode) {
194         APP_LOGE("error: versionCode not same, appQuickFix: %{public}u, bundleInfo: %{public}u",
195             appQuickFix.versionCode, bundleInfo.versionCode);
196         return ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_NOT_SAME;
197     }
198     const auto &deployedAppqfInfo = bundleInfo.applicationInfo.appQuickFix.deployedAppqfInfo;
199     if (deployedAppqfInfo.hqfInfos.empty()) {
200         APP_LOGD("no patch used in bundleName: %{public}s", bundleInfo.name.c_str());
201         return ERR_OK;
202     }
203     const auto &qfInfo = appQuickFix.deployingAppqfInfo;
204     if (qfInfo.versionCode <= deployedAppqfInfo.versionCode) {
205         APP_LOGE("qhf version code %{public}u should be greater than the original %{public}u",
206             qfInfo.versionCode, deployedAppqfInfo.versionCode);
207         return ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_ERROR;
208     }
209     return ERR_OK;
210 }
211 
CheckModuleNameExist(const BundleInfo & bundleInfo,const std::unordered_map<std::string,AppQuickFix> & infos)212 ErrCode QuickFixChecker::CheckModuleNameExist(const BundleInfo &bundleInfo,
213     const std::unordered_map<std::string, AppQuickFix> &infos)
214 {
215     for (const auto &info : infos) {
216         if (info.second.deployingAppqfInfo.hqfInfos.empty()) {
217             return ERR_BUNDLEMANAGER_QUICK_FIX_MODULE_NAME_NOT_EXIST;
218         }
219         auto iter = std::find(bundleInfo.moduleNames.begin(), bundleInfo.moduleNames.end(),
220             info.second.deployingAppqfInfo.hqfInfos[0].moduleName);
221         if (iter == bundleInfo.moduleNames.end()) {
222             APP_LOGE("error: moduleName %{public}s does not exist",
223                 info.second.deployingAppqfInfo.hqfInfos[0].moduleName.c_str());
224             return ERR_BUNDLEMANAGER_QUICK_FIX_MODULE_NAME_NOT_EXIST;
225         }
226     }
227     return ERR_OK;
228 }
229 
CheckSignatureInfo(const BundleInfo & bundleInfo,const Security::Verify::ProvisionInfo & provisionInfo)230 ErrCode QuickFixChecker::CheckSignatureInfo(const BundleInfo &bundleInfo,
231     const Security::Verify::ProvisionInfo &provisionInfo)
232 {
233     std::string quickFixAppId = bundleInfo.name + Constants::FILE_UNDERLINE + provisionInfo.appId;
234     if ((bundleInfo.appId != quickFixAppId) ||
235         (bundleInfo.applicationInfo.appPrivilegeLevel != provisionInfo.bundleInfo.apl)) {
236             APP_LOGE("Quick fix signature info is different with installed bundle : %{public}s",
237                 bundleInfo.name.c_str());
238             return ERR_BUNDLEMANAGER_QUICK_FIX_SIGNATURE_INFO_NOT_SAME;
239     }
240     if (bundleInfo.name != provisionInfo.bundleInfo.bundleName) {
241         APP_LOGE("CheckSignatureInfo failed provisionBundleName:%{public}s, bundleName:%{public}s",
242             provisionInfo.bundleInfo.bundleName.c_str(), bundleInfo.name.c_str());
243         return ERR_BUNDLEMANAGER_QUICK_FIX_SIGNATURE_INFO_NOT_SAME;
244     }
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                 APP_LOGE("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     std::unordered_map<Security::Verify::AppDistType, std::string> map = {
289         { Security::Verify::AppDistType::NONE_TYPE, Constants::APP_DISTRIBUTION_TYPE_NONE },
290         { Security::Verify::AppDistType::APP_GALLERY, Constants::APP_DISTRIBUTION_TYPE_APP_GALLERY },
291         { Security::Verify::AppDistType::ENTERPRISE, Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE },
292         { Security::Verify::AppDistType::ENTERPRISE_NORMAL, Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_NORMAL },
293         { Security::Verify::AppDistType::ENTERPRISE_MDM, Constants::APP_DISTRIBUTION_TYPE_ENTERPRISE_MDM },
294         { Security::Verify::AppDistType::OS_INTEGRATION, Constants::APP_DISTRIBUTION_TYPE_OS_INTEGRATION },
295         { Security::Verify::AppDistType::CROWDTESTING, Constants::APP_DISTRIBUTION_TYPE_CROWDTESTING },
296     };
297     auto typeIter = map.find(type);
298     if (typeIter == map.end()) {
299         APP_LOGE("wrong AppDistType");
300         return Constants::APP_DISTRIBUTION_TYPE_NONE;
301     }
302 
303     return typeIter->second;
304 }
305 
GetAppProvisionType(const Security::Verify::ProvisionType & type)306 std::string QuickFixChecker::GetAppProvisionType(const Security::Verify::ProvisionType &type)
307 {
308     if (type == Security::Verify::ProvisionType::DEBUG) {
309         return Constants::APP_PROVISION_TYPE_DEBUG;
310     }
311 
312     return Constants::APP_PROVISION_TYPE_RELEASE;
313 }
314 } // AppExecFwk
315 } // OHOS
316