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