1 /*
2 * Copyright (c) 2021 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 "image_patch.h"
17 #include <memory>
18 #include <string>
19 #include <vector>
20 #include "diffpatch.h"
21 #include "lz4_adapter.h"
22 #include "openssl/sha.h"
23 #include "securec.h"
24 #include "zip_adapter.h"
25 #include "scope_guard.h"
26
27 using namespace Hpackage;
28 using namespace Updater;
29
30 namespace UpdatePatch {
31 uint32_t g_tmpFileId = 0;
32
ApplyImagePatch(const PatchParam ¶m, size_t &startOffset)33 int32_t NormalImagePatch::ApplyImagePatch(const PatchParam ¶m, size_t &startOffset)
34 {
35 size_t offset = startOffset;
36 if (offset + PATCH_NORMAL_MIN_HEADER_LEN > param.patchSize) {
37 PATCH_LOGE("Failed to check datalen");
38 return -1;
39 }
40
41 size_t srcStart = static_cast<size_t>(ReadLE<int64_t>(param.patch + offset));
42 offset += sizeof(int64_t);
43 size_t srcLen = static_cast<size_t>(ReadLE<int64_t>(param.patch + offset));
44 offset += sizeof(int64_t);
45 size_t patchOffset = static_cast<size_t>(ReadLE<int64_t>(param.patch + offset));
46 offset += sizeof(int64_t);
47 if (srcStart > param.oldSize || param.oldSize - srcStart < srcLen ||
48 patchOffset > param.patchSize) {
49 PATCH_LOGE("error, srcStart: %zu srcLen: %zu , param.oldSize: %zu, patchOffset: %zu",
50 srcStart, srcLen, param.oldSize, patchOffset);
51 return -1;
52 }
53
54 PatchBuffer patchInfo = {param.patch, patchOffset, param.patchSize};
55 BlockBuffer oldInfo = {param.oldBuff + srcStart, srcLen};
56 int32_t ret = UpdateApplyPatch::ApplyBlockPatch(patchInfo, oldInfo, writer_);
57 if (ret != 0) {
58 PATCH_LOGE("Failed to apply bsdiff patch");
59 return -1;
60 }
61 startOffset = offset;
62 return 0;
63 }
64
ApplyImagePatch(const PatchParam ¶m, size_t &startOffset)65 int32_t RowImagePatch::ApplyImagePatch(const PatchParam ¶m, size_t &startOffset)
66 {
67 size_t offset = startOffset;
68 if (offset + sizeof(int32_t) > param.patchSize) {
69 PATCH_LOGE("Failed to check datalen");
70 return -1;
71 }
72 size_t dataLen = static_cast<size_t>(ReadLE<uint32_t>(param.patch + offset));
73 if (offset + dataLen > param.patchSize) {
74 PATCH_LOGE("Failed to check datalen");
75 return -1;
76 }
77 offset += sizeof(uint32_t);
78
79 BlockBuffer data = {param.patch + offset, dataLen};
80 int32_t ret = writer_->Write(0, data, dataLen);
81 if (ret != 0) {
82 PATCH_LOGE("Failed to write chunk");
83 return -1;
84 }
85 PATCH_LOGI("RowImagePatch startOffset %zu dataLen %zu", startOffset, dataLen);
86 PATCH_DEBUG("ApplyImagePatch hash %zu %s", dataLen, GeneraterBufferHash(data).c_str());
87 startOffset = offset + dataLen;
88 return 0;
89 }
90
StartReadHeader(const PatchParam ¶m, PatchHeader &header, size_t &offset)91 int32_t CompressedImagePatch::StartReadHeader(const PatchParam ¶m, PatchHeader &header, size_t &offset)
92 {
93 int32_t ret = ReadHeader(param, header, offset);
94 if (ret != 0) {
95 PATCH_LOGE("Failed to read header");
96 return -1;
97 }
98 PATCH_LOGI("ApplyImagePatch srcStart %zu srcLen %zu patchOffset: %zu expandedLen:%zu %zu",
99 header.srcStart, header.srcLength, header.patchOffset, header.expandedLen, header.targetSize);
100 if (header.srcStart > param.oldSize || param.oldSize - header.srcStart < header.srcLength ||
101 header.patchOffset > param.patchSize) {
102 PATCH_LOGE("Failed to check patch");
103 return -1;
104 }
105 return 0;
106 }
107
ApplyImagePatch(const PatchParam ¶m, size_t &startOffset)108 int32_t CompressedImagePatch::ApplyImagePatch(const PatchParam ¶m, size_t &startOffset)
109 {
110 size_t offset = startOffset;
111 // read header
112 PatchHeader header {};
113 if (StartReadHeader(param, header, offset) != 0) {
114 return -1;
115 }
116 // decompress old data
117 Hpackage::PkgManager::PkgManagerPtr pkgManager = Hpackage::PkgManager::CreatePackageInstance();
118 if (pkgManager == nullptr) {
119 PATCH_LOGE("CreatePackageInstance fail");
120 return -1;
121 }
122 ON_SCOPE_EXIT(releaseManager) {
123 Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
124 };
125 Hpackage::PkgManager::StreamPtr stream = nullptr;
126 BlockBuffer oldData = { param.oldBuff + header.srcStart, header.srcLength };
127 if (DecompressData(pkgManager, oldData, stream, true, header.expandedLen) != 0) {
128 PATCH_LOGE("Failed to decompress data");
129 return -1;
130 }
131 // prepare new data
132 std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
133 if (info == nullptr) {
134 PATCH_LOGE("Failed to get file info");
135 return -1;
136 }
137 info->packedSize = header.targetSize;
138 info->unpackedSize = header.expandedLen;
139 std::unique_ptr<CompressedFileRestore> zipWriter = std::make_unique<CompressedFileRestore>(info.get(), writer_);
140 if (zipWriter == nullptr || zipWriter->Init() != 0) {
141 PATCH_LOGE("Failed to create zip writer");
142 return -1;
143 }
144 // apply patch
145 PatchBuffer patchInfo = {param.patch, header.patchOffset, param.patchSize};
146 if (UpdateApplyPatch::ApplyBlockPatch(patchInfo, stream, zipWriter.get()) != 0) {
147 PATCH_LOGE("Failed to apply bsdiff patch");
148 return -1;
149 }
150 // compress new data
151 size_t originalSize = 0;
152 size_t compressSize = 0;
153 zipWriter->CompressData(originalSize, compressSize);
154 PATCH_LOGI("ApplyImagePatch unpackedSize %zu %zu", originalSize, compressSize);
155 if (originalSize != header.targetSize) {
156 PATCH_LOGE("Failed to apply bsdiff patch");
157 return -1;
158 }
159 startOffset = offset;
160 return 0;
161 }
162
DecompressData(Hpackage::PkgManager::PkgManagerPtr &pkgManager, PkgBuffer buffer, Hpackage::PkgManager::StreamPtr &stream, bool memory, size_t expandedLen) const163 int32_t CompressedImagePatch::DecompressData(Hpackage::PkgManager::PkgManagerPtr &pkgManager, PkgBuffer buffer,
164 Hpackage::PkgManager::StreamPtr &stream, bool memory, size_t expandedLen) const
165 {
166 if (expandedLen == 0) {
167 PATCH_LOGE("Decompress data is null");
168 return 0;
169 }
170 std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
171 if (pkgManager == nullptr || info == nullptr) {
172 PATCH_LOGE("Failed to get pkg manager or file info");
173 return -1;
174 }
175
176 info->packedSize = buffer.length;
177 info->unpackedSize = expandedLen;
178 info->identity = std::to_string(g_tmpFileId++);
179
180 // 申请内存stream,用于解压老文件
181 int32_t ret = pkgManager->CreatePkgStream(stream, info->identity,
182 expandedLen, memory ? PkgStream::PkgStreamType_MemoryMap : PkgStream::PkgStreamType_Write);
183 if (stream == nullptr) {
184 PATCH_LOGE("Failed to create stream");
185 return -1;
186 }
187
188 ret = pkgManager->DecompressBuffer(info.get(), buffer, stream);
189 if (ret != 0) {
190 pkgManager->ClosePkgStream(stream);
191 PATCH_LOGE("Can not decompress buff");
192 return -1;
193 }
194
195 if (bonusData_.size() == 0) {
196 return 0;
197 }
198 if (info->unpackedSize > (expandedLen - bonusData_.size())) {
199 PATCH_LOGE("Source inflation short");
200 return -1;
201 }
202 if (memory) { // not support for none memory
203 PkgBuffer memBuffer;
204 if (stream->GetBuffer(memBuffer) != 0) {
205 pkgManager->ClosePkgStream(stream);
206 PATCH_LOGE("Can not get memory buff");
207 return -1;
208 }
209 ret = memcpy_s(memBuffer.buffer + info->unpackedSize,
210 expandedLen - info->unpackedSize, bonusData_.data(), bonusData_.size());
211 }
212 return ret;
213 }
214
ReadHeader(const PatchParam ¶m, PatchHeader &header, size_t &offset)215 int32_t ZipImagePatch::ReadHeader(const PatchParam ¶m, PatchHeader &header, size_t &offset)
216 {
217 if (offset + PATCH_DEFLATE_MIN_HEADER_LEN > param.patchSize) {
218 PATCH_LOGE("Failed to check datalen");
219 return -1;
220 }
221 header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
222 offset += sizeof(uint64_t);
223 header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
224 offset += sizeof(uint64_t);
225 header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
226 offset += sizeof(uint64_t);
227 header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
228 offset += sizeof(uint64_t);
229 header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
230 offset += sizeof(uint64_t);
231
232 level_ = ReadLE<int32_t>(param.patch + offset);
233 offset += sizeof(int32_t);
234 method_ = ReadLE<int32_t>(param.patch + offset);
235 offset += sizeof(int32_t);
236 windowBits_ = ReadLE<int32_t>(param.patch + offset);
237 offset += sizeof(int32_t);
238 memLevel_ = ReadLE<int32_t>(param.patch + offset);
239 offset += sizeof(int32_t);
240 strategy_ = ReadLE<int32_t>(param.patch + offset);
241 offset += sizeof(int32_t);
242
243 PATCH_LOGI("ZipImagePatch::ReadHeader level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
244 level_, method_, windowBits_, memLevel_, strategy_);
245 return 0;
246 }
247
GetFileInfo() const248 std::unique_ptr<Hpackage::FileInfo> ZipImagePatch::GetFileInfo() const
249 {
250 Hpackage::ZipFileInfo *fileInfo = new(std::nothrow) ZipFileInfo;
251 if (fileInfo == nullptr) {
252 PATCH_LOGE("Failed to new file info");
253 return nullptr;
254 }
255 fileInfo->fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
256 fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
257 fileInfo->fileInfo.packedSize = 0;
258 fileInfo->fileInfo.unpackedSize = 0;
259 fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
260 fileInfo->level = level_;
261 fileInfo->method = method_;
262 fileInfo->windowBits = windowBits_;
263 fileInfo->memLevel = memLevel_;
264 fileInfo->strategy = strategy_;
265 return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
266 }
267
ReadHeader(const PatchParam ¶m, PatchHeader &header, size_t &offset)268 int32_t Lz4ImagePatch::ReadHeader(const PatchParam ¶m, PatchHeader &header, size_t &offset)
269 {
270 if (offset + PATCH_LZ4_MIN_HEADER_LEN > param.patchSize) {
271 PATCH_LOGE("Failed to check datalen");
272 return -1;
273 }
274 header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
275 offset += sizeof(uint64_t);
276 header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
277 offset += sizeof(uint64_t);
278 header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
279 offset += sizeof(uint64_t);
280 header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
281 offset += sizeof(uint64_t);
282 header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
283 offset += sizeof(uint64_t);
284
285 compressionLevel_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
286 offset += sizeof(int32_t);
287 method_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
288 offset += sizeof(int32_t);
289 blockIndependence_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
290 offset += sizeof(int32_t);
291 contentChecksumFlag_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
292 offset += sizeof(int32_t);
293 blockSizeID_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
294 offset += sizeof(int32_t);
295 autoFlush_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
296 offset += sizeof(int32_t);
297 PATCH_LOGI("ReadHeader BLOCK_LZ4 level_:%d method_:%d %d contentChecksumFlag_:%d blockSizeID_:%d %d",
298 compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_, autoFlush_);
299 return 0;
300 }
301
GetFileInfo() const302 std::unique_ptr<Hpackage::FileInfo> Lz4ImagePatch::GetFileInfo() const
303 {
304 Hpackage::Lz4FileInfo *fileInfo = new(std::nothrow) Lz4FileInfo;
305 if (fileInfo == nullptr) {
306 PATCH_LOGE("Failed to new file info");
307 return nullptr;
308 }
309 fileInfo->fileInfo.packMethod = (method_ == LZ4B_MAGIC) ? PKG_COMPRESS_METHOD_LZ4_BLOCK : PKG_COMPRESS_METHOD_LZ4;
310 fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
311 fileInfo->fileInfo.packedSize = 0;
312 fileInfo->fileInfo.unpackedSize = 0;
313 fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
314 fileInfo->compressionLevel = static_cast<int8_t>(compressionLevel_);
315 fileInfo->blockIndependence = static_cast<int8_t>(blockIndependence_);
316 fileInfo->contentChecksumFlag = static_cast<int8_t>(contentChecksumFlag_);
317 fileInfo->blockSizeID = static_cast<int8_t>(blockSizeID_);
318 fileInfo->autoFlush = static_cast<int8_t>(autoFlush_);
319 return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
320 }
321
Init()322 int32_t CompressedFileRestore::Init()
323 {
324 SHA256_Init(&sha256Ctx_);
325 if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_ZIP) {
326 deflateAdapter_.reset(new ZipAdapter(writer_, 0, fileInfo_));
327 } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4) {
328 deflateAdapter_.reset(new Lz4FrameAdapter(writer_, 0, fileInfo_));
329 } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4_BLOCK) {
330 deflateAdapter_.reset(new Lz4BlockAdapter(writer_, 0, fileInfo_));
331 }
332 if (deflateAdapter_ == nullptr) {
333 PATCH_LOGE("Failed to create zip adapter");
334 return -1;
335 }
336 return deflateAdapter_->Open();
337 }
338
Write(size_t start, const BlockBuffer &buffer, size_t size)339 int32_t CompressedFileRestore::Write(size_t start, const BlockBuffer &buffer, size_t size)
340 {
341 if (size == 0) {
342 return 0;
343 }
344 dataSize_ += size;
345 SHA256_Update(&sha256Ctx_, buffer.buffer, size);
346 BlockBuffer data = { buffer.buffer, size };
347 return deflateAdapter_->WriteData(data);
348 }
349
CompressData(size_t &originalSize, size_t &compressSize)350 int32_t CompressedFileRestore::CompressData(size_t &originalSize, size_t &compressSize)
351 {
352 int32_t ret = deflateAdapter_->FlushData(compressSize);
353 if (ret != 0) {
354 PATCH_LOGE("Failed to flush data");
355 return -1;
356 }
357 originalSize = dataSize_;
358
359 std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH);
360 SHA256_Final(digest.data(), &sha256Ctx_);
361 BlockBuffer buffer = { digest.data(), digest.size() };
362 std::string hexDigest = ConvertSha256Hex(buffer);
363 PATCH_LOGI("CompressedFileRestore hash %zu %s ", dataSize_, hexDigest.c_str());
364 return 0;
365 }
366 } // namespace UpdatePatch
367