• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &currentPath, 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 &currentPath, 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