1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "installd/installd_operator.h"
17
18 #include <algorithm>
19 #if defined(CODE_SIGNATURE_ENABLE)
20 #include "code_sign_utils.h"
21 #endif
22 #include <cstdio>
23 #include <dirent.h>
24 #include <dlfcn.h>
25 #include <dlfcn.h>
26 #include <fstream>
27 #include <map>
28 #include <sstream>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 #include "app_log_wrapper.h"
35 #include "bundle_constants.h"
36 #include "directory_ex.h"
37 #include "parameters.h"
38
39 namespace OHOS {
40 namespace AppExecFwk {
41 namespace {
42 static const char LIB_DIFF_PATCH_SHARED_SO_PATH[] = "system/lib/libdiff_patch_shared.z.so";
43 static const char LIB64_DIFF_PATCH_SHARED_SO_PATH[] = "system/lib64/libdiff_patch_shared.z.so";
44 static const char APPLY_PATCH_FUNCTION_NAME[] = "ApplyPatch";
45 using ApplyPatch = int32_t (*)(const std::string, const std::string, const std::string);
46
HandleScanResult(const std::string & dir,const std::string & subName,ResultMode resultMode)47 static std::string HandleScanResult(
48 const std::string &dir, const std::string &subName, ResultMode resultMode)
49 {
50 if (resultMode == ResultMode::RELATIVE_PATH) {
51 return subName;
52 }
53
54 return dir + Constants::PATH_SEPARATOR + subName;
55 }
56
StartsWith(const std::string & sourceString,const std::string & targetPrefix)57 static bool StartsWith(const std::string &sourceString, const std::string &targetPrefix)
58 {
59 return sourceString.rfind(targetPrefix, 0) == 0;
60 }
61 }
62
IsExistFile(const std::string & path)63 bool InstalldOperator::IsExistFile(const std::string &path)
64 {
65 if (path.empty()) {
66 return false;
67 }
68
69 struct stat buf = {};
70 if (stat(path.c_str(), &buf) != 0) {
71 return false;
72 }
73 return S_ISREG(buf.st_mode);
74 }
75
IsExistDir(const std::string & path)76 bool InstalldOperator::IsExistDir(const std::string &path)
77 {
78 if (path.empty()) {
79 return false;
80 }
81
82 struct stat buf = {};
83 if (stat(path.c_str(), &buf) != 0) {
84 APP_LOGE("the path is not existed %{public}s", path.c_str());
85 return false;
86 }
87 return S_ISDIR(buf.st_mode);
88 }
89
IsDirEmpty(const std::string & dir)90 bool InstalldOperator::IsDirEmpty(const std::string &dir)
91 {
92 return OHOS::IsEmptyFolder(dir);
93 }
94
MkRecursiveDir(const std::string & path,bool isReadByOthers)95 bool InstalldOperator::MkRecursiveDir(const std::string &path, bool isReadByOthers)
96 {
97 if (!OHOS::ForceCreateDirectory(path)) {
98 APP_LOGE("mkdir failed");
99 return false;
100 }
101 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH;
102 mode |= (isReadByOthers ? S_IROTH : 0);
103 return OHOS::ChangeModeDirectory(path, mode);
104 }
105
DeleteDir(const std::string & path)106 bool InstalldOperator::DeleteDir(const std::string &path)
107 {
108 APP_LOGD("start to delete dir %{public}s", path.c_str());
109 if (IsExistFile(path)) {
110 return OHOS::RemoveFile(path);
111 }
112 if (IsExistDir(path)) {
113 return OHOS::ForceRemoveDirectory(path);
114 }
115 return true;
116 }
117
ExtractFiles(const std::string & sourcePath,const std::string & targetSoPath,const std::string & cpuAbi)118 bool InstalldOperator::ExtractFiles(const std::string &sourcePath, const std::string &targetSoPath,
119 const std::string &cpuAbi)
120 {
121 APP_LOGD("InstalldOperator::ExtractFiles start");
122 if (targetSoPath.empty()) {
123 return true;
124 }
125
126 BundleExtractor extractor(sourcePath);
127 if (!extractor.Init()) {
128 return false;
129 }
130
131 std::vector<std::string> soEntryFiles;
132 if (!ObtainNativeSoFile(extractor, cpuAbi, soEntryFiles)) {
133 APP_LOGE("ExtractFiles obtain native so file entryName failed");
134 return false;
135 }
136
137 for_each(soEntryFiles.begin(), soEntryFiles.end(), [&extractor, &targetSoPath, &cpuAbi](const auto &entry) {
138 ExtractTargetFile(extractor, entry, targetSoPath, cpuAbi);
139 });
140
141 APP_LOGD("InstalldOperator::ExtractFiles end");
142 return true;
143 }
144
ExtractFiles(const ExtractParam & extractParam)145 bool InstalldOperator::ExtractFiles(const ExtractParam &extractParam)
146 {
147 APP_LOGD("InstalldOperator::ExtractFiles start");
148 BundleExtractor extractor(extractParam.srcPath);
149 if (!extractor.Init()) {
150 APP_LOGE("extractor init failed");
151 return false;
152 }
153
154 if (extractParam.extractFileType == ExtractFileType::RESOURCE) {
155 return ExtractResourceFiles(extractParam, extractor);
156 }
157
158 if ((extractParam.extractFileType == ExtractFileType::AP) &&
159 !extractor.IsDirExist(Constants::AP)) {
160 APP_LOGD("hap has no ap files and does not need to be extracted.");
161 return true;
162 }
163
164 std::vector<std::string> entryNames;
165 if (!extractor.GetZipFileNames(entryNames) || entryNames.empty()) {
166 APP_LOGE("get entryNames failed");
167 return false;
168 }
169
170 for (const auto &entryName : entryNames) {
171 if (strcmp(entryName.c_str(), ".") == 0 ||
172 strcmp(entryName.c_str(), "..") == 0) {
173 continue;
174 }
175 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
176 continue;
177 }
178 // handle native file
179 if (IsNativeFile(entryName, extractParam)) {
180 ExtractTargetFile(extractor, entryName, extractParam.targetPath,
181 extractParam.cpuAbi, extractParam.extractFileType);
182 continue;
183 }
184 }
185
186 APP_LOGD("InstalldOperator::ExtractFiles end");
187 return true;
188 }
189
IsNativeFile(const std::string & entryName,const ExtractParam & extractParam)190 bool InstalldOperator::IsNativeFile(
191 const std::string &entryName, const ExtractParam &extractParam)
192 {
193 APP_LOGD("IsNativeFile, entryName : %{public}s", entryName.c_str());
194 if (extractParam.targetPath.empty()) {
195 APP_LOGD("current hap not include so");
196 return false;
197 }
198 std::string prefix;
199 std::vector<std::string> suffixs;
200 switch (extractParam.extractFileType) {
201 case ExtractFileType::SO: {
202 prefix = Constants::LIBS + extractParam.cpuAbi + Constants::PATH_SEPARATOR;
203 suffixs.emplace_back(Constants::SO_SUFFIX);
204 break;
205 }
206 case ExtractFileType::AN: {
207 prefix = Constants::AN + extractParam.cpuAbi + Constants::PATH_SEPARATOR;
208 suffixs.emplace_back(Constants::AN_SUFFIX);
209 suffixs.emplace_back(Constants::AI_SUFFIX);
210 break;
211 }
212 case ExtractFileType::AP: {
213 prefix = Constants::AP;
214 suffixs.emplace_back(Constants::AP_SUFFIX);
215 break;
216 }
217 default: {
218 return false;
219 }
220 }
221
222 if (entryName.find(prefix) == std::string::npos) {
223 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
224 return false;
225 }
226
227 bool checkSuffix = false;
228 for (const auto &suffix : suffixs) {
229 if (entryName.find(suffix) != std::string::npos) {
230 checkSuffix = true;
231 break;
232 }
233 }
234
235 if (!checkSuffix) {
236 APP_LOGD("file type error.");
237 return false;
238 }
239
240 APP_LOGD("find native file, prefix: %{public}s, entryName: %{public}s",
241 prefix.c_str(), entryName.c_str());
242 return true;
243 }
244
IsNativeSo(const std::string & entryName,const std::string & cpuAbi)245 bool InstalldOperator::IsNativeSo(const std::string &entryName, const std::string &cpuAbi)
246 {
247 APP_LOGD("IsNativeSo, entryName : %{public}s", entryName.c_str());
248 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
249 if (!StartsWith(entryName, prefix)) {
250 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
251 return false;
252 }
253 if (entryName.find(Constants::SO_SUFFIX) == std::string::npos) {
254 APP_LOGD("file name not so format.");
255 return false;
256 }
257 APP_LOGD("find native so, entryName : %{public}s", entryName.c_str());
258 return true;
259 }
260
IsDiffFiles(const std::string & entryName,const std::string & targetPath,const std::string & cpuAbi)261 bool InstalldOperator::IsDiffFiles(const std::string &entryName,
262 const std::string &targetPath, const std::string &cpuAbi)
263 {
264 APP_LOGD("IsDiffFiles, entryName : %{public}s", entryName.c_str());
265 if (targetPath.empty()) {
266 APP_LOGD("current hap not include diff");
267 return false;
268 }
269 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
270 if (entryName.find(prefix) == std::string::npos) {
271 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
272 return false;
273 }
274 if (entryName.find(Constants::DIFF_SUFFIX) == std::string::npos) {
275 APP_LOGD("file name not diff format.");
276 return false;
277 }
278 APP_LOGD("find native diff, entryName : %{public}s", entryName.c_str());
279 return true;
280 }
281
ExtractTargetFile(const BundleExtractor & extractor,const std::string & entryName,const std::string & targetPath,const std::string & cpuAbi,const ExtractFileType & extractFileType)282 void InstalldOperator::ExtractTargetFile(const BundleExtractor &extractor, const std::string &entryName,
283 const std::string &targetPath, const std::string &cpuAbi, const ExtractFileType &extractFileType)
284 {
285 // create dir if not exist
286 if (!IsExistDir(targetPath)) {
287 if (!MkRecursiveDir(targetPath, true)) {
288 APP_LOGE("create targetPath %{private}s failed", targetPath.c_str());
289 return;
290 }
291 }
292
293 std::string prefix;
294 switch (extractFileType) {
295 case ExtractFileType::SO: {
296 prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
297 break;
298 }
299 case ExtractFileType::AN: {
300 prefix = Constants::AN + cpuAbi + Constants::PATH_SEPARATOR;
301 break;
302 }
303 case ExtractFileType::AP: {
304 prefix = Constants::AP;
305 break;
306 }
307 default: {
308 return;
309 }
310 }
311 std::string targetName = entryName.substr(prefix.length());
312 std::string path = targetPath;
313 if (path.back() != Constants::FILE_SEPARATOR_CHAR) {
314 path += Constants::FILE_SEPARATOR_CHAR;
315 }
316 path += targetName;
317 bool ret = extractor.ExtractFile(entryName, path);
318 if (!ret) {
319 APP_LOGE("extract file failed, entryName : %{public}s", entryName.c_str());
320 return;
321 }
322 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
323 if (extractFileType == ExtractFileType::AP) {
324 struct stat buf = {};
325 if (stat(targetPath.c_str(), &buf) != 0) {
326 return;
327 }
328 ChangeFileAttr(path, buf.st_uid, buf.st_gid);
329 mode = (buf.st_uid == buf.st_gid) ? (S_IRUSR | S_IWUSR) : (S_IRUSR | S_IWUSR | S_IRGRP);
330 }
331 if (!OHOS::ChangeModeFile(path, mode)) {
332 return;
333 }
334 APP_LOGD("extract file success, path : %{private}s", path.c_str());
335 }
336
RenameDir(const std::string & oldPath,const std::string & newPath)337 bool InstalldOperator::RenameDir(const std::string &oldPath, const std::string &newPath)
338 {
339 if (oldPath.empty() || oldPath.size() > PATH_MAX) {
340 APP_LOGE("oldpath error");
341 return false;
342 }
343 if (access(oldPath.c_str(), F_OK) != 0 && access(newPath.c_str(), F_OK) == 0) {
344 return true;
345 }
346 std::string realOldPath;
347 realOldPath.reserve(PATH_MAX);
348 realOldPath.resize(PATH_MAX - 1);
349 if (realpath(oldPath.c_str(), &(realOldPath[0])) == nullptr) {
350 APP_LOGE("realOldPath %{private}s", realOldPath.c_str());
351 return false;
352 }
353
354 if (!(IsValidCodePath(realOldPath) && IsValidCodePath(newPath))) {
355 APP_LOGE("IsValidCodePath failed");
356 return false;
357 }
358 return RenameFile(realOldPath, newPath);
359 }
360
GetPathDir(const std::string & path)361 std::string InstalldOperator::GetPathDir(const std::string &path)
362 {
363 std::size_t pos = path.rfind(Constants::PATH_SEPARATOR);
364 if (pos == std::string::npos) {
365 return std::string();
366 }
367 return path.substr(0, pos + 1);
368 }
369
ChangeDirOwnerRecursively(const std::string & path,const int uid,const int gid)370 bool InstalldOperator::ChangeDirOwnerRecursively(const std::string &path, const int uid, const int gid)
371 {
372 std::string subPath;
373 bool ret = true;
374 DIR *dir = opendir(path.c_str());
375 if (dir == nullptr) {
376 return false;
377 }
378
379 while (true) {
380 struct dirent *ptr = readdir(dir);
381 if (ptr == nullptr) {
382 break;
383 }
384
385 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
386 continue;
387 }
388
389 subPath = OHOS::IncludeTrailingPathDelimiter(path) + std::string(ptr->d_name);
390 if (ptr->d_type == DT_DIR) {
391 ret = ChangeDirOwnerRecursively(subPath, uid, gid);
392 continue;
393 }
394
395 if (access(subPath.c_str(), F_OK) == 0) {
396 if (!ChangeFileAttr(subPath, uid, gid)) {
397 APP_LOGE("Failed to ChangeFileAttr %{public}s", subPath.c_str());
398 closedir(dir);
399 return false;
400 }
401 }
402 }
403
404 closedir(dir);
405 std::string currentPath = OHOS::ExcludeTrailingPathDelimiter(path);
406 if (access(currentPath.c_str(), F_OK) == 0) {
407 if (!ChangeFileAttr(currentPath, uid, gid)) {
408 APP_LOGE("Failed to ChangeFileAttr %{public}s", currentPath.c_str());
409 return false;
410 }
411 }
412
413 return ret;
414 }
415
ChangeFileAttr(const std::string & filePath,const int uid,const int gid)416 bool InstalldOperator::ChangeFileAttr(const std::string &filePath, const int uid, const int gid)
417 {
418 APP_LOGD("begin to change %{private}s file attribute", filePath.c_str());
419 if (chown(filePath.c_str(), uid, gid) != 0) {
420 APP_LOGE("fail to change %{private}s ownership", filePath.c_str());
421 return false;
422 }
423 APP_LOGD("change %{private}s file attribute successfully", filePath.c_str());
424 return true;
425 }
426
RenameFile(const std::string & oldPath,const std::string & newPath)427 bool InstalldOperator::RenameFile(const std::string &oldPath, const std::string &newPath)
428 {
429 if (oldPath.empty() || newPath.empty()) {
430 return false;
431 }
432 if (!DeleteDir(newPath)) {
433 return false;
434 }
435 return rename(oldPath.c_str(), newPath.c_str()) == 0;
436 }
437
IsValidPath(const std::string & rootDir,const std::string & path)438 bool InstalldOperator::IsValidPath(const std::string &rootDir, const std::string &path)
439 {
440 if (rootDir.find(Constants::PATH_SEPARATOR) != 0 ||
441 rootDir.rfind(Constants::PATH_SEPARATOR) != (rootDir.size() - 1) || rootDir.find("..") != std::string::npos) {
442 return false;
443 }
444 if (path.find("..") != std::string::npos) {
445 return false;
446 }
447 return path.compare(0, rootDir.size(), rootDir) == 0;
448 }
449
IsValidCodePath(const std::string & codePath)450 bool InstalldOperator::IsValidCodePath(const std::string &codePath)
451 {
452 if (codePath.empty()) {
453 return false;
454 }
455 return IsValidPath(Constants::BUNDLE_BASE_CODE_DIR + Constants::PATH_SEPARATOR, codePath);
456 }
457
DeleteFiles(const std::string & dataPath)458 bool InstalldOperator::DeleteFiles(const std::string &dataPath)
459 {
460 APP_LOGD("InstalldOperator::DeleteFiles start");
461 std::string subPath;
462 bool ret = true;
463 DIR *dir = opendir(dataPath.c_str());
464 if (dir == nullptr) {
465 return false;
466 }
467 while (true) {
468 struct dirent *ptr = readdir(dir);
469 if (ptr == nullptr) {
470 break;
471 }
472 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
473 continue;
474 }
475 subPath = OHOS::IncludeTrailingPathDelimiter(dataPath) + std::string(ptr->d_name);
476 if (ptr->d_type == DT_DIR) {
477 ret = OHOS::ForceRemoveDirectory(subPath);
478 } else {
479 if (access(subPath.c_str(), F_OK) == 0) {
480 ret = OHOS::RemoveFile(subPath);
481 }
482 }
483 }
484 closedir(dir);
485 return ret;
486 }
487
MkOwnerDir(const std::string & path,bool isReadByOthers,const int uid,const int gid)488 bool InstalldOperator::MkOwnerDir(const std::string &path, bool isReadByOthers, const int uid, const int gid)
489 {
490 if (!MkRecursiveDir(path, isReadByOthers)) {
491 return false;
492 }
493 return ChangeFileAttr(path, uid, gid);
494 }
495
MkOwnerDir(const std::string & path,int mode,const int uid,const int gid)496 bool InstalldOperator::MkOwnerDir(const std::string &path, int mode, const int uid, const int gid)
497 {
498 if (!OHOS::ForceCreateDirectory(path)) {
499 APP_LOGE("mkdir failed");
500 return false;
501 }
502 if (!OHOS::ChangeModeDirectory(path, mode)) {
503 return false;
504 }
505 return ChangeDirOwnerRecursively(path, uid, gid);
506 }
507
GetDiskUsage(const std::string & dir)508 int64_t InstalldOperator::GetDiskUsage(const std::string &dir)
509 {
510 if (dir.empty() || (dir.size() > Constants::PATH_MAX_SIZE)) {
511 APP_LOGE("GetDiskUsage dir path invaild");
512 return 0;
513 }
514 std::string filePath = "";
515 if (!PathToRealPath(dir, filePath)) {
516 APP_LOGE("file is not real path, file path: %{private}s", dir.c_str());
517 return 0;
518 }
519 DIR *dirPtr = opendir(filePath.c_str());
520 if (dirPtr == nullptr) {
521 APP_LOGE("GetDiskUsage open file dir:%{private}s is failure", filePath.c_str());
522 return 0;
523 }
524 if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
525 filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
526 }
527 struct dirent *entry = nullptr;
528 int64_t size = 0;
529 while ((entry = readdir(dirPtr)) != nullptr) {
530 if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
531 continue;
532 }
533 std::string path = filePath + entry->d_name;
534 std::string realPath = "";
535 if (!PathToRealPath(path, realPath)) {
536 APP_LOGE("file is not real path %{private}s", path.c_str());
537 continue;
538 }
539 struct stat fileInfo = {0};
540 if (stat(realPath.c_str(), &fileInfo) != 0) {
541 APP_LOGE("call stat error %{private}s", realPath.c_str());
542 fileInfo.st_size = 0;
543 }
544 size += fileInfo.st_size;
545 if (entry->d_type == DT_DIR) {
546 size += GetDiskUsage(realPath);
547 }
548 }
549 closedir(dirPtr);
550 return size;
551 }
552
TraverseCacheDirectory(const std::string & currentPath,std::vector<std::string> & cacheDirs)553 void InstalldOperator::TraverseCacheDirectory(const std::string ¤tPath, std::vector<std::string> &cacheDirs)
554 {
555 if (currentPath.empty() || (currentPath.size() > Constants::PATH_MAX_SIZE)) {
556 APP_LOGE("TraverseCacheDirectory current path invaild");
557 return;
558 }
559 std::string filePath = "";
560 if (!PathToRealPath(currentPath, filePath)) {
561 APP_LOGE("file is not real path, file path: %{private}s", currentPath.c_str());
562 return;
563 }
564 DIR* dir = opendir(filePath.c_str());
565 if (dir == nullptr) {
566 return;
567 }
568 if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
569 filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
570 }
571 struct dirent *ptr = nullptr;
572 while ((ptr = readdir(dir)) != nullptr) {
573 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
574 continue;
575 }
576 if (ptr->d_type == DT_DIR && strcmp(ptr->d_name, Constants::CACHE_DIR) == 0) {
577 std::string currentDir = filePath + std::string(ptr->d_name);
578 cacheDirs.emplace_back(currentDir);
579 continue;
580 }
581 if (ptr->d_type == DT_DIR) {
582 std::string currentDir = filePath + std::string(ptr->d_name);
583 TraverseCacheDirectory(currentDir, cacheDirs);
584 }
585 }
586 closedir(dir);
587 }
588
GetDiskUsageFromPath(const std::vector<std::string> & path)589 int64_t InstalldOperator::GetDiskUsageFromPath(const std::vector<std::string> &path)
590 {
591 int64_t fileSize = 0;
592 for (auto &st : path) {
593 fileSize += GetDiskUsage(st);
594 }
595 return fileSize;
596 }
597
ScanDir(const std::string & dirPath,ScanMode scanMode,ResultMode resultMode,std::vector<std::string> & paths)598 bool InstalldOperator::ScanDir(
599 const std::string &dirPath, ScanMode scanMode, ResultMode resultMode, std::vector<std::string> &paths)
600 {
601 if (dirPath.empty() || (dirPath.size() > Constants::PATH_MAX_SIZE)) {
602 APP_LOGE("Scan dir path invaild");
603 return false;
604 }
605
606 std::string realPath = "";
607 if (!PathToRealPath(dirPath, realPath)) {
608 APP_LOGE("file(%{public}s) is not real path", dirPath.c_str());
609 return false;
610 }
611
612 DIR* dir = opendir(realPath.c_str());
613 if (dir == nullptr) {
614 APP_LOGE("Scan open dir(%{public}s) fail", realPath.c_str());
615 return false;
616 }
617
618 struct dirent *ptr = nullptr;
619 while ((ptr = readdir(dir)) != nullptr) {
620 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
621 continue;
622 }
623
624 std::string subName(ptr->d_name);
625 if (scanMode == ScanMode::SUB_FILE_DIR) {
626 if (ptr->d_type == DT_DIR) {
627 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
628 }
629
630 continue;
631 }
632
633 if (scanMode == ScanMode::SUB_FILE_FILE) {
634 if (ptr->d_type == DT_REG) {
635 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
636 }
637
638 continue;
639 }
640
641 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
642 }
643
644 closedir(dir);
645 return true;
646 }
647
CopyFile(const std::string & sourceFile,const std::string & destinationFile)648 bool InstalldOperator::CopyFile(
649 const std::string &sourceFile, const std::string &destinationFile)
650 {
651 if (sourceFile.empty() || destinationFile.empty()) {
652 APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
653 return false;
654 }
655
656 std::ifstream in(sourceFile);
657 if (!in.is_open()) {
658 APP_LOGE("Copy file failed due to open sourceFile failed");
659 return false;
660 }
661
662 std::ofstream out(destinationFile);
663 if (!out.is_open()) {
664 APP_LOGE("Copy file failed due to open destinationFile failed");
665 in.close();
666 return false;
667 }
668
669 out << in.rdbuf();
670 in.close();
671 out.close();
672 return true;
673 }
674
ExtractDiffFiles(const std::string & filePath,const std::string & targetPath,const std::string & cpuAbi)675 bool InstalldOperator::ExtractDiffFiles(const std::string &filePath, const std::string &targetPath,
676 const std::string &cpuAbi)
677 {
678 BundleExtractor extractor(filePath);
679 if (!extractor.Init()) {
680 return false;
681 }
682 std::vector<std::string> entryNames;
683 if (!extractor.GetZipFileNames(entryNames)) {
684 return false;
685 }
686 for (const auto &entryName : entryNames) {
687 if (strcmp(entryName.c_str(), ".") == 0 ||
688 strcmp(entryName.c_str(), "..") == 0) {
689 continue;
690 }
691 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
692 continue;
693 }
694 // handle diff file
695 if (IsDiffFiles(entryName, targetPath, cpuAbi)) {
696 ExtractTargetFile(extractor, entryName, targetPath, cpuAbi);
697 }
698 }
699 return true;
700 }
701
OpenHandle(void ** handle)702 bool InstalldOperator::OpenHandle(void **handle)
703 {
704 APP_LOGI("InstalldOperator::OpenHandle start");
705 if (handle == nullptr) {
706 APP_LOGE("InstalldOperator::OpenHandle error handle is nullptr.");
707 return false;
708 }
709 *handle = dlopen(LIB64_DIFF_PATCH_SHARED_SO_PATH, RTLD_NOW | RTLD_GLOBAL);
710 if (*handle == nullptr) {
711 APP_LOGW("ApplyDiffPatch failed to open libdiff_patch_shared.z.so, err:%{public}s", dlerror());
712 *handle = dlopen(LIB_DIFF_PATCH_SHARED_SO_PATH, RTLD_NOW | RTLD_GLOBAL);
713 }
714 if (*handle == nullptr) {
715 APP_LOGE("ApplyDiffPatch failed to open libdiff_patch_shared.z.so, err:%{public}s", dlerror());
716 return false;
717 }
718 APP_LOGI("InstalldOperator::OpenHandle end");
719 return true;
720 }
721
CloseHandle(void ** handle)722 void InstalldOperator::CloseHandle(void **handle)
723 {
724 APP_LOGI("InstalldOperator::CloseHandle start");
725 if ((handle != nullptr) && (*handle != nullptr)) {
726 dlclose(*handle);
727 *handle = nullptr;
728 APP_LOGD("InstalldOperator::CloseHandle, err:%{public}s", dlerror());
729 }
730 APP_LOGI("InstalldOperator::CloseHandle end");
731 }
732
ProcessApplyDiffPatchPath(const std::string & oldSoPath,const std::string & diffFilePath,const std::string & newSoPath,std::vector<std::string> & oldSoFileNames,std::vector<std::string> & diffFileNames)733 bool InstalldOperator::ProcessApplyDiffPatchPath(
734 const std::string &oldSoPath, const std::string &diffFilePath,
735 const std::string &newSoPath, std::vector<std::string> &oldSoFileNames, std::vector<std::string> &diffFileNames)
736 {
737 APP_LOGI("ProcessApplyDiffPatchPath oldSoPath: %{private}s, diffFilePath: %{private}s, newSoPath: %{public}s",
738 oldSoPath.c_str(), diffFilePath.c_str(), newSoPath.c_str());
739 if (oldSoPath.empty() || diffFilePath.empty() || newSoPath.empty()) {
740 return false;
741 }
742 if (!IsExistDir(oldSoPath) || !IsExistDir(diffFilePath)) {
743 APP_LOGE("ProcessApplyDiffPatchPath oldSoPath or diffFilePath not exist");
744 return false;
745 }
746
747 if (!ScanDir(oldSoPath, ScanMode::SUB_FILE_FILE, ResultMode::RELATIVE_PATH, oldSoFileNames)) {
748 APP_LOGE("ProcessApplyDiffPatchPath ScanDir oldSoPath failed");
749 return false;
750 }
751
752 if (!ScanDir(diffFilePath, ScanMode::SUB_FILE_FILE, ResultMode::RELATIVE_PATH, diffFileNames)) {
753 APP_LOGE("ProcessApplyDiffPatchPath ScanDir diffFilePath failed");
754 return false;
755 }
756
757 if (oldSoFileNames.empty() || diffFileNames.empty()) {
758 APP_LOGE("ProcessApplyDiffPatchPath so or diff files empty");
759 return false;
760 }
761
762 if (!IsExistDir(newSoPath)) {
763 APP_LOGD("ProcessApplyDiffPatchPath create newSoPath");
764 if (!MkRecursiveDir(newSoPath, true)) {
765 APP_LOGE("ProcessApplyDiffPatchPath create newSo dir (%{private}s) failed", newSoPath.c_str());
766 return false;
767 }
768 }
769 APP_LOGI("ProcessApplyDiffPatchPath end");
770 return true;
771 }
772
ApplyDiffPatch(const std::string & oldSoPath,const std::string & diffFilePath,const std::string & newSoPath)773 bool InstalldOperator::ApplyDiffPatch(const std::string &oldSoPath, const std::string &diffFilePath,
774 const std::string &newSoPath)
775 {
776 APP_LOGI("ApplyDiffPatch start");
777 std::vector<std::string> oldSoFileNames;
778 std::vector<std::string> diffFileNames;
779 if (InstalldOperator::IsDirEmpty(oldSoPath) || InstalldOperator::IsDirEmpty(diffFilePath)) {
780 APP_LOGD("oldSoPath or diffFilePath is empty, not require ApplyPatch");
781 return true;
782 }
783 if (!ProcessApplyDiffPatchPath(oldSoPath, diffFilePath, newSoPath, oldSoFileNames, diffFileNames)) {
784 APP_LOGE("ApplyDiffPatch ProcessApplyDiffPatchPath failed");
785 return false;
786 }
787 std::string realOldSoPath;
788 std::string realDiffFilePath;
789 std::string realNewSoPath;
790 if (!PathToRealPath(oldSoPath, realOldSoPath) || !PathToRealPath(diffFilePath, realDiffFilePath) ||
791 !PathToRealPath(newSoPath, realNewSoPath)) {
792 APP_LOGE("ApplyDiffPatch Path is not real path");
793 return false;
794 }
795 void *handle = nullptr;
796 if (!OpenHandle(&handle)) {
797 return false;
798 }
799 auto applyPatch = reinterpret_cast<ApplyPatch>(dlsym(handle, APPLY_PATCH_FUNCTION_NAME));
800 if (applyPatch == nullptr) {
801 APP_LOGE("ApplyDiffPatch failed to get applyPatch err:%{public}s", dlerror());
802 CloseHandle(&handle);
803 return false;
804 }
805 std::vector<std::string> newSoList;
806 for (const auto &diffFileName : diffFileNames) {
807 std::string soFileName = diffFileName.substr(0, diffFileName.rfind(Constants::DIFF_SUFFIX));
808 APP_LOGD("ApplyDiffPatch soName: %{public}s, diffName: %{public}s", soFileName.c_str(), diffFileName.c_str());
809 if (find(oldSoFileNames.begin(), oldSoFileNames.end(), soFileName) != oldSoFileNames.end()) {
810 int32_t ret = applyPatch(realDiffFilePath + Constants::PATH_SEPARATOR + diffFileName,
811 realOldSoPath + Constants::PATH_SEPARATOR + soFileName,
812 realNewSoPath + Constants::PATH_SEPARATOR + soFileName);
813 if (ret != ERR_OK) {
814 APP_LOGE("ApplyDiffPatch failed, applyPatch errcode: %{public}d", ret);
815 for (const auto &file : newSoList) {
816 DeleteDir(file);
817 }
818 CloseHandle(&handle);
819 return false;
820 }
821 newSoList.emplace_back(realNewSoPath + Constants::PATH_SEPARATOR + soFileName);
822 }
823 }
824 CloseHandle(&handle);
825 APP_LOGI("ApplyDiffPatch end");
826 return true;
827 }
828
ObtainQuickFixFileDir(const std::string & dir,std::vector<std::string> & fileVec)829 bool InstalldOperator::ObtainQuickFixFileDir(const std::string &dir, std::vector<std::string> &fileVec)
830 {
831 if (dir.empty()) {
832 APP_LOGE("ObtainQuickFixFileDir dir path invaild");
833 return false;
834 }
835
836 std::string realPath = "";
837 if (!PathToRealPath(dir, realPath)) {
838 APP_LOGE("dir(%{public}s) is not real path", dir.c_str());
839 return false;
840 }
841
842 DIR* directory = opendir(realPath.c_str());
843 if (directory == nullptr) {
844 APP_LOGE("ObtainQuickFixFileDir open dir(%{public}s) fail", realPath.c_str());
845 return false;
846 }
847
848 struct dirent *ptr = nullptr;
849 while ((ptr = readdir(directory)) != nullptr) {
850 std::string currentName(ptr->d_name);
851 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
852 continue;
853 }
854
855 std::string curPath = dir + Constants::PATH_SEPARATOR + currentName;
856 struct stat s;
857 if (stat(curPath.c_str(), &s) == 0) {
858 // directory
859 if (s.st_mode & S_IFDIR) {
860 ObtainQuickFixFileDir(curPath, fileVec);
861 }
862
863 // file
864 if ((s.st_mode & S_IFREG) &&
865 (currentName.find(Constants::QUICK_FIX_FILE_SUFFIX) != std::string::npos)) {
866 fileVec.emplace_back(dir);
867 }
868 }
869 }
870 closedir(directory);
871 return true;
872 }
873
CopyFiles(const std::string & sourceDir,const std::string & destinationDir)874 bool InstalldOperator::CopyFiles(const std::string &sourceDir, const std::string &destinationDir)
875 {
876 APP_LOGD("sourceDir is %{public}s, destinationDir is %{public}s", sourceDir.c_str(), destinationDir.c_str());
877 if (sourceDir.empty() || destinationDir.empty()) {
878 APP_LOGE("Copy file failed due to sourceDir or destinationDir is empty");
879 return false;
880 }
881
882 std::string realPath = "";
883 if (!PathToRealPath(sourceDir, realPath)) {
884 APP_LOGE("sourceDir(%{public}s) is not real path", sourceDir.c_str());
885 return false;
886 }
887
888 DIR* directory = opendir(realPath.c_str());
889 if (directory == nullptr) {
890 APP_LOGE("CopyFiles open dir(%{public}s) fail", realPath.c_str());
891 return false;
892 }
893
894 struct dirent *ptr = nullptr;
895 while ((ptr = readdir(directory)) != nullptr) {
896 std::string currentName(ptr->d_name);
897 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
898 continue;
899 }
900
901 std::string curPath = sourceDir + Constants::PATH_SEPARATOR + currentName;
902 struct stat s;
903 if ((stat(curPath.c_str(), &s) == 0) && (s.st_mode & S_IFREG)) {
904 std::string innerDesStr = destinationDir + Constants::PATH_SEPARATOR + currentName;
905 if (CopyFile(curPath, innerDesStr)) {
906 ChangeFileAttr(innerDesStr, Constants::FOUNDATION_UID, Constants::BMS_GID);
907 }
908 }
909 }
910 closedir(directory);
911 return true;
912 }
913
GetNativeLibraryFileNames(const std::string & filePath,const std::string & cpuAbi,std::vector<std::string> & fileNames)914 bool InstalldOperator::GetNativeLibraryFileNames(const std::string &filePath, const std::string &cpuAbi,
915 std::vector<std::string> &fileNames)
916 {
917 BundleExtractor extractor(filePath);
918 if (!extractor.Init()) {
919 return false;
920 }
921 std::vector<std::string> entryNames;
922 if (!extractor.GetZipFileNames(entryNames)) {
923 return false;
924 }
925 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
926 for (const auto &entryName : entryNames) {
927 if ((entryName.find(prefix) == 0) &&
928 (entryName.find(Constants::SO_SUFFIX) != std::string::npos)) {
929 fileNames.push_back(entryName.substr(prefix.length(), entryName.length()));
930 }
931 }
932 APP_LOGD("InstalldOperator::GetNativeLibraryFileNames end");
933 return true;
934 }
935
VerifyCodeSignature(const std::string & modulePath,const std::string & cpuAbi,const std::string & targetSoPath,const std::string & signatureFileDir)936 bool InstalldOperator::VerifyCodeSignature(const std::string &modulePath, const std::string &cpuAbi,
937 const std::string &targetSoPath, const std::string &signatureFileDir)
938 {
939 APP_LOGD("process code signature of src path %{public}s, signature file path %{public}s", modulePath.c_str(),
940 signatureFileDir.c_str());
941 if (signatureFileDir.empty()) {
942 APP_LOGD("signature file dir is empty and does not need to verify code signature");
943 return true;
944 }
945
946 BundleExtractor extractor(modulePath);
947 if (!extractor.Init()) {
948 return false;
949 }
950
951 std::vector<std::string> soEntryFiles;
952 if (!ObtainNativeSoFile(extractor, cpuAbi, soEntryFiles)) {
953 APP_LOGE("ObtainNativeSoFile failed");
954 return false;
955 }
956
957 if (soEntryFiles.empty()) {
958 APP_LOGD("no so file in installation file %{public}s", modulePath.c_str());
959 return true;
960 }
961
962 #if defined(CODE_SIGNATURE_ENABLE)
963 Security::CodeSign::EntryMap entryMap;
964 if (!targetSoPath.empty()) {
965 const std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
966 for_each(soEntryFiles.begin(), soEntryFiles.end(), [&entryMap, &prefix, &targetSoPath](const auto &entry) {
967 std::string fileName = entry.substr(prefix.length());
968 std::string path = targetSoPath;
969 if (path.back() != Constants::FILE_SEPARATOR_CHAR) {
970 path += Constants::FILE_SEPARATOR_CHAR;
971 }
972 entryMap.emplace(entry, path + fileName);
973 APP_LOGD("VerifyCode the targetSoPath is %{public}s", (path + fileName).c_str());
974 });
975 }
976 ErrCode ret = Security::CodeSign::CodeSignUtils::EnforceCodeSignForApp(entryMap, signatureFileDir);
977 if (ret != ERR_OK) {
978 APP_LOGE("VerifyCode failed due to %{public}d", ret);
979 return false;
980 }
981 #endif
982 return true;
983 }
984
ObtainNativeSoFile(const BundleExtractor & extractor,const std::string & cpuAbi,std::vector<std::string> & soEntryFiles)985 bool InstalldOperator::ObtainNativeSoFile(const BundleExtractor &extractor, const std::string &cpuAbi,
986 std::vector<std::string> &soEntryFiles)
987 {
988 std::vector<std::string> entryNames;
989 if (!extractor.GetZipFileNames(entryNames)) {
990 return false;
991 }
992 if (entryNames.empty()) {
993 return false;
994 }
995
996 for (const auto &entryName : entryNames) {
997 if (strcmp(entryName.c_str(), ".") == 0 ||
998 strcmp(entryName.c_str(), "..") == 0) {
999 continue;
1000 }
1001 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
1002 continue;
1003 }
1004 // save native so file entryName in the hap
1005 if (IsNativeSo(entryName, cpuAbi)) {
1006 soEntryFiles.emplace_back(entryName);
1007 continue;
1008 }
1009 }
1010 return true;
1011 }
1012
MoveFiles(const std::string & srcDir,const std::string & desDir)1013 bool InstalldOperator::MoveFiles(const std::string &srcDir, const std::string &desDir)
1014 {
1015 APP_LOGD("srcDir is %{public}s, desDir is %{public}s", srcDir.c_str(), desDir.c_str());
1016 if (srcDir.empty() || desDir.empty()) {
1017 APP_LOGE("move file failed due to srcDir or desDir is empty");
1018 return false;
1019 }
1020
1021 std::string realPath = "";
1022 if (!PathToRealPath(srcDir, realPath)) {
1023 APP_LOGE("srcDir(%{public}s) is not real path", srcDir.c_str());
1024 return false;
1025 }
1026
1027 std::string realDesDir = "";
1028 if (!PathToRealPath(desDir, realDesDir)) {
1029 APP_LOGE("desDir(%{public}s) is not real path", desDir.c_str());
1030 return false;
1031 }
1032
1033 DIR* directory = opendir(realPath.c_str());
1034 if (directory == nullptr) {
1035 APP_LOGE("MoveFiles open dir(%{public}s) fail", realPath.c_str());
1036 return false;
1037 }
1038
1039 struct dirent *ptr = nullptr;
1040 while ((ptr = readdir(directory)) != nullptr) {
1041 std::string currentName(ptr->d_name);
1042 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
1043 continue;
1044 }
1045
1046 std::string curPath = realPath + Constants::PATH_SEPARATOR + currentName;
1047 struct stat s;
1048 if ((stat(curPath.c_str(), &s) == 0) && (s.st_mode & S_IFREG)) {
1049 std::string innerDesStr = realDesDir + Constants::PATH_SEPARATOR + currentName;
1050 if (!RenameFile(curPath, innerDesStr)) {
1051 APP_LOGE("move file from curPath(%{public}s) to desPath(%{public}s) failed", curPath.c_str(),
1052 innerDesStr.c_str());
1053 closedir(directory);
1054 return false;
1055 }
1056 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1057 OHOS::ChangeModeFile(innerDesStr, mode);
1058 }
1059 }
1060 closedir(directory);
1061 return true;
1062 }
1063
ExtractResourceFiles(const ExtractParam & extractParam,const BundleExtractor & extractor)1064 bool InstalldOperator::ExtractResourceFiles(const ExtractParam &extractParam, const BundleExtractor &extractor)
1065 {
1066 APP_LOGD("ExtractResourceFiles begin");
1067 std::string targetDir = extractParam.targetPath;
1068 if (!MkRecursiveDir(targetDir, true)) {
1069 APP_LOGE("create targetDir failed");
1070 return false;
1071 }
1072 std::vector<std::string> entryNames;
1073 if (!extractor.GetZipFileNames(entryNames)) {
1074 APP_LOGE("GetZipFileNames failed");
1075 return false;
1076 }
1077 for (const auto &entryName : entryNames) {
1078 if (StartsWith(entryName, Constants::LIBS)
1079 || StartsWith(entryName, Constants::AN)
1080 || StartsWith(entryName, Constants::AP)) {
1081 continue;
1082 }
1083 const std::string relativeDir = GetPathDir(entryName);
1084 if (!relativeDir.empty()) {
1085 if (!MkRecursiveDir(targetDir + relativeDir, true)) {
1086 APP_LOGE("MkRecursiveDir failed");
1087 return false;
1088 }
1089 }
1090 std::string filePath = targetDir + entryName;
1091 if (!extractor.ExtractFile(entryName, filePath)) {
1092 APP_LOGE("ExtractFile failed");
1093 return false;
1094 }
1095 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1096 if (!OHOS::ChangeModeFile(filePath, mode)) {
1097 APP_LOGE("change mode failed");
1098 return false;
1099 }
1100 }
1101 APP_LOGD("ExtractResourceFiles success");
1102 return true;
1103 }
1104 } // namespace AppExecFwk
1105 } // namespace OHOS