• 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 
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