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