1 /*
2 * Copyright (c) 2024 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 #include <fstream>
16 #include <sys/mount.h>
17 #include "i18n_hilog.h"
18 #include "signature_verifier.h"
19 #include "utils.h"
20 #include "upgrade_utils.h"
21
22 namespace OHOS {
23 namespace Global {
24 namespace I18n {
25 const std::string UpgradeUtils::CERT_FILE = "CERT.ENC";
26 const std::string UpgradeUtils::VERIFY_FILE = "CERT.SF";
27 const std::string UpgradeUtils::MANIFEST_FILE = "MANIFEST.MF";
28 const size_t UpgradeUtils::VERSION_SIZE = 4;
29
CheckIfUpdateNecessary(const std::string & updateVersionPath,const std::string & localVersionPath)30 bool UpgradeUtils::CheckIfUpdateNecessary(const std::string& updateVersionPath, const std::string& localVersionPath)
31 {
32 std::string versionUpdate = LoadFileVersion(updateVersionPath);
33 std::string versionLocal = LoadFileVersion(localVersionPath);
34 HILOG_INFO_I18N("UpgradeUtils::CheckIfUpdateNecessary: versionUpdate(%{public}s) versionLocal(%{public}s).",
35 versionUpdate.c_str(), versionLocal.c_str());
36
37 if (versionLocal.empty() || versionUpdate.empty()) {
38 return false;
39 }
40 return CompareVersion(versionLocal, versionUpdate);
41 }
42
CheckFileIntegrity(const std::string & cfgPath,const std::string & pubkeyPath,std::vector<std::string> & filesList)43 bool UpgradeUtils::CheckFileIntegrity(const std::string& cfgPath, const std::string& pubkeyPath,
44 std::vector<std::string>& filesList)
45 {
46 std::string certPath = cfgPath + CERT_FILE;
47 std::string verifyPath = cfgPath + VERIFY_FILE;
48 std::string manifestPath = cfgPath + MANIFEST_FILE;
49 if (!SignatureVerifier::VerifyCertFile(certPath, verifyPath, pubkeyPath, manifestPath)) {
50 HILOG_ERROR_I18N("UpgradeUtils::CheckFileIntegrity: VerifyCertFile error.");
51 return false;
52 }
53 return SignatureVerifier::VerifyUpdateFile(cfgPath, manifestPath, filesList);
54 }
55
CopyDataFile(const std::string & srcPath,const std::string & dstPath,const std::vector<std::string> & filesList)56 bool UpgradeUtils::CopyDataFile(const std::string& srcPath, const std::string& dstPath,
57 const std::vector<std::string>& filesList)
58 {
59 if (!IsDirExist(dstPath.c_str())) {
60 HILOG_ERROR_I18N("UpgradeUtils::CopyDataFile: dstPath is not exist.");
61 return false;
62 }
63
64 std::filesystem::path dstPathDir(dstPath);
65 ClearDir(dstPathDir);
66
67 bool copySuccess = true;
68 for (const auto& file : filesList) {
69 std::filesystem::path srcFile = std::filesystem::path(srcPath) / file;
70 std::filesystem::path dstFile = std::filesystem::path(dstPath) / file;
71 if (!CopySingleFile(srcFile, dstFile)) {
72 HILOG_ERROR_I18N("UpgradeUtils::CopyDataFile: Copy failed for %{public}s.", file.c_str());
73 copySuccess = false;
74 break;
75 }
76 }
77
78 if (!copySuccess) {
79 HILOG_ERROR_I18N("UpgradeUtils::CopyDataFile: CopyDataFile error, clearing the safe directory...");
80 ClearDir(dstPathDir);
81 }
82
83 return copySuccess;
84 }
85
FileDirMount(const std::string & srcDirPath,const std::string & dstDirPath)86 bool UpgradeUtils::FileDirMount(const std::string& srcDirPath, const std::string& dstDirPath)
87 {
88 if (!IsDirExist(srcDirPath.c_str()) || !IsDirExist(dstDirPath.c_str())) {
89 HILOG_ERROR_I18N("UpgradeUtils::FileDirMount: srcDirPath or dstDirPath not exist.");
90 return false;
91 }
92
93 std::string cotaOpkeyVersionDir = srcDirPath;
94 std::string custOpkeyVersionDir = dstDirPath;
95
96 if (mount(cotaOpkeyVersionDir.c_str(), custOpkeyVersionDir.c_str(), nullptr, MS_BIND, nullptr) != 0) {
97 HILOG_ERROR_I18N("UpgradeUtils::FileDirMount: Fail to mount, errno %{public}s.", strerror(errno));
98 return false;
99 }
100
101 if (mount(nullptr, custOpkeyVersionDir.c_str(), nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr) != 0) {
102 HILOG_ERROR_I18N("UpgradeUtils::FileDirMount: Fail to mount read only, errno %{public}s.", strerror(errno));
103 if (umount(custOpkeyVersionDir.c_str()) != 0) {
104 HILOG_ERROR_I18N("UpgradeUtils::FileDirMount: Error during unmount, errno %{public}s.", strerror(errno));
105 }
106 return false;
107 }
108
109 HILOG_INFO_I18N("UpgradeUtils::FileDirMount: Succeeded in mounting the file path.");
110 return true;
111 }
112
LoadFileVersion(const std::string & versionPath)113 std::string UpgradeUtils::LoadFileVersion(const std::string& versionPath)
114 {
115 std::string version;
116 char* result = realpath(versionPath.c_str(), nullptr);
117 if (result == nullptr) {
118 HILOG_ERROR_I18N("UpgradeUtils::LoadFileVersion: realpath error: %{public}s.", strerror(errno));
119 return version;
120 }
121 std::ifstream file(result);
122 free(result);
123 result = nullptr;
124 if (!file.is_open()) {
125 HILOG_ERROR_I18N("UpgradeUtils::LoadFileVersion: open version file failed.");
126 return version;
127 }
128 std::string line;
129 std::vector<std::string> strs;
130 while (std::getline(file, line)) {
131 Split(line, "=", strs);
132 if (strs.size() < SignatureVerifier::MIN_SIZE) {
133 continue;
134 }
135 if (strs[0] == "version") {
136 version = trim(strs[1]);
137 break;
138 }
139 }
140 return version;
141 }
142
143 // compare version
CompareVersion(const std::string & preVersion,const std::string & curVersion)144 bool UpgradeUtils::CompareVersion(const std::string& preVersion, const std::string& curVersion)
145 {
146 std::vector<std::string> preVersionStr;
147 std::vector<std::string> curVersionStr;
148 Split(preVersion, ".", preVersionStr);
149 Split(curVersion, ".", curVersionStr);
150 if (curVersionStr.size() != VERSION_SIZE || preVersionStr.size() != VERSION_SIZE) {
151 HILOG_ERROR_I18N("UpgradeUtils::CompareVersion: Parse version failed.");
152 return false;
153 }
154 for (size_t i = 0; i < VERSION_SIZE; i++) {
155 int32_t status = 0;
156 int32_t preVersionNum = ConvertString2Int(preVersionStr.at(i), status);
157 if (status != 0) {
158 HILOG_ERROR_I18N("UpgradeUtils::CompareVersion: preVersionStr convert to int failed.");
159 return false;
160 }
161 int32_t curVersionNum = ConvertString2Int(curVersionStr.at(i), status);
162 if (status != 0) {
163 HILOG_ERROR_I18N("UpgradeUtils::CompareVersion: curVersionStr convert to int failed.");
164 return false;
165 }
166 if (preVersionNum < curVersionNum) {
167 return true;
168 } else if (preVersionNum > curVersionNum) {
169 return false;
170 }
171 }
172 return false;
173 }
174
CopySingleFile(const std::filesystem::path & srcFile,const std::filesystem::path & dstFile)175 bool UpgradeUtils::CopySingleFile(const std::filesystem::path& srcFile, const std::filesystem::path& dstFile)
176 {
177 if (!FileExist(srcFile.c_str())) {
178 HILOG_ERROR_I18N("UpgradeUtils::copySingleFile: Source file does not exist.");
179 return false;
180 }
181
182 if (!EnsureDirectoryExists(dstFile.parent_path())) {
183 HILOG_ERROR_I18N("UpgradeUtils::copySingleFile: Target file dir not exist.");
184 return false;
185 }
186 if (!FileCopy(srcFile.c_str(), dstFile.c_str())) {
187 HILOG_ERROR_I18N("UpgradeUtils::copySingleFile: Failed to copy file.");
188 return false;
189 }
190 return true;
191 }
192
EnsureDirectoryExists(const std::filesystem::path & dirPath)193 bool UpgradeUtils::EnsureDirectoryExists(const std::filesystem::path& dirPath)
194 {
195 std::error_code errCode;
196 if (!std::filesystem::exists(dirPath)) {
197 std::filesystem::create_directories(dirPath, errCode);
198 if (errCode) {
199 HILOG_ERROR_I18N("UpgradeUtils::EnsureDirectoryExists: failed to create directory, Error %{public}s",
200 errCode.message().c_str());
201 return false;
202 }
203 }
204 return true;
205 }
206 }
207 }
208 }