• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "update_image_patch.h"
16 #include <cerrno>
17 #include <fcntl.h>
18 #include <pthread.h>
19 #include <sstream>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include "applypatch/block_set.h"
25 #include "applypatch/store.h"
26 #include "applypatch/transfer_manager.h"
27 #include "applypatch/partition_record.h"
28 #include "diffpatch/diffpatch.h"
29 #include "dump.h"
30 #include "fs_manager/mount.h"
31 #include "log/log.h"
32 #include "patch/update_patch.h"
33 #include "updater/updater_const.h"
34 #include "utils.h"
35 
36 using namespace Uscript;
37 using namespace Hpackage;
38 using namespace Updater;
39 
40 namespace Updater {
41 constexpr uint32_t IMAGE_PATCH_CMD_LEN = 6;
42 constexpr uint32_t IMAGE_PATCH_CHECK_CMD_LEN = 5;
43 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)44 int32_t USInstrImagePatch::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
45 {
46     int32_t result = ExecuteImagePatch(env, context);
47     context.PushParam(result);
48     return result;
49 }
50 
GetParam(Uscript::UScriptContext & context,ImagePatchPara & para)51 int32_t USInstrImagePatch::GetParam(Uscript::UScriptContext &context, ImagePatchPara &para)
52 {
53     if (context.GetParamCount() != IMAGE_PATCH_CMD_LEN) {
54         LOG(ERROR) << "para count error " << context.GetParamCount();
55         return USCRIPT_INVALID_PARAM;
56     }
57 
58     int index = 0;
59     uint32_t ret = static_cast<uint32_t>(context.GetParam(index++, para.partName));
60     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcSize));
61     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcHash));
62     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destSize));
63     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destHash));
64     ret |= static_cast<uint32_t>(context.GetParam(index++, para.patchFile));
65     if (ret != USCRIPT_SUCCESS) {
66         LOG(ERROR) << "para get error";
67         return USCRIPT_INVALID_PARAM;
68     }
69     para.devPath = GetBlockDeviceByMountPoint(para.partName);
70     if (para.devPath.empty()) {
71         LOG(ERROR) << "get " << para.partName << " dev path error";
72         return USCRIPT_ERROR_EXECUTE;
73     }
74     return USCRIPT_SUCCESS;
75 }
76 
GetFileHash(const std::string & file)77 std::string USInstrImagePatch::GetFileHash(const std::string &file)
78 {
79     UpdatePatch::MemMapInfo mapBuffer {};
80     if (PatchMapFile(file, mapBuffer) != UpdatePatch::PATCH_SUCCESS) {
81         LOG(ERROR) << "PatchMapFile error";
82         return "";
83     }
84     UpdatePatch::BlockBuffer data = { mapBuffer.memory, mapBuffer.length };
85     std::string resultSha = UpdatePatch::GeneraterBufferHash(data);
86     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::toupper);
87     return resultSha;
88 }
89 
ApplyPatch(const ImagePatchPara & para,const std::string & patchFile)90 int32_t USInstrImagePatch::ApplyPatch(const ImagePatchPara &para, const std::string &patchFile)
91 {
92     std::string newFile = UPDATER_PATH + para.partName + ".new";
93     int32_t ret = UpdatePatch::UpdateApplyPatch::ApplyPatch(patchFile, para.devPath, newFile);
94     if (ret != UpdatePatch::PATCH_SUCCESS) {
95         UPDATER_LAST_WORD(ret);
96         LOG(ERROR) << "ApplyPatch error:" << ret;
97         return ret;
98     }
99 
100     std::string resultSha = GetFileHash(newFile);
101     if (resultSha != para.destHash) {
102         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
103         LOG(ERROR) << "apply patch fail resultSha:" << resultSha << " destHash:" << para.destHash;
104         return USCRIPT_ERROR_EXECUTE;
105     }
106 
107     if (!Utils::CopyFile(newFile, para.devPath)) {
108         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
109         LOG(ERROR) << "write " << newFile << " to " << para.devPath << " failed";
110         return USCRIPT_ERROR_EXECUTE;
111     }
112     unlink(newFile.c_str());
113     return USCRIPT_SUCCESS;
114 }
115 
GetPatchFile(Uscript::UScriptEnv & env,const ImagePatchPara & para)116 std::string USInstrImagePatch::GetPatchFile(Uscript::UScriptEnv &env, const ImagePatchPara &para)
117 {
118     if (env.GetPkgManager() == nullptr) {
119         LOG(ERROR) << "Error to get pkg manager";
120         return "";
121     }
122 
123     const FileInfo *info = env.GetPkgManager()->GetFileInfo(para.partName);
124     if (info == nullptr) {
125         LOG(ERROR) << "Error to get file info";
126         return "";
127     }
128 
129     Hpackage::PkgManager::StreamPtr outStream = nullptr;
130     std::string patchFile = UPDATER_PATH + para.partName;
131     int32_t ret = env.GetPkgManager()->CreatePkgStream(outStream,
132         patchFile, info->unpackedSize, PkgStream::PkgStreamType_Write);
133     if (ret != PKG_SUCCESS || outStream == nullptr) {
134         LOG(ERROR) << "Error to create output stream";
135         return "";
136     }
137 
138     ret = env.GetPkgManager()->ExtractFile(para.partName, outStream);
139     env.GetPkgManager()->ClosePkgStream(outStream);
140     if (ret != PKG_SUCCESS) {
141         LOG(ERROR) << "Error to extract file";
142         return "";
143     }
144 
145     LOG(INFO) << "USInstrImageShaCheck::Execute patchFile " << patchFile;
146     return patchFile;
147 }
148 
GetSourceFile(const ImagePatchPara & para)149 std::string USInstrImagePatch::GetSourceFile(const ImagePatchPara &para)
150 {
151     // Back up partitions to prevent power failures during the upgrade.
152     std::string srcFile = UPDATER_PATH + para.partName + ".backup";
153 
154     if (access(srcFile.c_str(), F_OK) == 0 && GetFileHash(srcFile) != para.srcHash) {
155         LOG(INFO) << "using backup file:" << srcFile;
156         return srcFile;
157     }
158 
159     if (!Utils::CopyFile(para.devPath, srcFile)) {
160         LOG(ERROR) << "copy " << para.devPath << " to " << srcFile << " failed";
161         return "";
162     }
163     return srcFile;
164 }
165 
ExecuteImagePatch(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)166 int32_t USInstrImagePatch::ExecuteImagePatch(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
167 {
168     ImagePatchPara para {};
169     int32_t ret = GetParam(context, para);
170     if (ret != USCRIPT_SUCCESS) {
171         UPDATER_LAST_WORD(ret);
172         LOG(ERROR) << "GetParam error";
173         return ret;
174     }
175 
176     if (env.IsRetry()) {
177         LOG(DEBUG) << "Retry updater, check if current partition updatered already during last time";
178         if (PartitionRecord::GetInstance().IsPartitionUpdated(para.partName)) {
179             LOG(INFO) << para.partName << " already updated, skip";
180             return USCRIPT_SUCCESS;
181         }
182     }
183 
184     std::string patchFile = GetPatchFile(env, para);
185     if (patchFile.empty()) {
186         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
187         LOG(ERROR) << "get patch file error";
188         return USCRIPT_ERROR_EXECUTE;
189     }
190 
191     std::string srcFile = GetSourceFile(para);
192     if (srcFile.empty()) {
193         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE);
194         LOG(ERROR) << "get source file error";
195         return USCRIPT_ERROR_EXECUTE;
196     }
197 
198     ret = ApplyPatch(para, patchFile);
199     if (ret == USCRIPT_SUCCESS) {
200         PartitionRecord::GetInstance().RecordPartitionUpdateStatus(para.partName, true);
201     }
202     unlink(patchFile.c_str());
203     unlink(srcFile.c_str());
204     LOG(INFO) << "USInstrImageCheck::Execute ret:" << ret;
205     return ret;
206 }
207 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)208 int32_t USInstrImageShaCheck::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
209 {
210     int32_t result = ExecuteShaCheck(env, context);
211     context.PushParam(result);
212     return result;
213 }
214 
GetParam(Uscript::UScriptContext & context,CheckPara & para)215 int32_t USInstrImageShaCheck::GetParam(Uscript::UScriptContext &context, CheckPara &para)
216 {
217     if (context.GetParamCount() != IMAGE_PATCH_CHECK_CMD_LEN) {
218         LOG(ERROR) << "para count error " << context.GetParamCount();
219         return USCRIPT_INVALID_PARAM;
220     }
221     int index = 0;
222     uint32_t ret = static_cast<uint32_t>(context.GetParam(index++, para.partName));
223     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcSize));
224     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcHash));
225     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destSize));
226     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destHash));
227     if (ret != USCRIPT_SUCCESS) {
228         LOG(ERROR) << "para get error";
229         return USCRIPT_INVALID_PARAM;
230     }
231 
232     para.devPath = GetBlockDeviceByMountPoint(para.partName);
233     if (para.devPath.empty()) {
234         LOG(ERROR) << "cannot get block device of partition" << para.partName;
235         return USCRIPT_ERROR_EXECUTE;
236     }
237     LOG(INFO) << "dev path: " << para.devPath;
238     return USCRIPT_SUCCESS;
239 }
240 
CheckHash(const CheckPara & para)241 int32_t USInstrImageShaCheck::CheckHash(const CheckPara &para)
242 {
243     UpdatePatch::MemMapInfo mapBuffer {};
244     if (PatchMapFile(para.devPath, mapBuffer) != UpdatePatch::PATCH_SUCCESS) {
245         LOG(ERROR) << "PatchMapFile error";
246         return USCRIPT_ERROR_EXECUTE;
247     }
248 
249     UpdatePatch::BlockBuffer data = { mapBuffer.memory, mapBuffer.length };
250     std::string resultSha = UpdatePatch::GeneraterBufferHash(data);
251     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::toupper);
252     if (resultSha != para.srcHash) {
253         LOG(ERROR) << "resultSha:" << resultSha << " srcHash:" << para.srcHash;
254         return USCRIPT_INVALID_PARAM;
255     }
256     return USCRIPT_SUCCESS;
257 }
258 
ExecuteShaCheck(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)259 int32_t USInstrImageShaCheck::ExecuteShaCheck(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
260 {
261     if (env.IsRetry()) {
262         return USCRIPT_SUCCESS;
263     }
264 
265     CheckPara para {};
266     int32_t ret = GetParam(context, para);
267     if (ret != USCRIPT_SUCCESS) {
268         UPDATER_LAST_WORD(ret);
269         LOG(ERROR) << "GetParam error";
270         return ret;
271     }
272 
273     ret = CheckHash(para);
274     if (ret != USCRIPT_SUCCESS) {
275         UPDATER_LAST_WORD(ret);
276         LOG(ERROR) << "CheckHash error";
277         return ret;
278     }
279 
280     LOG(INFO) << "USInstrImageCheck::Execute Success";
281     return USCRIPT_SUCCESS;
282 }
283 }
284 
285