1 /*
2 * Copyright (c) 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 "module_file.h"
17
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <dlfcn.h>
22
23 #include "json_node.h"
24 #include "log/log.h"
25 #include "module_constants.h"
26 #include "module_utils.h"
27 #include "module_zip_helper.h"
28 #include "package/package.h"
29 #include "scope_guard.h"
30 #include "securec.h"
31 #include "string_ex.h"
32 #include "unique_fd.h"
33 #include "utils.h"
34
35 #ifdef SUPPORT_HVB
36 #include "hvb.h"
37 #include "hvb_footer.h"
38 #include "module_hvb_ops.h"
39 #endif
40
41 namespace OHOS {
42 namespace SysInstaller {
43 using namespace Updater;
44 using std::string;
45
46 namespace {
47 constexpr const char *JSON_NODE_NAME = "name";
48 constexpr const char *JSON_NODE_SAID = "id";
49 constexpr const char *JSON_NODE_VERSION = "version";
50 constexpr const char *VERSION_DELIMITER = ".";
51 constexpr size_t API_VERSION_INDEX = 0;
52 constexpr size_t VERSION_CODE_INDEX = 1;
53 constexpr size_t PATCH_VERSION_INDEX = 2;
54 constexpr size_t VERSION_VECTOR_SIZE = 3;
55 constexpr size_t PACKINFO_VERSION_VECTOR_SIZE = 5;
56
57 struct FsMagic {
58 const char *type;
59 int32_t offset;
60 int16_t len;
61 const char *magic;
62 };
63 constexpr const FsMagic FS_TYPES[] = {{"f2fs", 1024, 4, "\x10\x20\xF5\xF2"},
64 {"ext4", 1080, 2, "\x53\xEF"}};
65
RetrieveFsType(int fd,uint32_t imageOffset)66 const char *RetrieveFsType(int fd, uint32_t imageOffset)
67 {
68 for (const auto &fs : FS_TYPES) {
69 uint8_t buf[fs.len];
70 if (!ReadFullyAtOffset(fd, buf, fs.len, imageOffset + fs.offset)) {
71 LOG(ERROR) << "Couldn't read filesystem magic";
72 return nullptr;
73 }
74 if (memcmp(buf, fs.magic, fs.len) == 0) {
75 return fs.type;
76 }
77 }
78 LOG(ERROR) << "Couldn't find filesystem magic";
79 return nullptr;
80 }
81
ParseImageStat(ModuleZipHelper & helper,const string & path,ImageStat & imageStat)82 bool ParseImageStat(ModuleZipHelper &helper, const string &path, ImageStat &imageStat)
83 {
84 if (!helper.LocateFile(IMG_FILE_NAME)) {
85 LOG(ERROR) << "Could not find " << IMG_FILE_NAME << " in package " << path;
86 return false;
87 }
88 if (!helper.GetFileOffset(imageStat.imageOffset)) {
89 LOG(ERROR) << "Failed to get file offset from package " << path;
90 return false;
91 }
92 if (!helper.GetFileSize(imageStat.imageSize)) {
93 LOG(ERROR) << "Failed to get file size from package " << path;
94 return false;
95 }
96
97 string realPath = GetRealPath(path);
98 if (realPath.empty()) {
99 LOG(ERROR) << "Invalid path " << path;
100 return false;
101 }
102 UniqueFd fd(open(realPath.c_str(), O_RDONLY | O_CLOEXEC));
103 if (fd.Get() == -1) {
104 LOG(ERROR) << "Failed to open package " << path << ": I/O error";
105 return false;
106 }
107 const char *fsTypePtr = RetrieveFsType(fd.Get(), imageStat.imageOffset);
108 if (fsTypePtr == nullptr) {
109 LOG(ERROR) << "Failed to get fs type " << path;
110 return false;
111 }
112 errno_t ret = strcpy_s(imageStat.fsType, FS_TYPE_MAX_SIZE, fsTypePtr);
113 if (ret != EOK) {
114 LOG(ERROR) << "Failed to copy fs type " << fsTypePtr;
115 return false;
116 }
117 return true;
118 }
119
ParseModuleInfo(const string & moduleInfo,string & saName,int32_t & saId,ModuleVersion & versionInfo)120 bool ParseModuleInfo(const string &moduleInfo, string &saName, int32_t &saId, ModuleVersion &versionInfo)
121 {
122 JsonNode root(moduleInfo);
123
124 std::optional<string> name = root[JSON_NODE_NAME].As<string>();
125 if (!name.has_value()) {
126 LOG(ERROR) << "Failed to get name string";
127 return false;
128 }
129 saName = name.value();
130
131 std::optional<int> optionalSaId = root[JSON_NODE_SAID].As<int>();
132 if (!optionalSaId.has_value()) {
133 LOG(ERROR) << "Failed to get saId";
134 return false;
135 }
136 saId = static_cast<int32_t>(optionalSaId.value());
137
138 std::optional<string> versionStr = root[JSON_NODE_VERSION].As<string>();
139 if (!versionStr.has_value()) {
140 LOG(ERROR) << "Failed to get version string";
141 return false;
142 }
143 std::vector<string> versionVec;
144 SplitStr(versionStr.value(), VERSION_DELIMITER, versionVec);
145 if (versionVec.size() != VERSION_VECTOR_SIZE) {
146 LOG(ERROR) << "invalid version " << versionStr.value();
147 return false;
148 }
149 versionInfo.apiVersion = static_cast<uint32_t>(std::stoi(versionVec.at(API_VERSION_INDEX)));
150 versionInfo.versionCode = static_cast<uint32_t>(std::stoi(versionVec.at(VERSION_CODE_INDEX)));
151 versionInfo.patchVersion = static_cast<uint32_t>(std::stoi(versionVec.at(PATCH_VERSION_INDEX)));
152
153 LOG(INFO) << "ParseModuleInfo success. name: " << saName << " saId: " << saId << " version: " <<
154 static_cast<string>(versionInfo);
155 return true;
156 }
157 } // namespace
158
ExtractZipFile(ModuleZipHelper & helper,const string & fileName,string & buf)159 bool ExtractZipFile(ModuleZipHelper &helper, const string &fileName, string &buf)
160 {
161 if (!helper.LocateFile(fileName)) {
162 LOG(ERROR) << "Could not find " << fileName;
163 return false;
164 }
165 if (!helper.GetFileContent(buf)) {
166 LOG(ERROR) << "Failed to get content of " << fileName;
167 return false;
168 }
169 return true;
170 }
171
ComparePackInfoVer(const std::vector<std::string> & smallVersion,const std::vector<std::string> & bigVersion)172 __attribute__((unused)) bool ComparePackInfoVer(const std::vector<std::string> &smallVersion,
173 const std::vector<std::string> &bigVersion)
174 {
175 if (smallVersion.size() != PACKINFO_VERSION_VECTOR_SIZE || bigVersion.size() != PACKINFO_VERSION_VECTOR_SIZE) {
176 LOG(ERROR) << "invalid smallVersion " << smallVersion.size() << " invalid bigVersion " << bigVersion.size();
177 return false;
178 }
179 if (smallVersion[0] != bigVersion[0]) {
180 LOG(ERROR) << "pre " << smallVersion[0] << " not same as pkg " << bigVersion[0];
181 return false;
182 }
183
184 for (size_t i = 1; i < PACKINFO_VERSION_VECTOR_SIZE; i++) {
185 uint32_t smallVer = static_cast<uint32_t>(std::stoi(smallVersion.at(i)));
186 uint32_t bigVer = static_cast<uint32_t>(std::stoi(bigVersion.at(i)));
187 if (smallVer > bigVer) {
188 return false;
189 } else if (smallVer < bigVer) {
190 return true;
191 }
192 }
193 // same
194 return true;
195 }
196
ParseVersion(const std::string & version,const std::string & split,std::vector<std::string> & versionVec)197 __attribute__((unused)) bool ParseVersion(const std::string &version, const std::string &split,
198 std::vector<std::string> &versionVec)
199 {
200 size_t index = version.rfind(split);
201 if (index == std::string::npos) {
202 LOG(ERROR) << "ParseVersion failed " << version;
203 return false;
204 }
205 versionVec.emplace_back(version.substr(0, index));
206 std::string versionNumber = version.substr(index + split.length());
207
208 std::vector<std::string> tmpVersionVec = Utils::SplitString(versionNumber, "."); // xxx-d01_4.10.0.1
209 if (tmpVersionVec.size() != 4) { // 4: version number size
210 LOG(ERROR) << version << " is not right";
211 return false;
212 }
213 versionVec.insert(versionVec.end(), tmpVersionVec.begin(), tmpVersionVec.end());
214 return true;
215 }
216
VerifyModulePackageSign(const std::string & path)217 __attribute__((weak)) int32_t VerifyModulePackageSign(const std::string &path)
218 {
219 LOG(INFO) << "VerifyModulePackageSign " << path;
220 return VerifyPackage(path.c_str(), Utils::GetCertName().c_str(), "", nullptr, 0);
221 }
222
Open(const string & path)223 std::unique_ptr<ModuleFile> ModuleFile::Open(const string &path)
224 {
225 ModuleZipHelper helper(path);
226 if (!helper.IsValid()) {
227 LOG(ERROR) << "Failed to open file " << path;
228 return nullptr;
229 }
230
231 string moduleInfo;
232 if (!ExtractZipFile(helper, CONFIG_FILE_NAME, moduleInfo)) {
233 LOG(ERROR) << "Failed to extract " << CONFIG_FILE_NAME << " from package " << path;
234 return nullptr;
235 }
236 string saName;
237 int32_t saId = 0;
238 ModuleVersion versionInfo;
239 if (!ParseModuleInfo(moduleInfo, saName, saId, versionInfo)) {
240 LOG(ERROR) << "Failed to parse version info of package " << path;
241 return nullptr;
242 }
243
244 ImageStat tmpStat;
245 std::optional<ImageStat> imageStat;
246 if (ParseImageStat(helper, path, tmpStat)) {
247 imageStat = std::move(tmpStat);
248 } else if (!StartsWith(path, MODULE_PREINSTALL_DIR)) {
249 LOG(ERROR) << "Update package without image " << path;
250 return nullptr;
251 }
252
253 string modulePubkey = "";
254 #ifdef SUPPORT_HVB
255 if (!ExtractZipFile(helper, PUBLIC_KEY_NAME, modulePubkey)) {
256 LOG(ERROR) << "Failed to extract pubkey from package " << path;
257 return nullptr;
258 }
259 if (modulePubkey.empty()) {
260 LOG(ERROR) << "Public key is empty in " << path;
261 return nullptr;
262 }
263 #endif
264
265 return std::make_unique<ModuleFile>(path, saName, saId, versionInfo, modulePubkey, imageStat);
266 }
267
CompareVersion(const ModuleFile & file1,const ModuleFile & file2)268 bool ModuleFile::CompareVersion(const ModuleFile &file1, const ModuleFile &file2)
269 {
270 ModuleVersion version1 = file1.GetVersionInfo();
271 ModuleVersion version2 = file2.GetVersionInfo();
272 if (version1.apiVersion != version2.apiVersion) {
273 return false;
274 }
275 if (version1.versionCode != version2.versionCode) {
276 return version1.versionCode > version2.versionCode;
277 }
278 return version1.patchVersion >= version2.patchVersion;
279 }
280
VerifyModuleVerity(const string & publicKey)281 bool ModuleFile::VerifyModuleVerity(const string &publicKey)
282 {
283 #ifdef SUPPORT_HVB
284 if (vd_ != nullptr) {
285 LOG(INFO) << "already verified verity";
286 return true;
287 }
288 struct hvb_buf pubkey;
289 vd_ = hvb_init_verified_data();
290 if (vd_ == nullptr) {
291 LOG(ERROR) << "init verified data failed";
292 return false;
293 }
294 ON_SCOPE_EXIT(clear) {
295 ClearVerifiedData();
296 };
297 enum hvb_errno ret = footer_init_desc(ModuleHvbGetOps(), GetPath().c_str(), nullptr, &pubkey, vd_);
298 if (ret != HVB_OK) {
299 LOG(ERROR) << "hvb verify failed err=" << ret;
300 return false;
301 }
302
303 CANCEL_SCOPE_EXIT_GUARD(clear);
304 return true;
305 #else
306 LOG(INFO) << "do not support hvb";
307 return true;
308 #endif
309 }
310
ClearVerifiedData()311 void ModuleFile::ClearVerifiedData()
312 {
313 #ifdef SUPPORT_HVB
314 if (vd_ != nullptr) {
315 hvb_chain_verify_data_free(vd_);
316 vd_ = nullptr;
317 }
318 #endif
319 }
320 } // namespace SysInstaller
321 } // namespace OHOS