• 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 <memory>
25 #include <vector>
26 #include "applypatch/block_set.h"
27 #include "applypatch/store.h"
28 #include "applypatch/transfer_manager.h"
29 #include "applypatch/partition_record.h"
30 #include "diffpatch/diffpatch.h"
31 #include "dump.h"
32 #include "fs_manager/mount.h"
33 #include "log/log.h"
34 #include "patch/update_patch.h"
35 #include "updater/updater_const.h"
36 #include "updater/hardware_fault_retry.h"
37 #include "utils.h"
38 #include "slot_info/slot_info.h"
39 
40 using namespace Uscript;
41 using namespace Hpackage;
42 using namespace Updater;
43 
44 namespace Updater {
45 constexpr uint32_t IMAGE_PATCH_CMD_LEN = 6;
46 constexpr uint32_t IMAGE_PATCH_CHECK_CMD_LEN = 5;
47 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)48 int32_t USInstrImagePatch::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
49 {
50     int32_t result = ExecuteImagePatch(env, context);
51     context.PushParam(result);
52     return result;
53 }
54 
GetParam(Uscript::UScriptContext & context,ImagePatchPara & para)55 int32_t USInstrImagePatch::GetParam(Uscript::UScriptContext &context, ImagePatchPara &para)
56 {
57     if (context.GetParamCount() != IMAGE_PATCH_CMD_LEN) {
58         LOG(ERROR) << "para count error " << context.GetParamCount();
59         return USCRIPT_INVALID_PARAM;
60     }
61 
62     int index = 0;
63     uint32_t ret = static_cast<uint32_t>(context.GetParam(index++, para.partName));
64     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcSize));
65     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcHash));
66     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destSize));
67     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destHash));
68     ret |= static_cast<uint32_t>(context.GetParam(index++, para.patchFile));
69     if (ret != USCRIPT_SUCCESS) {
70         LOG(ERROR) << "para get error";
71         return USCRIPT_INVALID_PARAM;
72     }
73     para.devPath = GetBlockDeviceByMountPoint(para.partName);
74 #ifndef UPDATER_UT
75     if (para.partName != "/userdata") {
76         std::string suffix = Utils::GetUpdateSuffix();
77         para.devPath += suffix;
78     }
79 #else
80     para.devPath = "/data/updater" + para.partName;
81 #endif
82     if (para.devPath.empty()) {
83         LOG(ERROR) << "get " << para.partName << " dev path error";
84         return USCRIPT_ERROR_EXECUTE;
85     }
86     return USCRIPT_SUCCESS;
87 }
88 
GetFileHash(const std::string & file)89 std::string USInstrImagePatch::GetFileHash(const std::string &file)
90 {
91     UpdatePatch::MemMapInfo mapBuffer {};
92     if (PatchMapFile(file, mapBuffer) != UpdatePatch::PATCH_SUCCESS) {
93         LOG(ERROR) << "PatchMapFile error";
94         return "";
95     }
96     UpdatePatch::BlockBuffer data = { mapBuffer.memory, mapBuffer.length };
97     std::string resultSha = UpdatePatch::GeneraterBufferHash(data);
98     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::toupper);
99     return resultSha;
100 }
101 
ApplyPatch(const ImagePatchPara & para,const UpdatePatch::MemMapInfo & srcData,const PkgBuffer & patchData)102 int32_t USInstrImagePatch::ApplyPatch(const ImagePatchPara &para, const UpdatePatch::MemMapInfo &srcData,
103     const PkgBuffer &patchData)
104 {
105     std::vector<uint8_t> empty;
106     UpdatePatch::PatchParam patchParam = {
107         srcData.memory, srcData.length, patchData.buffer, patchData.length
108     };
109     std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_RAW, para.devPath);
110     if (writer.get() == nullptr) {
111         LOG(ERROR) << "Cannot create block writer, pkgdiff patch abort!";
112         return -1;
113     }
114     std::string resultSha = para.destHash;
115     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::tolower);
116     int32_t ret = UpdatePatch::UpdateApplyPatch::ApplyImagePatch(patchParam, empty,
117         [&](size_t start, const UpdatePatch::BlockBuffer &data, size_t size) -> int {
118             return (writer->Write(data.buffer, size, nullptr)) ? 0 : -1;
119         }, resultSha);
120     writer.reset();
121     if (ret != 0) {
122         LOG(ERROR) << "Fail to ApplyImagePatch";
123         return -1;
124     }
125     return USCRIPT_SUCCESS;
126 }
127 
CreatePatchStream(Uscript::UScriptEnv & env,const ImagePatchPara & para,PkgManager::StreamPtr & patchStream)128 int32_t USInstrImagePatch::CreatePatchStream(Uscript::UScriptEnv &env, const ImagePatchPara &para,
129     PkgManager::StreamPtr &patchStream)
130 {
131     if (env.GetPkgManager() == nullptr) {
132         LOG(ERROR) << "Error to get pkg manager";
133         return -1;
134     }
135 
136     std::string patchName = para.patchFile;
137     const FileInfo *info = env.GetPkgManager()->GetFileInfo(patchName);
138     if (info == nullptr) {
139         LOG(WARNING) << "Error to get file info " << para.patchFile; // 兼容旧升级包
140         patchName = para.partName;
141         info = env.GetPkgManager()->GetFileInfo(patchName);
142         if (info == nullptr) {
143             return -1;
144         }
145     }
146 
147     std::string patchFile = UPDATER_PATH + para.patchFile;
148     int32_t ret = env.GetPkgManager()->CreatePkgStream(patchStream,
149         patchFile, info->unpackedSize, PkgStream::PkgStreamType_MemoryMap);
150     if (ret != PKG_SUCCESS || patchStream == nullptr) {
151         LOG(ERROR) << "Error to create output stream";
152         return -1;
153     }
154 
155     ret = env.GetPkgManager()->ExtractFile(patchName, patchStream);
156     if (ret != PKG_SUCCESS) {
157         env.GetPkgManager()->ClosePkgStream(patchStream);
158         LOG(ERROR) << "Error to extract file " << para.patchFile;
159         return -1;
160     }
161 
162     LOG(INFO) << "USInstrImagePatch::CreatePatchStream " << para.partName;
163     return USCRIPT_SUCCESS;
164 }
165 
GetSourceFile(const ImagePatchPara & para)166 std::string USInstrImagePatch::GetSourceFile(const ImagePatchPara &para)
167 {
168     // Back up partitions to prevent power failures during the upgrade.
169     std::string srcFile = UPDATER_PATH + para.partName + ".backup";
170 
171     if (access(srcFile.c_str(), F_OK) == 0 && GetFileHash(srcFile) != para.srcHash) {
172         LOG(INFO) << "using backup file:" << srcFile;
173         return srcFile;
174     }
175 
176     if (!Utils::CopyFile(para.devPath, srcFile)) {
177         LOG(ERROR) << "copy " << para.devPath << " to " << srcFile << " failed";
178         return "";
179     }
180     return srcFile;
181 }
182 
ExecuteImagePatch(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)183 int32_t USInstrImagePatch::ExecuteImagePatch(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
184 {
185     UPDATER_INIT_RECORD;
186     ImagePatchPara para {};
187     int32_t ret = GetParam(context, para);
188     if (ret != USCRIPT_SUCCESS) {
189         UPDATER_LAST_WORD(ret, "GetParam error");
190         LOG(ERROR) << "GetParam error";
191         return ret;
192     }
193 
194     if (env.IsRetry()) {
195         LOG(DEBUG) << "Retry updater, check if current partition updatered already during last time";
196         if (PartitionRecord::GetInstance().IsPartitionUpdated(para.partName)) {
197             LOG(INFO) << para.partName << " already updated, skip";
198             return USCRIPT_SUCCESS;
199         }
200     }
201 
202     std::string srcFile = GetSourceFile(para);
203     if (srcFile.empty()) {
204         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE, "get source file error");
205         LOG(ERROR) << "get source file error";
206         return USCRIPT_ERROR_EXECUTE;
207     }
208     UpdatePatch::MemMapInfo srcData {};
209     ret = UpdatePatch::PatchMapFile(srcFile, srcData);
210     if (ret != 0) {
211         UPDATER_LAST_WORD(ret, "Failed to mmap src file error");
212         LOG(ERROR) << "Failed to mmap src file error:" << ret;
213         return -1;
214     }
215 
216     PkgManager::StreamPtr patchStream = nullptr;
217     ret = CreatePatchStream(env, para, patchStream);
218     if (ret != USCRIPT_SUCCESS) {
219         UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE, "CreatePatchStream error");
220         LOG(ERROR) << "CreatePatchStream error";
221         return USCRIPT_ERROR_EXECUTE;
222     }
223     PkgBuffer patchData = {};
224     patchStream->GetBuffer(patchData);
225 
226     ret = ApplyPatch(para, srcData, patchData);
227     if (ret != USCRIPT_SUCCESS) {
228         env.GetPkgManager()->ClosePkgStream(patchStream);
229         return ret;
230     }
231 
232     PartitionRecord::GetInstance().RecordPartitionUpdateStatus(para.partName, true);
233     env.GetPkgManager()->ClosePkgStream(patchStream);
234     unlink(srcFile.c_str());
235     LOG(INFO) << "USInstrImageCheck::Execute ret:" << ret;
236     return ret;
237 }
238 
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)239 int32_t USInstrImageShaCheck::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
240 {
241     int32_t result = ExecuteShaCheck(env, context);
242     context.PushParam(result);
243     return result;
244 }
245 
GetParam(Uscript::UScriptContext & context,CheckPara & para)246 int32_t USInstrImageShaCheck::GetParam(Uscript::UScriptContext &context, CheckPara &para)
247 {
248     if (context.GetParamCount() != IMAGE_PATCH_CHECK_CMD_LEN) {
249         LOG(ERROR) << "para count error " << context.GetParamCount();
250         return USCRIPT_INVALID_PARAM;
251     }
252     int index = 0;
253     uint32_t ret = static_cast<uint32_t>(context.GetParam(index++, para.partName));
254     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcSize));
255     ret |= static_cast<uint32_t>(context.GetParam(index++, para.srcHash));
256     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destSize));
257     ret |= static_cast<uint32_t>(context.GetParam(index++, para.destHash));
258     if (ret != USCRIPT_SUCCESS) {
259         LOG(ERROR) << "para get error";
260         return USCRIPT_INVALID_PARAM;
261     }
262 
263     para.devPath = GetBlockDeviceByMountPoint(para.partName);
264 #ifndef UPDATER_UT
265     if (para.partName != "/userdata") {
266         std::string suffix = Utils::GetUpdateSuffix();
267         para.devPath += suffix;
268     }
269 #else
270     para.devPath = "/data/updater" + para.partName;
271 #endif
272     if (para.devPath.empty()) {
273         LOG(ERROR) << "cannot get block device of partition" << para.partName;
274         return USCRIPT_ERROR_EXECUTE;
275     }
276     LOG(INFO) << "dev path: " << para.devPath;
277     return USCRIPT_SUCCESS;
278 }
279 
CheckHash(const CheckPara & para)280 int32_t USInstrImageShaCheck::CheckHash(const CheckPara &para)
281 {
282     UpdatePatch::MemMapInfo mapBuffer {};
283     if (PatchMapFile(para.devPath, mapBuffer) != UpdatePatch::PATCH_SUCCESS) {
284         LOG(ERROR) << "PatchMapFile error";
285         return USCRIPT_ERROR_EXECUTE;
286     }
287     if (!std::all_of(para.srcSize.begin(), para.srcSize.end(), ::isdigit)) {
288         LOG(ERROR) << "para size error " << para.srcSize;
289         return USCRIPT_ERROR_EXECUTE;
290     }
291     uint32_t length = 0;
292     if (!Utils::ConvertToUnsignedLong(para.srcSize, length)) {
293         LOG(ERROR) << "ConvertToUnsignedLong error";
294         return USCRIPT_ERROR_EXECUTE;
295     }
296     UpdatePatch::BlockBuffer data = { mapBuffer.memory, length };
297     std::string resultSha = UpdatePatch::GeneraterBufferHash(data);
298     std::transform(resultSha.begin(), resultSha.end(), resultSha.begin(), ::toupper);
299     if (resultSha != para.srcHash) {
300         LOG(ERROR) << "resultSha:" << resultSha << " srcHash:" << para.srcHash;
301         return USCRIPT_INVALID_PARAM;
302     }
303     return USCRIPT_SUCCESS;
304 }
305 
ExecuteShaCheck(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)306 int32_t USInstrImageShaCheck::ExecuteShaCheck(Uscript::UScriptEnv &env, Uscript::UScriptContext &context)
307 {
308     UPDATER_INIT_RECORD;
309     if (env.IsRetry() && !Utils::CheckFaultInfo(VERIFY_FAILED_REBOOT)) {
310         return USCRIPT_SUCCESS;
311     }
312 
313     CheckPara para {};
314     int32_t ret = GetParam(context, para);
315     if (ret != USCRIPT_SUCCESS) {
316         UPDATER_LAST_WORD(ret, "GetParam error");
317         LOG(ERROR) << "GetParam error";
318         return ret;
319     }
320 
321     ret = CheckHash(para);
322     if (ret != USCRIPT_SUCCESS) {
323         UPDATER_LAST_WORD(ret, "CheckHash error");
324         env.PostMessage(UPDATER_RETRY_TAG, VERIFY_FAILED_REBOOT);
325         LOG(ERROR) << "CheckHash error";
326         return ret;
327     }
328 
329     LOG(INFO) << "USInstrImageCheck::Execute Success";
330     return USCRIPT_SUCCESS;
331 }
332 }
333 
334