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 "installd/installd_operator.h"
17
18 #include <algorithm>
19 #if defined(CODE_SIGNATURE_ENABLE)
20 #include "code_sign_utils.h"
21 #endif
22 #if defined(CODE_ENCRYPTION_ENABLE)
23 #include <sys/ioctl.h>
24 #include "code_crypto_metadata_process.h"
25 #include "linux/code_decrypt.h"
26 #endif
27 #include <cerrno>
28 #include <cstdio>
29 #include <dirent.h>
30 #include <dlfcn.h>
31 #include <fcntl.h>
32 #include <filesystem>
33 #include <fstream>
34 #include <map>
35 #include <regex>
36 #include <sstream>
37 #include <string.h>
38 #include <sys/mman.h>
39 #include <sys/quota.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43
44 #include "app_log_wrapper.h"
45 #include "bundle_constants.h"
46 #include "bundle_util.h"
47 #include "directory_ex.h"
48 #include "parameters.h"
49
50 namespace OHOS {
51 namespace AppExecFwk {
52 namespace {
53 static const char LIB_DIFF_PATCH_SHARED_SO_PATH[] = "system/lib/libdiff_patch_shared.z.so";
54 static const char LIB64_DIFF_PATCH_SHARED_SO_PATH[] = "system/lib64/libdiff_patch_shared.z.so";
55 static const char APPLY_PATCH_FUNCTION_NAME[] = "ApplyPatch";
56 static std::string PREFIX_RESOURCE_PATH = "/resources/rawfile/";
57 static std::string PREFIX_TARGET_PATH = "/print_service/";
58 static const std::string SO_SUFFIX_REGEX = "\\.so\\.[0-9][0-9]*$";
59 static constexpr int32_t INSTALLS_UID = 3060;
60 static constexpr int32_t MODE_BASE = 07777;
61 static const std::string PROC_MOUNTS_PATH = "/proc/mounts";
62 static const std::string QUOTA_DEVICE_DATA_PATH = "/data";
63 #if defined(CODE_SIGNATURE_ENABLE)
64 using namespace OHOS::Security::CodeSign;
65 #endif
66 #if defined(CODE_ENCRYPTION_ENABLE)
67 static std::string CODE_DECRYPT = "/dev/code_decrypt";
68 static int32_t INVALID_RETURN_VALUE = -1;
69 static int32_t INVALID_FILE_DESCRIPTOR = -1;
70 #endif
71 std::recursive_mutex mMountsLock;
72 static std::map<std::string, std::string> mQuotaReverseMounts;
73 using ApplyPatch = int32_t (*)(const std::string, const std::string, const std::string);
74
HandleScanResult(const std::string & dir,const std::string & subName,ResultMode resultMode)75 static std::string HandleScanResult(
76 const std::string &dir, const std::string &subName, ResultMode resultMode)
77 {
78 if (resultMode == ResultMode::RELATIVE_PATH) {
79 return subName;
80 }
81
82 return dir + Constants::PATH_SEPARATOR + subName;
83 }
84
StartsWith(const std::string & sourceString,const std::string & targetPrefix)85 static bool StartsWith(const std::string &sourceString, const std::string &targetPrefix)
86 {
87 return sourceString.find(targetPrefix) == 0;
88 }
89
EndsWith(const std::string & sourceString,const std::string & targetSuffix)90 static bool EndsWith(const std::string &sourceString, const std::string &targetSuffix)
91 {
92 if (sourceString.length() < targetSuffix.length()) {
93 return false;
94 }
95 if (sourceString.rfind(targetSuffix) == (sourceString.length() - targetSuffix.length())) {
96 return true;
97 }
98 if (targetSuffix == Constants::SO_SUFFIX) {
99 std::regex soRegex(SO_SUFFIX_REGEX);
100 return std::regex_search(sourceString, soRegex);
101 }
102 return false;
103 }
104 } // namespace
105
IsExistFile(const std::string & path)106 bool InstalldOperator::IsExistFile(const std::string &path)
107 {
108 if (path.empty()) {
109 return false;
110 }
111
112 struct stat buf = {};
113 if (stat(path.c_str(), &buf) != 0) {
114 return false;
115 }
116 return S_ISREG(buf.st_mode);
117 }
118
IsExistApFile(const std::string & path)119 bool InstalldOperator::IsExistApFile(const std::string &path)
120 {
121 std::string realPath;
122 std::filesystem::path apFilePath(path);
123 std::string apDir = apFilePath.parent_path().string();
124 if (path.empty() || !PathToRealPath(apDir, realPath)) {
125 return false;
126 }
127
128 std::error_code errorCode;
129 std::filesystem::directory_iterator iter(realPath, errorCode);
130
131 if (errorCode) {
132 APP_LOGE("Error occurred while opening apDir: %{public}s", errorCode.message().c_str());
133 return false;
134 }
135 for (const auto& entry : iter) {
136 if (entry.path().extension() == Constants::AP_SUFFIX) {
137 return true;
138 }
139 }
140 return false;
141 }
142
IsExistDir(const std::string & path)143 bool InstalldOperator::IsExistDir(const std::string &path)
144 {
145 if (path.empty()) {
146 return false;
147 }
148
149 struct stat buf = {};
150 if (stat(path.c_str(), &buf) != 0) {
151 APP_LOGW("the path is not existed %{public}s", path.c_str());
152 return false;
153 }
154 return S_ISDIR(buf.st_mode);
155 }
156
IsDirEmpty(const std::string & dir)157 bool InstalldOperator::IsDirEmpty(const std::string &dir)
158 {
159 return OHOS::IsEmptyFolder(dir);
160 }
161
MkRecursiveDir(const std::string & path,bool isReadByOthers)162 bool InstalldOperator::MkRecursiveDir(const std::string &path, bool isReadByOthers)
163 {
164 if (!OHOS::ForceCreateDirectory(path)) {
165 APP_LOGE("mkdir failed");
166 return false;
167 }
168 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH;
169 mode |= (isReadByOthers ? S_IROTH : 0);
170 return OHOS::ChangeModeDirectory(path, mode);
171 }
172
DeleteDir(const std::string & path)173 bool InstalldOperator::DeleteDir(const std::string &path)
174 {
175 APP_LOGD("start to delete dir %{public}s", path.c_str());
176 if (IsExistFile(path)) {
177 return OHOS::RemoveFile(path);
178 }
179 if (IsExistDir(path)) {
180 return OHOS::ForceRemoveDirectory(path);
181 }
182 return true;
183 }
184
ExtractFiles(const std::string & sourcePath,const std::string & targetSoPath,const std::string & cpuAbi)185 bool InstalldOperator::ExtractFiles(const std::string &sourcePath, const std::string &targetSoPath,
186 const std::string &cpuAbi)
187 {
188 APP_LOGD("InstalldOperator::ExtractFiles start");
189 if (targetSoPath.empty()) {
190 return true;
191 }
192
193 BundleExtractor extractor(sourcePath);
194 if (!extractor.Init()) {
195 return false;
196 }
197
198 std::vector<std::string> soEntryFiles;
199 if (!ObtainNativeSoFile(extractor, cpuAbi, soEntryFiles)) {
200 APP_LOGE("ExtractFiles obtain native so file entryName failed");
201 return false;
202 }
203
204 for_each(soEntryFiles.begin(), soEntryFiles.end(), [&extractor, &targetSoPath, &cpuAbi](const auto &entry) {
205 ExtractTargetFile(extractor, entry, targetSoPath, cpuAbi);
206 });
207
208 APP_LOGD("InstalldOperator::ExtractFiles end");
209 return true;
210 }
211
ExtractFiles(const ExtractParam & extractParam)212 bool InstalldOperator::ExtractFiles(const ExtractParam &extractParam)
213 {
214 APP_LOGD("InstalldOperator::ExtractFiles start");
215 BundleExtractor extractor(extractParam.srcPath);
216 if (!extractor.Init()) {
217 APP_LOGE("extractor init failed");
218 return false;
219 }
220
221 if (extractParam.extractFileType == ExtractFileType::RESOURCE) {
222 return ExtractResourceFiles(extractParam, extractor);
223 }
224
225 if ((extractParam.extractFileType == ExtractFileType::AP) &&
226 !extractor.IsDirExist(Constants::AP)) {
227 APP_LOGD("hap has no ap files and does not need to be extracted.");
228 return true;
229 }
230
231 std::vector<std::string> entryNames;
232 if (!extractor.GetZipFileNames(entryNames) || entryNames.empty()) {
233 APP_LOGE("get entryNames failed");
234 return false;
235 }
236
237 for (const auto &entryName : entryNames) {
238 if (strcmp(entryName.c_str(), ".") == 0 ||
239 strcmp(entryName.c_str(), "..") == 0) {
240 continue;
241 }
242 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
243 continue;
244 }
245 // handle native file
246 if (IsNativeFile(entryName, extractParam)) {
247 ExtractTargetFile(extractor, entryName, extractParam.targetPath,
248 extractParam.cpuAbi, extractParam.extractFileType);
249 continue;
250 }
251 }
252
253 APP_LOGD("InstalldOperator::ExtractFiles end");
254 return true;
255 }
256
IsNativeFile(const std::string & entryName,const ExtractParam & extractParam)257 bool InstalldOperator::IsNativeFile(
258 const std::string &entryName, const ExtractParam &extractParam)
259 {
260 APP_LOGD("IsNativeFile, entryName : %{public}s", entryName.c_str());
261 if (extractParam.targetPath.empty()) {
262 APP_LOGD("current hap not include so");
263 return false;
264 }
265 std::string prefix;
266 std::vector<std::string> suffixes;
267 if (!DeterminePrefix(extractParam.extractFileType, extractParam.cpuAbi, prefix) ||
268 !DetermineSuffix(extractParam.extractFileType, suffixes)) {
269 APP_LOGE("determine prefix or suffix failed");
270 return false;
271 }
272
273 if (!StartsWith(entryName, prefix)) {
274 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
275 return false;
276 }
277
278 bool checkSuffix = false;
279 for (const auto &suffix : suffixes) {
280 if (EndsWith(entryName, suffix)) {
281 checkSuffix = true;
282 break;
283 }
284 }
285
286 if (!checkSuffix && extractParam.extractFileType != ExtractFileType::RES_FILE) {
287 APP_LOGD("file type error.");
288 return false;
289 }
290
291 APP_LOGD("find native file, prefix: %{public}s, entryName: %{public}s",
292 prefix.c_str(), entryName.c_str());
293 return true;
294 }
295
IsNativeSo(const std::string & entryName,const std::string & cpuAbi)296 bool InstalldOperator::IsNativeSo(const std::string &entryName, const std::string &cpuAbi)
297 {
298 APP_LOGD("IsNativeSo, entryName : %{public}s", entryName.c_str());
299 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
300 if (!StartsWith(entryName, prefix)) {
301 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
302 return false;
303 }
304 if (!EndsWith(entryName, Constants::SO_SUFFIX)) {
305 APP_LOGD("file name not so format.");
306 return false;
307 }
308 APP_LOGD("find native so, entryName : %{public}s", entryName.c_str());
309 return true;
310 }
311
IsDiffFiles(const std::string & entryName,const std::string & targetPath,const std::string & cpuAbi)312 bool InstalldOperator::IsDiffFiles(const std::string &entryName,
313 const std::string &targetPath, const std::string &cpuAbi)
314 {
315 APP_LOGD("IsDiffFiles, entryName : %{public}s", entryName.c_str());
316 if (targetPath.empty()) {
317 APP_LOGD("current hap not include diff");
318 return false;
319 }
320 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
321 if (!StartsWith(entryName, prefix)) {
322 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
323 return false;
324 }
325 if (!EndsWith(entryName, Constants::DIFF_SUFFIX)) {
326 APP_LOGD("file name not diff format.");
327 return false;
328 }
329 APP_LOGD("find native diff, entryName : %{public}s", entryName.c_str());
330 return true;
331 }
332
ExtractTargetFile(const BundleExtractor & extractor,const std::string & entryName,const std::string & targetPath,const std::string & cpuAbi,const ExtractFileType & extractFileType)333 void InstalldOperator::ExtractTargetFile(const BundleExtractor &extractor, const std::string &entryName,
334 const std::string &targetPath, const std::string &cpuAbi, const ExtractFileType &extractFileType)
335 {
336 // create dir if not exist
337 if (!IsExistDir(targetPath)) {
338 if (!MkRecursiveDir(targetPath, true)) {
339 APP_LOGE("create targetPath %{public}s failed", targetPath.c_str());
340 return;
341 }
342 }
343
344 std::string prefix;
345 if (!DeterminePrefix(extractFileType, cpuAbi, prefix)) {
346 APP_LOGE("determine prefix failed");
347 return;
348 }
349 std::string targetName = entryName.substr(prefix.length());
350 std::string path = targetPath;
351 if (path.back() != Constants::FILE_SEPARATOR_CHAR) {
352 path += Constants::FILE_SEPARATOR_CHAR;
353 }
354 path += targetName;
355 if (targetName.find(Constants::PATH_SEPARATOR) != std::string::npos) {
356 std::string dir = GetPathDir(path);
357 if (!IsExistDir(dir) && !MkRecursiveDir(dir, true)) {
358 APP_LOGE("create dir %{public}s failed", dir.c_str());
359 return;
360 }
361 }
362 bool ret = extractor.ExtractFile(entryName, path);
363 if (!ret) {
364 APP_LOGE("extract file failed, entryName : %{public}s", entryName.c_str());
365 return;
366 }
367 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
368 if (extractFileType == ExtractFileType::AP) {
369 struct stat buf = {};
370 if (stat(targetPath.c_str(), &buf) != 0) {
371 return;
372 }
373 ChangeFileAttr(path, buf.st_uid, buf.st_gid);
374 mode = (buf.st_uid == buf.st_gid) ? (S_IRUSR | S_IWUSR) : (S_IRUSR | S_IWUSR | S_IRGRP);
375 }
376 if (!OHOS::ChangeModeFile(path, mode)) {
377 APP_LOGE("ChangeModeFile %{public}s failed, errno: %{public}d", path.c_str(), errno);
378 return;
379 }
380 APP_LOGD("extract file success, path : %{public}s", path.c_str());
381 }
382
DeterminePrefix(const ExtractFileType & extractFileType,const std::string & cpuAbi,std::string & prefix)383 bool InstalldOperator::DeterminePrefix(const ExtractFileType &extractFileType, const std::string &cpuAbi,
384 std::string &prefix)
385 {
386 switch (extractFileType) {
387 case ExtractFileType::SO: {
388 prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
389 break;
390 }
391 case ExtractFileType::AN: {
392 prefix = Constants::AN + cpuAbi + Constants::PATH_SEPARATOR;
393 break;
394 }
395 case ExtractFileType::AP: {
396 prefix = Constants::AP;
397 break;
398 }
399 case ExtractFileType::RES_FILE: {
400 prefix = Constants::RES_FILE_PATH;
401 break;
402 }
403 default: {
404 return false;
405 }
406 }
407 return true;
408 }
409
DetermineSuffix(const ExtractFileType & extractFileType,std::vector<std::string> & suffixes)410 bool InstalldOperator::DetermineSuffix(const ExtractFileType &extractFileType, std::vector<std::string> &suffixes)
411 {
412 switch (extractFileType) {
413 case ExtractFileType::SO: {
414 suffixes.emplace_back(Constants::SO_SUFFIX);
415 break;
416 }
417 case ExtractFileType::AN: {
418 suffixes.emplace_back(Constants::AN_SUFFIX);
419 suffixes.emplace_back(Constants::AI_SUFFIX);
420 break;
421 }
422 case ExtractFileType::AP: {
423 suffixes.emplace_back(Constants::AP_SUFFIX);
424 break;
425 }
426 case ExtractFileType::RES_FILE: {
427 break;
428 }
429 default: {
430 return false;
431 }
432 }
433 return true;
434 }
435
RenameDir(const std::string & oldPath,const std::string & newPath)436 bool InstalldOperator::RenameDir(const std::string &oldPath, const std::string &newPath)
437 {
438 if (oldPath.empty() || oldPath.size() > PATH_MAX) {
439 APP_LOGE("oldpath error");
440 return false;
441 }
442 if (access(oldPath.c_str(), F_OK) != 0 && access(newPath.c_str(), F_OK) == 0) {
443 return true;
444 }
445 std::string realOldPath;
446 realOldPath.reserve(PATH_MAX);
447 realOldPath.resize(PATH_MAX - 1);
448 if (realpath(oldPath.c_str(), &(realOldPath[0])) == nullptr) {
449 APP_LOGE("realOldPath %{public}s", realOldPath.c_str());
450 return false;
451 }
452
453 if (!(IsValidCodePath(realOldPath) && IsValidCodePath(newPath))) {
454 APP_LOGE("IsValidCodePath failed");
455 return false;
456 }
457 return RenameFile(realOldPath, newPath);
458 }
459
GetPathDir(const std::string & path)460 std::string InstalldOperator::GetPathDir(const std::string &path)
461 {
462 std::size_t pos = path.rfind(Constants::PATH_SEPARATOR);
463 if (pos == std::string::npos) {
464 return std::string();
465 }
466 return path.substr(0, pos + 1);
467 }
468
ChangeDirOwnerRecursively(const std::string & path,const int uid,const int gid)469 bool InstalldOperator::ChangeDirOwnerRecursively(const std::string &path, const int uid, const int gid)
470 {
471 std::string subPath;
472 bool ret = true;
473 DIR *dir = opendir(path.c_str());
474 if (dir == nullptr) {
475 return false;
476 }
477
478 while (true) {
479 struct dirent *ptr = readdir(dir);
480 if (ptr == nullptr) {
481 break;
482 }
483
484 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
485 continue;
486 }
487
488 subPath = OHOS::IncludeTrailingPathDelimiter(path) + std::string(ptr->d_name);
489 if (ptr->d_type == DT_DIR) {
490 ret = ChangeDirOwnerRecursively(subPath, uid, gid);
491 continue;
492 }
493
494 if (access(subPath.c_str(), F_OK) == 0) {
495 if (!ChangeFileAttr(subPath, uid, gid)) {
496 APP_LOGE("Failed to ChangeFileAttr %{public}s, uid=%{public}d", subPath.c_str(), uid);
497 closedir(dir);
498 return false;
499 }
500 }
501 }
502
503 closedir(dir);
504 std::string currentPath = OHOS::ExcludeTrailingPathDelimiter(path);
505 if (access(currentPath.c_str(), F_OK) == 0) {
506 if (!ChangeFileAttr(currentPath, uid, gid)) {
507 APP_LOGE("Failed to ChangeFileAttr %{public}s, uid=%{public}d", currentPath.c_str(), uid);
508 return false;
509 }
510 }
511
512 return ret;
513 }
514
ChangeFileAttr(const std::string & filePath,const int uid,const int gid)515 bool InstalldOperator::ChangeFileAttr(const std::string &filePath, const int uid, const int gid)
516 {
517 APP_LOGD("begin to change %{public}s file attribute", filePath.c_str());
518 if (chown(filePath.c_str(), uid, gid) != 0) {
519 APP_LOGE("fail to change %{public}s ownership, uid=%{public}d", filePath.c_str(), uid);
520 return false;
521 }
522 APP_LOGD("change %{public}s file attribute successfully", filePath.c_str());
523 return true;
524 }
525
RenameFile(const std::string & oldPath,const std::string & newPath)526 bool InstalldOperator::RenameFile(const std::string &oldPath, const std::string &newPath)
527 {
528 if (oldPath.empty() || newPath.empty()) {
529 return false;
530 }
531 if (!DeleteDir(newPath)) {
532 return false;
533 }
534 return rename(oldPath.c_str(), newPath.c_str()) == 0;
535 }
536
IsValidPath(const std::string & rootDir,const std::string & path)537 bool InstalldOperator::IsValidPath(const std::string &rootDir, const std::string &path)
538 {
539 if (rootDir.find(Constants::PATH_SEPARATOR) != 0 ||
540 rootDir.rfind(Constants::PATH_SEPARATOR) != (rootDir.size() - 1) || rootDir.find("..") != std::string::npos) {
541 return false;
542 }
543 if (path.find("..") != std::string::npos) {
544 return false;
545 }
546 return path.compare(0, rootDir.size(), rootDir) == 0;
547 }
548
IsValidCodePath(const std::string & codePath)549 bool InstalldOperator::IsValidCodePath(const std::string &codePath)
550 {
551 if (codePath.empty()) {
552 return false;
553 }
554 return IsValidPath(Constants::BUNDLE_BASE_CODE_DIR + Constants::PATH_SEPARATOR, codePath);
555 }
556
DeleteFiles(const std::string & dataPath)557 bool InstalldOperator::DeleteFiles(const std::string &dataPath)
558 {
559 APP_LOGD("InstalldOperator::DeleteFiles start");
560 std::string subPath;
561 bool ret = true;
562 DIR *dir = opendir(dataPath.c_str());
563 if (dir == nullptr) {
564 return false;
565 }
566 while (true) {
567 struct dirent *ptr = readdir(dir);
568 if (ptr == nullptr) {
569 break;
570 }
571 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
572 continue;
573 }
574 subPath = OHOS::IncludeTrailingPathDelimiter(dataPath) + std::string(ptr->d_name);
575 if (ptr->d_type == DT_DIR) {
576 ret = OHOS::ForceRemoveDirectory(subPath);
577 } else {
578 if (access(subPath.c_str(), F_OK) == 0) {
579 ret = OHOS::RemoveFile(subPath);
580 }
581 }
582 }
583 closedir(dir);
584 return ret;
585 }
586
DeleteFilesExceptDirs(const std::string & dataPath,const std::vector<std::string> & dirsToKeep)587 bool InstalldOperator::DeleteFilesExceptDirs(const std::string &dataPath, const std::vector<std::string> &dirsToKeep)
588 {
589 APP_LOGD("InstalldOperator::DeleteFilesExceptBundleDataDirs start");
590 std::string filePath;
591 DIR *dir = opendir(dataPath.c_str());
592 if (dir == nullptr) {
593 return false;
594 }
595 bool ret = true;
596 while (true) {
597 struct dirent *ptr = readdir(dir);
598 if (ptr == nullptr) {
599 break;
600 }
601 std::string dirName = Constants::PATH_SEPARATOR + std::string(ptr->d_name);
602 if (std::find(dirsToKeep.begin(), dirsToKeep.end(), dirName) != dirsToKeep.end()) {
603 continue;
604 }
605 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
606 continue;
607 }
608 filePath = OHOS::IncludeTrailingPathDelimiter(dataPath) + std::string(ptr->d_name);
609 if (ptr->d_type == DT_DIR) {
610 ret = OHOS::ForceRemoveDirectory(filePath);
611 } else {
612 if (access(filePath.c_str(), F_OK) == 0) {
613 ret = OHOS::RemoveFile(filePath);
614 }
615 }
616 }
617 closedir(dir);
618 return ret;
619 }
620
MkOwnerDir(const std::string & path,bool isReadByOthers,const int uid,const int gid)621 bool InstalldOperator::MkOwnerDir(const std::string &path, bool isReadByOthers, const int uid, const int gid)
622 {
623 if (!MkRecursiveDir(path, isReadByOthers)) {
624 return false;
625 }
626 return ChangeFileAttr(path, uid, gid);
627 }
628
CheckPathIsSame(const std::string & path,int32_t mode,const int32_t uid,const int32_t gid,bool & isPathExist)629 bool InstalldOperator::CheckPathIsSame(const std::string &path, int32_t mode, const int32_t uid, const int32_t gid,
630 bool &isPathExist)
631 {
632 struct stat s;
633 if (stat(path.c_str(), &s) != 0) {
634 APP_LOGD("path :%{public}s is not exist, need create", path.c_str());
635 isPathExist = false;
636 return false;
637 }
638 isPathExist = true;
639 if (((s.st_mode & MODE_BASE) == mode) && (static_cast<int32_t>(s.st_uid) == uid)
640 && (static_cast<int32_t>(s.st_gid) == gid)) {
641 APP_LOGD("path :%{public}s mode uid and gid are same, no need to create again", path.c_str());
642 return true;
643 }
644 APP_LOGW("path:%{public}s exist, but mode uid or gid are not same, need to create again", path.c_str());
645 return false;
646 }
647
MkOwnerDir(const std::string & path,int mode,const int uid,const int gid)648 bool InstalldOperator::MkOwnerDir(const std::string &path, int mode, const int uid, const int gid)
649 {
650 bool isPathExist = false;
651 if (CheckPathIsSame(path, mode, uid, gid, isPathExist)) {
652 return true;
653 }
654 if (isPathExist) {
655 if (chown(path.c_str(), INSTALLS_UID, INSTALLS_UID) != 0) {
656 APP_LOGW("fail to change %{public}s ownership, errno:%{public}d", path.c_str(), errno);
657 }
658 }
659 if (!OHOS::ForceCreateDirectory(path)) {
660 APP_LOGE("mkdir failed, errno: %{public}d", errno);
661 return false;
662 }
663 // only modify parent dir mode
664 if (chmod(path.c_str(), mode) != 0) {
665 APP_LOGE("chmod path:%{public}s mode:%{public}d failed, errno:%{public}d", path.c_str(), mode, errno);
666 return false;
667 }
668 return ChangeDirOwnerRecursively(path, uid, gid);
669 }
670
GetDiskUsage(const std::string & dir,bool isRealPath)671 int64_t InstalldOperator::GetDiskUsage(const std::string &dir, bool isRealPath)
672 {
673 if (dir.empty() || (dir.size() > Constants::PATH_MAX_SIZE)) {
674 APP_LOGE("GetDiskUsage dir path invalid");
675 return 0;
676 }
677 std::string filePath = dir;
678 if (!isRealPath && !PathToRealPath(dir, filePath)) {
679 APP_LOGE("file is not real path, file path: %{public}s", dir.c_str());
680 return 0;
681 }
682 DIR *dirPtr = opendir(filePath.c_str());
683 if (dirPtr == nullptr) {
684 APP_LOGE("GetDiskUsage open file dir:%{public}s is failure", filePath.c_str());
685 return 0;
686 }
687 if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
688 filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
689 }
690 struct dirent *entry = nullptr;
691 int64_t size = 0;
692 while ((entry = readdir(dirPtr)) != nullptr) {
693 if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
694 continue;
695 }
696 std::string path = filePath + entry->d_name;
697 if (entry->d_type == DT_DIR) {
698 size += GetDiskUsage(path, true);
699 continue;
700 }
701 struct stat fileInfo = {0};
702 if (stat(path.c_str(), &fileInfo) != 0) {
703 APP_LOGE("call stat error %{public}s", path.c_str());
704 fileInfo.st_size = 0;
705 }
706 size += fileInfo.st_size;
707 }
708 closedir(dirPtr);
709 return size;
710 }
711
TraverseCacheDirectory(const std::string & currentPath,std::vector<std::string> & cacheDirs)712 void InstalldOperator::TraverseCacheDirectory(const std::string ¤tPath, std::vector<std::string> &cacheDirs)
713 {
714 if (currentPath.empty() || (currentPath.size() > Constants::PATH_MAX_SIZE)) {
715 APP_LOGE("TraverseCacheDirectory current path invaild");
716 return;
717 }
718 std::string filePath = "";
719 if (!PathToRealPath(currentPath, filePath)) {
720 APP_LOGE("file is not real path, file path: %{public}s", currentPath.c_str());
721 return;
722 }
723 DIR* dir = opendir(filePath.c_str());
724 if (dir == nullptr) {
725 return;
726 }
727 if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
728 filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
729 }
730 struct dirent *ptr = nullptr;
731 while ((ptr = readdir(dir)) != nullptr) {
732 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
733 continue;
734 }
735 if (ptr->d_type == DT_DIR && strcmp(ptr->d_name, Constants::CACHE_DIR) == 0) {
736 std::string currentDir = filePath + std::string(ptr->d_name);
737 cacheDirs.emplace_back(currentDir);
738 continue;
739 }
740 if (ptr->d_type == DT_DIR) {
741 std::string currentDir = filePath + std::string(ptr->d_name);
742 TraverseCacheDirectory(currentDir, cacheDirs);
743 }
744 }
745 closedir(dir);
746 }
747
GetDiskUsageFromPath(const std::vector<std::string> & path)748 int64_t InstalldOperator::GetDiskUsageFromPath(const std::vector<std::string> &path)
749 {
750 int64_t fileSize = 0;
751 for (auto &st : path) {
752 fileSize += GetDiskUsage(st);
753 }
754 return fileSize;
755 }
756
InitialiseQuotaMounts()757 bool InstalldOperator::InitialiseQuotaMounts()
758 {
759 mQuotaReverseMounts.clear();
760 std::ifstream mountsFile(PROC_MOUNTS_PATH);
761
762 if (!mountsFile.is_open()) {
763 APP_LOGE("Failed to open mounts file");
764 return false;
765 }
766 std::string line;
767
768 while (std::getline(mountsFile, line)) {
769 std::string device;
770 std::string mountPoint;
771 std::string fsType;
772 std::istringstream lineStream(line);
773
774 if (!(lineStream >> device >> mountPoint >> fsType)) {
775 APP_LOGW("Failed to parse mounts file line: %{public}s", line.c_str());
776 continue;
777 }
778
779 if (mountPoint == QUOTA_DEVICE_DATA_PATH) {
780 struct dqblk dq;
781 if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), 0, reinterpret_cast<char*>(&dq)) == 0) {
782 mQuotaReverseMounts[mountPoint] = device;
783 APP_LOGD("InitialiseQuotaMounts, mountPoint: %{public}s, device: %{public}s", mountPoint.c_str(),
784 device.c_str());
785 } else {
786 APP_LOGW("InitialiseQuotaMounts, Failed to get quotactl, errno: %{public}d", errno);
787 }
788 }
789 }
790 return true;
791 }
792
GetDiskUsageFromQuota(const int32_t uid)793 int64_t InstalldOperator::GetDiskUsageFromQuota(const int32_t uid)
794 {
795 std::lock_guard<std::recursive_mutex> lock(mMountsLock);
796 std::string device = "";
797 if (mQuotaReverseMounts.find(QUOTA_DEVICE_DATA_PATH) == mQuotaReverseMounts.end()) {
798 if (!InitialiseQuotaMounts()) {
799 APP_LOGE("Failed to initialise quota mounts");
800 return 0;
801 }
802 }
803 device = mQuotaReverseMounts[QUOTA_DEVICE_DATA_PATH];
804 if (device.empty()) {
805 APP_LOGW("skip when device no quotas present");
806 return 0;
807 }
808 struct dqblk dq;
809 if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) {
810 APP_LOGE("Failed to get quotactl, errno: %{public}d", errno);
811 return 0;
812 }
813 APP_LOGD("get disk usage from quota, uid: %{public}d, usage: %{public}llu", uid, dq.dqb_curspace);
814 return dq.dqb_curspace;
815 }
816
ScanDir(const std::string & dirPath,ScanMode scanMode,ResultMode resultMode,std::vector<std::string> & paths)817 bool InstalldOperator::ScanDir(
818 const std::string &dirPath, ScanMode scanMode, ResultMode resultMode, std::vector<std::string> &paths)
819 {
820 if (dirPath.empty() || (dirPath.size() > Constants::PATH_MAX_SIZE)) {
821 APP_LOGE("Scan dir path invaild");
822 return false;
823 }
824
825 std::string realPath = "";
826 if (!PathToRealPath(dirPath, realPath)) {
827 APP_LOGE("file(%{public}s) is not real path", dirPath.c_str());
828 return false;
829 }
830
831 DIR* dir = opendir(realPath.c_str());
832 if (dir == nullptr) {
833 APP_LOGE("Scan open dir(%{public}s) fail", realPath.c_str());
834 return false;
835 }
836
837 struct dirent *ptr = nullptr;
838 while ((ptr = readdir(dir)) != nullptr) {
839 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
840 continue;
841 }
842
843 std::string subName(ptr->d_name);
844 if (scanMode == ScanMode::SUB_FILE_DIR) {
845 if (ptr->d_type == DT_DIR) {
846 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
847 }
848
849 continue;
850 }
851
852 if (scanMode == ScanMode::SUB_FILE_FILE) {
853 if (ptr->d_type == DT_REG) {
854 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
855 }
856
857 continue;
858 }
859
860 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
861 }
862
863 closedir(dir);
864 return true;
865 }
866
ScanSoFiles(const std::string & newSoPath,const std::string & originPath,const std::string & currentPath,std::vector<std::string> & paths)867 bool InstalldOperator::ScanSoFiles(const std::string &newSoPath, const std::string &originPath,
868 const std::string ¤tPath, std::vector<std::string> &paths)
869 {
870 if (currentPath.empty() || (currentPath.size() > Constants::PATH_MAX_SIZE)) {
871 APP_LOGE("ScanSoFiles current path invalid");
872 return false;
873 }
874 std::string filePath = "";
875 if (!PathToRealPath(currentPath, filePath)) {
876 APP_LOGE("file is not real path, file path: %{public}s", currentPath.c_str());
877 return false;
878 }
879 DIR* dir = opendir(filePath.c_str());
880 if (dir == nullptr) {
881 APP_LOGE("ScanSoFiles open dir(%{public}s) fail", filePath.c_str());
882 return false;
883 }
884 if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
885 filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
886 }
887 struct dirent *ptr = nullptr;
888 while ((ptr = readdir(dir)) != nullptr) {
889 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
890 continue;
891 }
892 if (ptr->d_type == DT_DIR) {
893 std::string currentDir = filePath + std::string(ptr->d_name);
894 if (!ScanSoFiles(newSoPath, originPath, currentDir, paths)) {
895 closedir(dir);
896 return false;
897 }
898 }
899 if (ptr->d_type == DT_REG) {
900 std::string currentFile = filePath + std::string(ptr->d_name);
901 std::string prefixPath = originPath;
902 if (prefixPath.back() != Constants::FILE_SEPARATOR_CHAR) {
903 prefixPath.push_back(Constants::FILE_SEPARATOR_CHAR);
904 }
905 std::string relativePath = currentFile.substr(prefixPath.size());
906 paths.emplace_back(relativePath);
907 std::string subNewSoPath = GetPathDir(newSoPath + Constants::PATH_SEPARATOR + relativePath);
908 if (!IsExistDir(subNewSoPath) && !MkRecursiveDir(subNewSoPath, true)) {
909 APP_LOGE("ScanSoFiles create subNewSoPath (%{public}s) failed", filePath.c_str());
910 closedir(dir);
911 return false;
912 }
913 }
914 }
915 closedir(dir);
916 return true;
917 }
918
CopyFile(const std::string & sourceFile,const std::string & destinationFile)919 bool InstalldOperator::CopyFile(
920 const std::string &sourceFile, const std::string &destinationFile)
921 {
922 if (sourceFile.empty() || destinationFile.empty()) {
923 APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
924 return false;
925 }
926
927 std::ifstream in(sourceFile);
928 if (!in.is_open()) {
929 APP_LOGE("Copy file failed due to open sourceFile failed");
930 return false;
931 }
932
933 std::ofstream out(destinationFile);
934 if (!out.is_open()) {
935 APP_LOGE("Copy file failed due to open destinationFile failed");
936 in.close();
937 return false;
938 }
939
940 out << in.rdbuf();
941 in.close();
942 out.close();
943 return true;
944 }
945
CopyFileFast(const std::string & sourcePath,const std::string & destPath)946 bool InstalldOperator::CopyFileFast(const std::string &sourcePath, const std::string &destPath)
947 {
948 APP_LOGD("begin");
949 return BundleUtil::CopyFileFast(sourcePath, destPath);
950 }
951
ExtractDiffFiles(const std::string & filePath,const std::string & targetPath,const std::string & cpuAbi)952 bool InstalldOperator::ExtractDiffFiles(const std::string &filePath, const std::string &targetPath,
953 const std::string &cpuAbi)
954 {
955 BundleExtractor extractor(filePath);
956 if (!extractor.Init()) {
957 return false;
958 }
959 std::vector<std::string> entryNames;
960 if (!extractor.GetZipFileNames(entryNames)) {
961 return false;
962 }
963 for (const auto &entryName : entryNames) {
964 if (strcmp(entryName.c_str(), ".") == 0 ||
965 strcmp(entryName.c_str(), "..") == 0) {
966 continue;
967 }
968 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
969 continue;
970 }
971 // handle diff file
972 if (IsDiffFiles(entryName, targetPath, cpuAbi)) {
973 ExtractTargetFile(extractor, entryName, targetPath, cpuAbi);
974 }
975 }
976 return true;
977 }
978
OpenHandle(void ** handle)979 bool InstalldOperator::OpenHandle(void **handle)
980 {
981 APP_LOGI("InstalldOperator::OpenHandle start");
982 if (handle == nullptr) {
983 APP_LOGE("InstalldOperator::OpenHandle error handle is nullptr.");
984 return false;
985 }
986 *handle = dlopen(LIB64_DIFF_PATCH_SHARED_SO_PATH, RTLD_NOW | RTLD_GLOBAL);
987 if (*handle == nullptr) {
988 APP_LOGW("ApplyDiffPatch failed to open libdiff_patch_shared.z.so, err:%{public}s", dlerror());
989 *handle = dlopen(LIB_DIFF_PATCH_SHARED_SO_PATH, RTLD_NOW | RTLD_GLOBAL);
990 }
991 if (*handle == nullptr) {
992 APP_LOGE("ApplyDiffPatch failed to open libdiff_patch_shared.z.so, err:%{public}s", dlerror());
993 return false;
994 }
995 APP_LOGI("InstalldOperator::OpenHandle end");
996 return true;
997 }
998
CloseHandle(void ** handle)999 void InstalldOperator::CloseHandle(void **handle)
1000 {
1001 APP_LOGI("InstalldOperator::CloseHandle start");
1002 if ((handle != nullptr) && (*handle != nullptr)) {
1003 dlclose(*handle);
1004 *handle = nullptr;
1005 APP_LOGD("InstalldOperator::CloseHandle, err:%{public}s", dlerror());
1006 }
1007 APP_LOGI("InstalldOperator::CloseHandle end");
1008 }
1009
ProcessApplyDiffPatchPath(const std::string & oldSoPath,const std::string & diffFilePath,const std::string & newSoPath,std::vector<std::string> & oldSoFileNames,std::vector<std::string> & diffFileNames)1010 bool InstalldOperator::ProcessApplyDiffPatchPath(
1011 const std::string &oldSoPath, const std::string &diffFilePath,
1012 const std::string &newSoPath, std::vector<std::string> &oldSoFileNames, std::vector<std::string> &diffFileNames)
1013 {
1014 APP_LOGI("ProcessApplyDiffPatchPath oldSoPath: %{public}s, diffFilePath: %{public}s, newSoPath: %{public}s",
1015 oldSoPath.c_str(), diffFilePath.c_str(), newSoPath.c_str());
1016 if (oldSoPath.empty() || diffFilePath.empty() || newSoPath.empty()) {
1017 return false;
1018 }
1019 if (!IsExistDir(oldSoPath) || !IsExistDir(diffFilePath)) {
1020 APP_LOGE("ProcessApplyDiffPatchPath oldSoPath or diffFilePath not exist");
1021 return false;
1022 }
1023
1024 if (!ScanSoFiles(newSoPath, oldSoPath, oldSoPath, oldSoFileNames)) {
1025 APP_LOGE("ProcessApplyDiffPatchPath ScanSoFiles oldSoPath failed");
1026 return false;
1027 }
1028
1029 if (!ScanSoFiles(newSoPath, diffFilePath, diffFilePath, diffFileNames)) {
1030 APP_LOGE("ProcessApplyDiffPatchPath ScanSoFiles diffFilePath failed");
1031 return false;
1032 }
1033
1034 if (oldSoFileNames.empty() || diffFileNames.empty()) {
1035 APP_LOGE("ProcessApplyDiffPatchPath so or diff files empty");
1036 return false;
1037 }
1038
1039 if (!IsExistDir(newSoPath)) {
1040 APP_LOGD("ProcessApplyDiffPatchPath create newSoPath");
1041 if (!MkRecursiveDir(newSoPath, true)) {
1042 APP_LOGE("ProcessApplyDiffPatchPath create newSo dir (%{public}s) failed", newSoPath.c_str());
1043 return false;
1044 }
1045 }
1046 APP_LOGI("ProcessApplyDiffPatchPath end");
1047 return true;
1048 }
1049
ApplyDiffPatch(const std::string & oldSoPath,const std::string & diffFilePath,const std::string & newSoPath,int32_t uid)1050 bool InstalldOperator::ApplyDiffPatch(const std::string &oldSoPath, const std::string &diffFilePath,
1051 const std::string &newSoPath, int32_t uid)
1052 {
1053 APP_LOGI("ApplyDiffPatch start");
1054 std::vector<std::string> oldSoFileNames;
1055 std::vector<std::string> diffFileNames;
1056 if (InstalldOperator::IsDirEmpty(oldSoPath) || InstalldOperator::IsDirEmpty(diffFilePath)) {
1057 APP_LOGD("oldSoPath or diffFilePath is empty, not require ApplyPatch");
1058 return true;
1059 }
1060 if (!ProcessApplyDiffPatchPath(oldSoPath, diffFilePath, newSoPath, oldSoFileNames, diffFileNames)) {
1061 APP_LOGE("ApplyDiffPatch ProcessApplyDiffPatchPath failed");
1062 return false;
1063 }
1064 std::string realOldSoPath;
1065 std::string realDiffFilePath;
1066 std::string realNewSoPath;
1067 if (!PathToRealPath(oldSoPath, realOldSoPath) || !PathToRealPath(diffFilePath, realDiffFilePath) ||
1068 !PathToRealPath(newSoPath, realNewSoPath)) {
1069 APP_LOGE("ApplyDiffPatch Path is not real path");
1070 return false;
1071 }
1072 void *handle = nullptr;
1073 if (!OpenHandle(&handle)) {
1074 return false;
1075 }
1076 auto applyPatch = reinterpret_cast<ApplyPatch>(dlsym(handle, APPLY_PATCH_FUNCTION_NAME));
1077 if (applyPatch == nullptr) {
1078 APP_LOGE("ApplyDiffPatch failed to get applyPatch err:%{public}s", dlerror());
1079 CloseHandle(&handle);
1080 return false;
1081 }
1082 std::vector<std::string> newSoList;
1083 for (const auto &diffFileName : diffFileNames) {
1084 std::string soFileName = diffFileName.substr(0, diffFileName.rfind(Constants::DIFF_SUFFIX));
1085 APP_LOGD("ApplyDiffPatch soName: %{public}s, diffName: %{public}s", soFileName.c_str(), diffFileName.c_str());
1086 if (find(oldSoFileNames.begin(), oldSoFileNames.end(), soFileName) != oldSoFileNames.end()) {
1087 int32_t ret = applyPatch(realDiffFilePath + Constants::PATH_SEPARATOR + diffFileName,
1088 realOldSoPath + Constants::PATH_SEPARATOR + soFileName,
1089 realNewSoPath + Constants::PATH_SEPARATOR + soFileName);
1090 if (ret != ERR_OK) {
1091 APP_LOGE("ApplyDiffPatch failed, applyPatch errcode: %{public}d", ret);
1092 for (const auto &file : newSoList) {
1093 DeleteDir(file);
1094 }
1095 CloseHandle(&handle);
1096 return false;
1097 }
1098 newSoList.emplace_back(realNewSoPath + Constants::PATH_SEPARATOR + soFileName);
1099 }
1100 }
1101 CloseHandle(&handle);
1102 #if defined(CODE_ENCRYPTION_ENABLE)
1103 RemoveEncryptedKey(uid, newSoList);
1104 #endif
1105 APP_LOGI("ApplyDiffPatch end");
1106 return true;
1107 }
1108
ObtainQuickFixFileDir(const std::string & dir,std::vector<std::string> & fileVec)1109 bool InstalldOperator::ObtainQuickFixFileDir(const std::string &dir, std::vector<std::string> &fileVec)
1110 {
1111 if (dir.empty()) {
1112 APP_LOGE("ObtainQuickFixFileDir dir path invaild");
1113 return false;
1114 }
1115
1116 std::string realPath = "";
1117 if (!PathToRealPath(dir, realPath)) {
1118 APP_LOGE("dir(%{public}s) is not real path", dir.c_str());
1119 return false;
1120 }
1121
1122 DIR* directory = opendir(realPath.c_str());
1123 if (directory == nullptr) {
1124 APP_LOGE("ObtainQuickFixFileDir open dir(%{public}s) fail", realPath.c_str());
1125 return false;
1126 }
1127
1128 struct dirent *ptr = nullptr;
1129 while ((ptr = readdir(directory)) != nullptr) {
1130 std::string currentName(ptr->d_name);
1131 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
1132 continue;
1133 }
1134
1135 std::string curPath = dir + Constants::PATH_SEPARATOR + currentName;
1136 struct stat s;
1137 if (stat(curPath.c_str(), &s) == 0) {
1138 // directory
1139 if (s.st_mode & S_IFDIR) {
1140 ObtainQuickFixFileDir(curPath, fileVec);
1141 }
1142
1143 // file
1144 if ((s.st_mode & S_IFREG) &&
1145 (currentName.find(Constants::QUICK_FIX_FILE_SUFFIX) != std::string::npos)) {
1146 fileVec.emplace_back(dir);
1147 }
1148 }
1149 }
1150 closedir(directory);
1151 return true;
1152 }
1153
CopyFiles(const std::string & sourceDir,const std::string & destinationDir)1154 bool InstalldOperator::CopyFiles(const std::string &sourceDir, const std::string &destinationDir)
1155 {
1156 APP_LOGD("sourceDir is %{public}s, destinationDir is %{public}s", sourceDir.c_str(), destinationDir.c_str());
1157 if (sourceDir.empty() || destinationDir.empty()) {
1158 APP_LOGE("Copy file failed due to sourceDir or destinationDir is empty");
1159 return false;
1160 }
1161
1162 std::string realPath = "";
1163 if (!PathToRealPath(sourceDir, realPath)) {
1164 APP_LOGE("sourceDir(%{public}s) is not real path", sourceDir.c_str());
1165 return false;
1166 }
1167
1168 DIR* directory = opendir(realPath.c_str());
1169 if (directory == nullptr) {
1170 APP_LOGE("CopyFiles open dir(%{public}s) fail", realPath.c_str());
1171 return false;
1172 }
1173
1174 struct dirent *ptr = nullptr;
1175 while ((ptr = readdir(directory)) != nullptr) {
1176 std::string currentName(ptr->d_name);
1177 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
1178 continue;
1179 }
1180
1181 std::string curPath = sourceDir + Constants::PATH_SEPARATOR + currentName;
1182 struct stat s;
1183 if ((stat(curPath.c_str(), &s) == 0) && (s.st_mode & S_IFREG)) {
1184 std::string innerDesStr = destinationDir + Constants::PATH_SEPARATOR + currentName;
1185 if (CopyFile(curPath, innerDesStr)) {
1186 ChangeFileAttr(innerDesStr, Constants::FOUNDATION_UID, Constants::BMS_GID);
1187 }
1188 }
1189 }
1190 closedir(directory);
1191 return true;
1192 }
1193
GetNativeLibraryFileNames(const std::string & filePath,const std::string & cpuAbi,std::vector<std::string> & fileNames)1194 bool InstalldOperator::GetNativeLibraryFileNames(const std::string &filePath, const std::string &cpuAbi,
1195 std::vector<std::string> &fileNames)
1196 {
1197 BundleExtractor extractor(filePath);
1198 if (!extractor.Init()) {
1199 return false;
1200 }
1201 std::vector<std::string> entryNames;
1202 if (!extractor.GetZipFileNames(entryNames)) {
1203 return false;
1204 }
1205 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
1206 for (const auto &entryName : entryNames) {
1207 if (StartsWith(entryName, prefix) && EndsWith(entryName, Constants::SO_SUFFIX)) {
1208 fileNames.push_back(entryName.substr(prefix.length(), entryName.length()));
1209 }
1210 }
1211 APP_LOGD("InstalldOperator::GetNativeLibraryFileNames end");
1212 return true;
1213 }
1214
1215 #if defined(CODE_SIGNATURE_ENABLE)
PrepareEntryMap(const CodeSignatureParam & codeSignatureParam,const std::vector<std::string> & soEntryFiles,Security::CodeSign::EntryMap & entryMap)1216 bool InstalldOperator::PrepareEntryMap(const CodeSignatureParam &codeSignatureParam,
1217 const std::vector<std::string> &soEntryFiles, Security::CodeSign::EntryMap &entryMap)
1218 {
1219 if (codeSignatureParam.targetSoPath.empty()) {
1220 return false;
1221 }
1222 const std::string prefix = Constants::LIBS + codeSignatureParam.cpuAbi + Constants::PATH_SEPARATOR;
1223 for_each(soEntryFiles.begin(), soEntryFiles.end(),
1224 [&entryMap, &prefix, &codeSignatureParam](const auto &entry) {
1225 std::string fileName = entry.substr(prefix.length());
1226 std::string path = codeSignatureParam.targetSoPath;
1227 if (path.back() != Constants::FILE_SEPARATOR_CHAR) {
1228 path += Constants::FILE_SEPARATOR_CHAR;
1229 }
1230 entryMap.emplace(entry, path + fileName);
1231 APP_LOGD("VerifyCode the targetSoPath is %{public}s", (path + fileName).c_str());
1232 });
1233 return true;
1234 }
1235
PerformCodeSignatureCheck(const CodeSignatureParam & codeSignatureParam,const Security::CodeSign::EntryMap & entryMap)1236 ErrCode InstalldOperator::PerformCodeSignatureCheck(const CodeSignatureParam &codeSignatureParam,
1237 const Security::CodeSign::EntryMap &entryMap)
1238 {
1239 ErrCode ret = ERR_OK;
1240 if (codeSignatureParam.isCompileSdkOpenHarmony &&
1241 !Security::CodeSign::CodeSignUtils::IsSupportOHCodeSign()) {
1242 APP_LOGD("code signature is not supported");
1243 return ret;
1244 }
1245 if (codeSignatureParam.signatureFileDir.empty()) {
1246 std::shared_ptr<CodeSignHelper> codeSignHelper = std::make_shared<CodeSignHelper>();
1247 Security::CodeSign::FileType fileType = codeSignatureParam.isPreInstalledBundle ?
1248 FILE_ENTRY_ONLY : FILE_ENTRY_ADD;
1249 if (codeSignatureParam.isEnterpriseBundle) {
1250 APP_LOGD("Verify code signature for enterprise bundle");
1251 ret = codeSignHelper->EnforceCodeSignForAppWithOwnerId(codeSignatureParam.appIdentifier,
1252 codeSignatureParam.modulePath, entryMap, fileType);
1253 } else {
1254 APP_LOGD("Verify code signature for non-enterprise bundle");
1255 ret = codeSignHelper->EnforceCodeSignForApp(codeSignatureParam.modulePath, entryMap, fileType);
1256 }
1257 APP_LOGI("Verify code signature for hap %{public}s", codeSignatureParam.modulePath.c_str());
1258 } else {
1259 ret = CodeSignUtils::EnforceCodeSignForApp(entryMap, codeSignatureParam.signatureFileDir);
1260 }
1261 return ret;
1262 }
1263 #endif
1264
VerifyCodeSignature(const CodeSignatureParam & codeSignatureParam)1265 bool InstalldOperator::VerifyCodeSignature(const CodeSignatureParam &codeSignatureParam)
1266 {
1267 BundleExtractor extractor(codeSignatureParam.modulePath);
1268 if (!extractor.Init()) {
1269 return false;
1270 }
1271
1272 std::vector<std::string> soEntryFiles;
1273 if (!ObtainNativeSoFile(extractor, codeSignatureParam.cpuAbi, soEntryFiles)) {
1274 return false;
1275 }
1276
1277 if (soEntryFiles.empty()) {
1278 return true;
1279 }
1280
1281 #if defined(CODE_SIGNATURE_ENABLE)
1282 Security::CodeSign::EntryMap entryMap;
1283 if (!PrepareEntryMap(codeSignatureParam, soEntryFiles, entryMap)) {
1284 return false;
1285 }
1286
1287 ErrCode ret = PerformCodeSignatureCheck(codeSignatureParam, entryMap);
1288 if (ret == VerifyErrCode::CS_CODE_SIGN_NOT_EXISTS) {
1289 APP_LOGW("no code sign file in the bundle");
1290 return true;
1291 }
1292 if (ret != ERR_OK) {
1293 APP_LOGE("VerifyCode failed due to %{public}d", ret);
1294 return false;
1295 }
1296 #endif
1297 return true;
1298 }
1299
CheckEncryption(const CheckEncryptionParam & checkEncryptionParam,bool & isEncryption)1300 bool InstalldOperator::CheckEncryption(const CheckEncryptionParam &checkEncryptionParam, bool &isEncryption)
1301 {
1302 APP_LOGD("process check encryption of src path %{public}s", checkEncryptionParam.modulePath.c_str());
1303 if (checkEncryptionParam.cpuAbi.empty() && checkEncryptionParam.targetSoPath.empty()) {
1304 return CheckHapEncryption(checkEncryptionParam, isEncryption);
1305 }
1306 const std::string cpuAbi = checkEncryptionParam.cpuAbi;
1307 const int32_t bundleId = checkEncryptionParam.bundleId;
1308 InstallBundleType installBundleType = checkEncryptionParam.installBundleType;
1309 const bool isCompressNativeLibrary = checkEncryptionParam.isCompressNativeLibrary;
1310 APP_LOGD("CheckEncryption: bundleId %{public}d, installBundleType %{public}d, isCompressNativeLibrary %{public}d",
1311 bundleId, installBundleType, isCompressNativeLibrary);
1312
1313 BundleExtractor extractor(checkEncryptionParam.modulePath);
1314 if (!extractor.Init()) {
1315 return false;
1316 }
1317
1318 std::vector<std::string> soEntryFiles;
1319 if (!ObtainNativeSoFile(extractor, cpuAbi, soEntryFiles)) {
1320 APP_LOGE("ObtainNativeSoFile failed");
1321 return false;
1322 }
1323
1324 if (soEntryFiles.empty()) {
1325 APP_LOGD("no so file in installation file %{public}s", checkEncryptionParam.modulePath.c_str());
1326 return true;
1327 }
1328
1329 #if defined(CODE_ENCRYPTION_ENABLE)
1330 const std::string targetSoPath = checkEncryptionParam.targetSoPath;
1331 Security::CodeCrypto::EntryMap entryMap;
1332 entryMap.emplace(Constants::CODE_SIGNATURE_HAP, checkEncryptionParam.modulePath);
1333 if (!targetSoPath.empty()) {
1334 const std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
1335 std::for_each(soEntryFiles.begin(), soEntryFiles.end(), [&entryMap, &prefix, &targetSoPath](const auto &entry) {
1336 std::string fileName = entry.substr(prefix.length());
1337 std::string path = targetSoPath;
1338 if (path.back() != Constants::FILE_SEPARATOR_CHAR) {
1339 path += Constants::FILE_SEPARATOR_CHAR;
1340 }
1341 entryMap.emplace(entry, path + fileName);
1342 APP_LOGD("CheckEncryption the targetSoPath is %{public}s", (path + fileName).c_str());
1343 });
1344 }
1345 ErrCode ret = Security::CodeCrypto::CodeCryptoUtils::EnforceMetadataProcessForApp(entryMap, bundleId,
1346 isEncryption, static_cast<Security::CodeCrypto::CodeCryptoUtils::InstallBundleType>(installBundleType),
1347 isCompressNativeLibrary);
1348 if (ret != ERR_OK) {
1349 APP_LOGE("CheckEncryption failed due to %{public}d", ret);
1350 return false;
1351 }
1352 #endif
1353 return true;
1354 }
1355
CheckHapEncryption(const CheckEncryptionParam & checkEncryptionParam,bool & isEncryption)1356 bool InstalldOperator::CheckHapEncryption(const CheckEncryptionParam &checkEncryptionParam, bool &isEncryption)
1357 {
1358 const std::string hapPath = checkEncryptionParam.modulePath;
1359 const int32_t bundleId = checkEncryptionParam.bundleId;
1360 InstallBundleType installBundleType = checkEncryptionParam.installBundleType;
1361 const bool isCompressNativeLibrary = checkEncryptionParam.isCompressNativeLibrary;
1362 APP_LOGD("CheckHapEncryption the hapPath is %{public}s, installBundleType is %{public}d, "
1363 "bundleId is %{public}d, isCompressNativeLibrary is %{public}d", hapPath.c_str(),
1364 installBundleType, bundleId, isCompressNativeLibrary);
1365 #if defined(CODE_ENCRYPTION_ENABLE)
1366 Security::CodeCrypto::EntryMap entryMap;
1367 entryMap.emplace(Constants::CODE_SIGNATURE_HAP, hapPath);
1368 ErrCode ret = Security::CodeCrypto::CodeCryptoUtils::EnforceMetadataProcessForApp(entryMap, bundleId,
1369 isEncryption, static_cast<Security::CodeCrypto::CodeCryptoUtils::InstallBundleType>(installBundleType),
1370 isCompressNativeLibrary);
1371 if (ret != ERR_OK) {
1372 APP_LOGE("CheckEncryption failed due to %{public}d", ret);
1373 return false;
1374 }
1375 #endif
1376 return true;
1377 }
1378
ObtainNativeSoFile(const BundleExtractor & extractor,const std::string & cpuAbi,std::vector<std::string> & soEntryFiles)1379 bool InstalldOperator::ObtainNativeSoFile(const BundleExtractor &extractor, const std::string &cpuAbi,
1380 std::vector<std::string> &soEntryFiles)
1381 {
1382 std::vector<std::string> entryNames;
1383 if (!extractor.GetZipFileNames(entryNames)) {
1384 APP_LOGE("GetZipFileNames failed");
1385 return false;
1386 }
1387 if (entryNames.empty()) {
1388 APP_LOGE("entryNames is empty");
1389 return false;
1390 }
1391
1392 for (const auto &entryName : entryNames) {
1393 if (strcmp(entryName.c_str(), ".") == 0 ||
1394 strcmp(entryName.c_str(), "..") == 0) {
1395 continue;
1396 }
1397 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
1398 continue;
1399 }
1400 // save native so file entryName in the hap
1401 if (IsNativeSo(entryName, cpuAbi)) {
1402 soEntryFiles.emplace_back(entryName);
1403 continue;
1404 }
1405 }
1406
1407 if (soEntryFiles.empty()) {
1408 APP_LOGD("no so file in installation file");
1409 }
1410 return true;
1411 }
1412
MoveFiles(const std::string & srcDir,const std::string & desDir,bool isDesDirNeedCreated)1413 bool InstalldOperator::MoveFiles(const std::string &srcDir, const std::string &desDir, bool isDesDirNeedCreated)
1414 {
1415 APP_LOGD("srcDir is %{public}s, desDir is %{public}s", srcDir.c_str(), desDir.c_str());
1416 if (isDesDirNeedCreated && !MkRecursiveDir(desDir, true)) {
1417 APP_LOGE("create desDir failed");
1418 return false;
1419 }
1420
1421 if (srcDir.empty() || desDir.empty()) {
1422 APP_LOGE("move file failed due to srcDir or desDir is empty");
1423 return false;
1424 }
1425
1426 std::string realPath = "";
1427 if (!PathToRealPath(srcDir, realPath)) {
1428 APP_LOGE("srcDir(%{public}s) is not real path", srcDir.c_str());
1429 return false;
1430 }
1431
1432 std::string realDesDir = "";
1433 if (!PathToRealPath(desDir, realDesDir)) {
1434 APP_LOGE("desDir(%{public}s) is not real path", desDir.c_str());
1435 return false;
1436 }
1437
1438 DIR* directory = opendir(realPath.c_str());
1439 if (directory == nullptr) {
1440 APP_LOGE("MoveFiles open dir(%{public}s) fail", realPath.c_str());
1441 return false;
1442 }
1443
1444 struct dirent *ptr = nullptr;
1445 while ((ptr = readdir(directory)) != nullptr) {
1446 std::string currentName(ptr->d_name);
1447 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
1448 continue;
1449 }
1450
1451 std::string curPath = realPath + Constants::PATH_SEPARATOR + currentName;
1452 std::string innerDesStr = realDesDir + Constants::PATH_SEPARATOR + currentName;
1453 struct stat s;
1454 if (stat(curPath.c_str(), &s) != 0) {
1455 APP_LOGD("MoveFiles stat %{public}s failed", curPath.c_str());
1456 continue;
1457 }
1458 if (!MoveFileOrDir(curPath, innerDesStr, s.st_mode)) {
1459 closedir(directory);
1460 return false;
1461 }
1462 }
1463 closedir(directory);
1464 return true;
1465 }
1466
MoveFileOrDir(const std::string & srcPath,const std::string & destPath,mode_t mode)1467 bool InstalldOperator::MoveFileOrDir(const std::string &srcPath, const std::string &destPath, mode_t mode)
1468 {
1469 if (mode & S_IFREG) {
1470 APP_LOGD("srcPath(%{public}s) is a file", srcPath.c_str());
1471 return MoveFile(srcPath, destPath);
1472 } else if (mode & S_IFDIR) {
1473 APP_LOGD("srcPath(%{public}s) is a dir", srcPath.c_str());
1474 return MoveFiles(srcPath, destPath, true);
1475 }
1476 return true;
1477 }
1478
MoveFile(const std::string & srcPath,const std::string & destPath)1479 bool InstalldOperator::MoveFile(const std::string &srcPath, const std::string &destPath)
1480 {
1481 APP_LOGD("srcPath is %{public}s, destPath is %{public}s", srcPath.c_str(), destPath.c_str());
1482 if (!RenameFile(srcPath, destPath)) {
1483 APP_LOGE("move file from srcPath(%{public}s) to destPath(%{public}s) failed", srcPath.c_str(),
1484 destPath.c_str());
1485 return false;
1486 }
1487 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1488 if (!OHOS::ChangeModeFile(destPath, mode)) {
1489 APP_LOGE("change mode failed");
1490 return false;
1491 }
1492 return true;
1493 }
1494
ExtractResourceFiles(const ExtractParam & extractParam,const BundleExtractor & extractor)1495 bool InstalldOperator::ExtractResourceFiles(const ExtractParam &extractParam, const BundleExtractor &extractor)
1496 {
1497 APP_LOGD("ExtractResourceFiles begin");
1498 std::string targetDir = extractParam.targetPath;
1499 if (!MkRecursiveDir(targetDir, true)) {
1500 APP_LOGE("create targetDir failed");
1501 return false;
1502 }
1503 std::vector<std::string> entryNames;
1504 if (!extractor.GetZipFileNames(entryNames)) {
1505 APP_LOGE("GetZipFileNames failed");
1506 return false;
1507 }
1508 for (const auto &entryName : entryNames) {
1509 if (StartsWith(entryName, Constants::LIBS)
1510 || StartsWith(entryName, Constants::AN)
1511 || StartsWith(entryName, Constants::AP)) {
1512 continue;
1513 }
1514 const std::string relativeDir = GetPathDir(entryName);
1515 if (!relativeDir.empty()) {
1516 if (!MkRecursiveDir(targetDir + relativeDir, true)) {
1517 APP_LOGE("MkRecursiveDir failed");
1518 return false;
1519 }
1520 }
1521 std::string filePath = targetDir + entryName;
1522 if (!extractor.ExtractFile(entryName, filePath)) {
1523 APP_LOGE("ExtractFile failed");
1524 continue;
1525 }
1526 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1527 if (!OHOS::ChangeModeFile(filePath, mode)) {
1528 APP_LOGE("change mode failed");
1529 return false;
1530 }
1531 }
1532 APP_LOGD("ExtractResourceFiles success");
1533 return true;
1534 }
1535
ExtractDriverSoFiles(const std::string & srcPath,const std::unordered_multimap<std::string,std::string> & dirMap)1536 bool InstalldOperator::ExtractDriverSoFiles(const std::string &srcPath,
1537 const std::unordered_multimap<std::string, std::string> &dirMap)
1538 {
1539 APP_LOGD("ExtractDriverSoFiles start with src(%{public}s)", srcPath.c_str());
1540 if (srcPath.empty() || dirMap.empty()) {
1541 APP_LOGE("ExtractDriverSoFiles parameters are invalid");
1542 return false;
1543 }
1544 BundleExtractor extractor(srcPath);
1545 if (!extractor.Init()) {
1546 APP_LOGE("extractor init failed");
1547 return false;
1548 }
1549
1550 std::vector<std::string> entryNames;
1551 if (!extractor.GetZipFileNames(entryNames)) {
1552 APP_LOGE("GetZipFileNames failed");
1553 return false;
1554 }
1555
1556 for (auto &[originalDir, destinedDir] : dirMap) {
1557 if ((originalDir.compare(".") == 0) || (originalDir.compare("..") == 0)) {
1558 APP_LOGE("the originalDir %{public}s is not existed in the hap", originalDir.c_str());
1559 return false;
1560 }
1561 if (!BundleUtil::StartWith(originalDir, PREFIX_RESOURCE_PATH) ||
1562 !BundleUtil::StartWith(destinedDir, PREFIX_TARGET_PATH)) {
1563 APP_LOGE("the originalDir %{public}s and destined dir %{public}s are invalid", originalDir.c_str(),
1564 destinedDir.c_str());
1565 return false;
1566 }
1567 std::string innerOriginalDir = originalDir;
1568 if (innerOriginalDir.front() == Constants::PATH_SEPARATOR[0]) {
1569 innerOriginalDir = innerOriginalDir.substr(1);
1570 }
1571 if (find(entryNames.cbegin(), entryNames.cend(), innerOriginalDir) == entryNames.cend()) {
1572 APP_LOGE("the innerOriginalDir %{public}s is not existed in the hap", innerOriginalDir.c_str());
1573 return false;
1574 }
1575 std::string systemServiceDir = Constants::SYSTEM_SERVICE_DIR;
1576 if (!CopyDriverSoFiles(extractor, innerOriginalDir, systemServiceDir + destinedDir)) {
1577 APP_LOGE("CopyDriverSoFiles failed");
1578 return false;
1579 }
1580 }
1581 APP_LOGD("ExtractDriverSoFiles end");
1582 return true;
1583 }
1584
CopyDriverSoFiles(const BundleExtractor & extractor,const std::string & originalDir,const std::string & destinedDir)1585 bool InstalldOperator::CopyDriverSoFiles(const BundleExtractor &extractor, const std::string &originalDir,
1586 const std::string &destinedDir)
1587 {
1588 APP_LOGD("CopyDriverSoFiles beign");
1589 auto pos = destinedDir.rfind(Constants::PATH_SEPARATOR);
1590 if ((pos == std::string::npos) || (pos == destinedDir.length() -1)) {
1591 APP_LOGE("destinedDir(%{public}s) is invalid path", destinedDir.c_str());
1592 return false;
1593 }
1594 std::string desDir = destinedDir.substr(0, pos);
1595 std::string realDesDir;
1596 if (!PathToRealPath(desDir, realDesDir)) {
1597 APP_LOGE("desDir(%{public}s) is not real path", desDir.c_str());
1598 return false;
1599 }
1600 std::string realDestinedDir = realDesDir + destinedDir.substr(pos);
1601 APP_LOGD("realDestinedDir is %{public}s", realDestinedDir.c_str());
1602 if (!extractor.ExtractFile(originalDir, realDestinedDir)) {
1603 APP_LOGE("ExtractFile failed");
1604 return false;
1605 }
1606
1607 struct stat buf = {};
1608 if (stat(realDesDir.c_str(), &buf) != 0) {
1609 APP_LOGE("failed to obtain the stat status of realDesDir %{public}s", realDesDir.c_str());
1610 return false;
1611 }
1612 ChangeFileAttr(realDestinedDir, buf.st_uid, buf.st_gid);
1613 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1614 if (!OHOS::ChangeModeFile(realDestinedDir, mode)) {
1615 return false;
1616 }
1617 APP_LOGD("CopyDriverSoFiles end");
1618 return true;
1619 }
1620
1621 #if defined(CODE_ENCRYPTION_ENABLE)
ExtractSoFilesToTmpHapPath(const std::string & hapPath,const std::string & cpuAbi,const std::string & tmpSoPath,int32_t uid)1622 ErrCode InstalldOperator::ExtractSoFilesToTmpHapPath(const std::string &hapPath, const std::string &cpuAbi,
1623 const std::string &tmpSoPath, int32_t uid)
1624 {
1625 APP_LOGD("start to obtain decoded so files from hapPath %{public}s", hapPath.c_str());
1626 BundleExtractor extractor(hapPath);
1627 if (!extractor.Init()) {
1628 APP_LOGE("init bundle extractor failed");
1629 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
1630 }
1631
1632 /* obtain the so list in the hap */
1633 std::vector<std::string> soEntryFiles;
1634 if (!ObtainNativeSoFile(extractor, cpuAbi, soEntryFiles)) {
1635 APP_LOGE("ExtractFiles obtain native so file entryName failed");
1636 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
1637 }
1638
1639 std::string innerTmpSoPath = tmpSoPath;
1640 if (innerTmpSoPath.back() != Constants::PATH_SEPARATOR[0]) {
1641 innerTmpSoPath += Constants::PATH_SEPARATOR;
1642 }
1643
1644 /* create innerTmpSoPath */
1645 if (!IsExistDir(innerTmpSoPath)) {
1646 if (!MkRecursiveDir(innerTmpSoPath, true)) {
1647 APP_LOGE("create innerTmpSoPath %{public}s failed", innerTmpSoPath.c_str());
1648 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
1649 }
1650 }
1651
1652 for (const auto &entry : soEntryFiles) {
1653 APP_LOGD("entryName is %{public}s", entry.c_str());
1654 auto pos = entry.rfind(Constants::PATH_SEPARATOR[0]);
1655 if (pos == std::string::npos) {
1656 APP_LOGW("invalid so entry %{public}s", entry.c_str());
1657 continue;
1658 }
1659 std::string soFileName = entry.substr(pos + 1);
1660 if (soFileName.empty()) {
1661 APP_LOGW("invalid so entry %{public}s", entry.c_str());
1662 continue;
1663 }
1664 APP_LOGD("so file is %{public}s", soFileName.c_str());
1665 uint32_t offset = 0;
1666 uint32_t length = 0;
1667 if (!extractor.GetFileInfo(entry, offset, length) || length == 0) {
1668 APP_LOGW("GetFileInfo failed or invalid so file");
1669 continue;
1670 }
1671 APP_LOGD("so file %{public}s has offset %{public}d and file size %{public}d", entry.c_str(), offset, length);
1672
1673 /* mmap so to ram and write so file to temp path */
1674 ErrCode res = ERR_OK;
1675 if ((res = DecryptSoFile(hapPath, innerTmpSoPath + soFileName, uid, length, offset)) != ERR_OK) {
1676 APP_LOGE("decrypt file failed, srcPath is %{public}s and destPath is %{public}s", hapPath.c_str(),
1677 (innerTmpSoPath + soFileName).c_str());
1678 return res;
1679 }
1680 }
1681
1682 return ERR_OK;
1683 }
1684
ExtractSoFilesToTmpSoPath(const std::string & hapPath,const std::string & realSoFilesPath,const std::string & cpuAbi,const std::string & tmpSoPath,int32_t uid)1685 ErrCode InstalldOperator::ExtractSoFilesToTmpSoPath(const std::string &hapPath, const std::string &realSoFilesPath,
1686 const std::string &cpuAbi, const std::string &tmpSoPath, int32_t uid)
1687 {
1688 APP_LOGD("start to obtain decoded so files from so path");
1689 if (realSoFilesPath.empty()) {
1690 APP_LOGE("real so file path is empty");
1691 return ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_PATH;
1692 }
1693 BundleExtractor extractor(hapPath);
1694 if (!extractor.Init()) {
1695 APP_LOGE("init bundle extractor failed");
1696 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
1697 }
1698 /* obtain the so list in the hap */
1699 std::vector<std::string> soEntryFiles;
1700 if (!ObtainNativeSoFile(extractor, cpuAbi, soEntryFiles)) {
1701 APP_LOGE("ExtractFiles obtain native so file entryName failed");
1702 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
1703 }
1704
1705 std::string innerTmpSoPath = tmpSoPath;
1706 if (innerTmpSoPath.back() != Constants::PATH_SEPARATOR[0]) {
1707 innerTmpSoPath += Constants::PATH_SEPARATOR;
1708 }
1709 // create innerTmpSoPath
1710 if (!IsExistDir(innerTmpSoPath)) {
1711 if (!MkRecursiveDir(innerTmpSoPath, true)) {
1712 APP_LOGE("create innerTmpSoPath %{public}s failed", innerTmpSoPath.c_str());
1713 return ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR;
1714 }
1715 }
1716
1717 for (const auto &entry : soEntryFiles) {
1718 auto pos = entry.rfind(Constants::PATH_SEPARATOR[0]);
1719 if (pos == std::string::npos) {
1720 APP_LOGW("invalid so entry %{public}s", entry.c_str());
1721 continue;
1722 }
1723 std::string soFileName = entry.substr(pos + 1);
1724 if (soFileName.empty()) {
1725 APP_LOGW("invalid so entry %{public}s", entry.c_str());
1726 continue;
1727 }
1728
1729 std::string soPath = realSoFilesPath + soFileName;
1730 APP_LOGD("real path of the so file %{public}s is %{public}s", soFileName.c_str(), soPath.c_str());
1731
1732 if (IsExistFile(soPath)) {
1733 /* mmap so file to ram and write to innerTmpSoPath */
1734 ErrCode res = ERR_OK;
1735 APP_LOGD("tmp so path is %{public}s", (innerTmpSoPath + soFileName).c_str());
1736 if ((res = DecryptSoFile(soPath, innerTmpSoPath + soFileName, uid, 0, 0)) != ERR_OK) {
1737 APP_LOGE("decrypt file failed, srcPath is %{public}s and destPath is %{public}s", soPath.c_str(),
1738 (innerTmpSoPath + soFileName).c_str());
1739 return res;
1740 }
1741 } else {
1742 APP_LOGW("so file %{public}s is not existed", soPath.c_str());
1743 }
1744 }
1745 return ERR_OK;
1746 }
1747
DecryptSoFile(const std::string & filePath,const std::string & tmpPath,int32_t uid,uint32_t fileSize,uint32_t offset)1748 ErrCode InstalldOperator::DecryptSoFile(const std::string &filePath, const std::string &tmpPath, int32_t uid,
1749 uint32_t fileSize, uint32_t offset)
1750 {
1751 APP_LOGD("src file is %{public}s, temp path is %{public}s, bundle uid is %{public}d", filePath.c_str(),
1752 tmpPath.c_str(), uid);
1753 ErrCode result = ERR_BUNDLEMANAGER_QUICK_FIX_DECRYPTO_SO_FAILED;
1754
1755 /* call CallIoctl */
1756 int32_t dev_fd = INVALID_FILE_DESCRIPTOR;
1757 auto ret = CallIoctl(CODE_DECRYPT_CMD_SET_KEY, CODE_DECRYPT_CMD_SET_ASSOCIATE_KEY, uid, dev_fd);
1758 if (ret != 0) {
1759 APP_LOGE("CallIoctl failed");
1760 return result;
1761 }
1762
1763 /* mmap hap or so file to ram */
1764 std::string newfilePath;
1765 if (!PathToRealPath(filePath, newfilePath)) {
1766 APP_LOGE("file is not real path, file path: %{public}s", filePath.c_str());
1767 return result;
1768 }
1769 auto fd = open(newfilePath.c_str(), O_RDONLY);
1770 if (fd < 0) {
1771 APP_LOGE("open hap failed");
1772 close(dev_fd);
1773 return result;
1774 }
1775 struct stat st;
1776 if (fstat(fd, &st) == INVALID_RETURN_VALUE) {
1777 APP_LOGE("obtain hap file status faield");
1778 close(dev_fd);
1779 close(fd);
1780 return result;
1781 }
1782 off_t innerFileSize = fileSize;
1783 if (fileSize == 0) {
1784 innerFileSize = st.st_size;
1785 }
1786 void *addr = mmap(NULL, innerFileSize, PROT_READ, MAP_PRIVATE, fd, offset);
1787 if (addr == MAP_FAILED) {
1788 APP_LOGE("mmap hap file status faield");
1789 close(dev_fd);
1790 close(fd);
1791 return result;
1792 }
1793
1794 /* write hap file to the temp path */
1795 auto outPutFd = BundleUtil::CreateFileDescriptor(tmpPath, 0);
1796 if (outPutFd < 0) {
1797 APP_LOGE("create fd for tmp hap file failed");
1798 close(dev_fd);
1799 close(fd);
1800 munmap(addr, innerFileSize);
1801 return result;
1802 }
1803 if (write(outPutFd, addr, innerFileSize) != INVALID_RETURN_VALUE) {
1804 result = ERR_OK;
1805 APP_LOGD("write hap to temp path successfully");
1806 }
1807 close(dev_fd);
1808 close(fd);
1809 close(outPutFd);
1810 munmap(addr, innerFileSize);
1811 return result;
1812 }
1813
RemoveEncryptedKey(int32_t uid,const std::vector<std::string> & soList)1814 ErrCode InstalldOperator::RemoveEncryptedKey(int32_t uid, const std::vector<std::string> &soList)
1815 {
1816 if (uid == Constants::INVALID_UID) {
1817 APP_LOGD("invalid uid and no need to remove encrypted key");
1818 return ERR_OK;
1819 }
1820 if (soList.empty()) {
1821 APP_LOGD("no new so generated and no need to remove encrypted key");
1822 return ERR_OK;
1823 }
1824 ErrCode result = ERR_BUNDLEMANAGER_QUICK_FIX_DECRYPTO_SO_FAILED;
1825
1826 /* call CallIoctl */
1827 int32_t dev_fd = INVALID_FILE_DESCRIPTOR;
1828 auto ret = CallIoctl(CODE_DECRYPT_CMD_REMOVE_KEY, CODE_DECRYPT_CMD_REMOVE_KEY, uid, dev_fd);
1829 if (ret == 0) {
1830 APP_LOGD("ioctl successfully");
1831 result = ERR_OK;
1832 }
1833 close(dev_fd);
1834 return result;
1835 }
1836
CallIoctl(int32_t flag,int32_t associatedFlag,int32_t uid,int32_t & fd)1837 int32_t InstalldOperator::CallIoctl(int32_t flag, int32_t associatedFlag, int32_t uid, int32_t &fd)
1838 {
1839 int32_t installdUid = static_cast<int32_t>(getuid());
1840 int32_t bundleUid = uid;
1841 APP_LOGD("current process uid is %{public}d and bundle uid is %{public}d", installdUid, bundleUid);
1842
1843 /* open CODE_DECRYPT */
1844 std::string newCodeDecrypt;
1845 if (!PathToRealPath(CODE_DECRYPT, newCodeDecrypt)) {
1846 APP_LOGE("file is not real path, file path: %{public}s", CODE_DECRYPT.c_str());
1847 return INVALID_RETURN_VALUE;
1848 }
1849 fd = open(newCodeDecrypt.c_str(), O_RDONLY);
1850 if (fd < 0) {
1851 APP_LOGE("call open failed");
1852 return INVALID_RETURN_VALUE;
1853 }
1854
1855 /* build ioctl args to set key or remove key*/
1856 struct code_decrypt_arg firstArg;
1857 firstArg.arg1_len = sizeof(bundleUid);
1858 firstArg.arg1 = reinterpret_cast<void *>(&bundleUid);
1859 auto ret = ioctl(fd, flag, &firstArg);
1860 if (ret != 0) {
1861 APP_LOGE("call ioctl failed");
1862 close(fd);
1863 }
1864
1865 struct code_decrypt_arg secondArg;
1866 secondArg.arg1_len = sizeof(installdUid);
1867 secondArg.arg1 = reinterpret_cast<void *>(&installdUid);
1868 if (associatedFlag == CODE_DECRYPT_CMD_SET_ASSOCIATE_KEY) {
1869 secondArg.arg2_len = sizeof(bundleUid);
1870 secondArg.arg2 = reinterpret_cast<void *>(&bundleUid);
1871 }
1872 ret = ioctl(fd, associatedFlag, &secondArg);
1873 if (ret != 0) {
1874 APP_LOGE("call ioctl failed");
1875 close(fd);
1876 }
1877 return ret;
1878 }
1879 #endif
1880 } // namespace AppExecFwk
1881 } // namespace OHOS