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 & param,size_t & startOffset)33 int32_t NormalImagePatch::ApplyImagePatch(const PatchParam &param, 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 & param,size_t & startOffset)65 int32_t RowImagePatch::ApplyImagePatch(const PatchParam &param, 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 & param,PatchHeader & header,size_t & offset)91 int32_t CompressedImagePatch::StartReadHeader(const PatchParam &param, 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, srcStart: %zu srcLength: %zu , param.oldSize: %zu, patchOffset: %zu",
103             header.srcStart, header.srcLength, param.oldSize, header.patchOffset);
104         return -1;
105     }
106     return 0;
107 }
108 
ApplyImagePatch(const PatchParam & param,size_t & startOffset)109 int32_t CompressedImagePatch::ApplyImagePatch(const PatchParam &param, size_t &startOffset)
110 {
111     size_t offset = startOffset;
112     // read header
113     PatchHeader header {};
114     if (StartReadHeader(param, header, offset) != 0) {
115         return -1;
116     }
117     // decompress old data
118     Hpackage::PkgManager::PkgManagerPtr pkgManager = Hpackage::PkgManager::CreatePackageInstance();
119     if (pkgManager == nullptr) {
120         PATCH_LOGE("CreatePackageInstance fail");
121         return -1;
122     }
123     ON_SCOPE_EXIT(releaseManager) {
124         Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
125     };
126     Hpackage::PkgManager::StreamPtr stream = nullptr;
127     BlockBuffer oldData = { param.oldBuff + header.srcStart, header.srcLength };
128     if (DecompressData(pkgManager, oldData, stream, true, header.expandedLen) != 0) {
129         PATCH_LOGE("Failed to decompress data");
130         return -1;
131     }
132     // prepare new data
133     std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
134     if (info == nullptr) {
135         PATCH_LOGE("Failed to get file info");
136         return -1;
137     }
138     info->packedSize = header.targetSize;
139     info->unpackedSize = header.expandedLen;
140     std::unique_ptr<CompressedFileRestore> zipWriter = std::make_unique<CompressedFileRestore>(info.get(), writer_);
141     if (zipWriter == nullptr || zipWriter->Init() != 0) {
142         PATCH_LOGE("Failed to create zip writer");
143         return -1;
144     }
145     // apply patch
146     PatchBuffer patchInfo = {param.patch, header.patchOffset, param.patchSize};
147     if (UpdateApplyPatch::ApplyBlockPatch(patchInfo, stream, zipWriter.get()) != 0) {
148         PATCH_LOGE("Failed to apply bsdiff patch");
149         return -1;
150     }
151     // compress new data
152     size_t originalSize = 0;
153     size_t compressSize = 0;
154     zipWriter->CompressData(originalSize, compressSize);
155     PATCH_LOGI("ApplyImagePatch unpackedSize %zu %zu", originalSize, compressSize);
156     if (originalSize != header.targetSize) {
157         PATCH_LOGE("Failed to apply bsdiff patch");
158         return -1;
159     }
160     startOffset = offset;
161     return 0;
162 }
163 
DecompressData(Hpackage::PkgManager::PkgManagerPtr & pkgManager,PkgBuffer buffer,Hpackage::PkgManager::StreamPtr & stream,bool memory,size_t expandedLen) const164 int32_t CompressedImagePatch::DecompressData(Hpackage::PkgManager::PkgManagerPtr &pkgManager, PkgBuffer buffer,
165     Hpackage::PkgManager::StreamPtr &stream, bool memory, size_t expandedLen) const
166 {
167     if (expandedLen == 0) {
168         PATCH_LOGE("Decompress data is null");
169         return 0;
170     }
171     std::unique_ptr<Hpackage::FileInfo> info = GetFileInfo();
172     if (pkgManager == nullptr || info == nullptr) {
173         PATCH_LOGE("Failed to get pkg manager or file info");
174         return -1;
175     }
176 
177     info->packedSize = buffer.length;
178     info->unpackedSize = expandedLen;
179     info->identity = std::to_string(g_tmpFileId++);
180 
181     // 申请内存stream,用于解压老文件
182     int32_t ret = pkgManager->CreatePkgStream(stream, info->identity,
183         expandedLen, memory ? PkgStream::PkgStreamType_MemoryMap : PkgStream::PkgStreamType_Write);
184     if (stream == nullptr) {
185         PATCH_LOGE("Failed to create stream");
186         return -1;
187     }
188 
189     ret = pkgManager->DecompressBuffer(info.get(), buffer, stream);
190     if (ret != 0) {
191         pkgManager->ClosePkgStream(stream);
192         PATCH_LOGE("Can not decompress buff");
193         return -1;
194     }
195 
196     if (bonusData_.size() == 0) {
197         return 0;
198     }
199     if (info->unpackedSize > (expandedLen - bonusData_.size())) {
200         PATCH_LOGE("Source inflation short");
201         return -1;
202     }
203     if (memory) { // not support for none memory
204         PkgBuffer memBuffer;
205         if (stream->GetBuffer(memBuffer) != 0) {
206             pkgManager->ClosePkgStream(stream);
207             PATCH_LOGE("Can not get memory buff");
208             return -1;
209         }
210         ret = memcpy_s(memBuffer.buffer + info->unpackedSize,
211             expandedLen - info->unpackedSize, bonusData_.data(), bonusData_.size());
212     }
213     return ret;
214 }
215 
ReadHeader(const PatchParam & param,PatchHeader & header,size_t & offset)216 int32_t ZipImagePatch::ReadHeader(const PatchParam &param, PatchHeader &header, size_t &offset)
217 {
218     if (offset + PATCH_DEFLATE_MIN_HEADER_LEN > param.patchSize) {
219         PATCH_LOGE("Failed to check datalen");
220         return -1;
221     }
222     header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
223     offset += sizeof(uint64_t);
224     header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
225     offset += sizeof(uint64_t);
226     header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
227     offset += sizeof(uint64_t);
228     header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
229     offset += sizeof(uint64_t);
230     header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
231     offset += sizeof(uint64_t);
232 
233     level_ = ReadLE<int32_t>(param.patch + offset);
234     offset += sizeof(int32_t);
235     method_ = ReadLE<int32_t>(param.patch + offset);
236     offset += sizeof(int32_t);
237     windowBits_ = ReadLE<int32_t>(param.patch + offset);
238     offset += sizeof(int32_t);
239     memLevel_ = ReadLE<int32_t>(param.patch + offset);
240     offset += sizeof(int32_t);
241     strategy_ = ReadLE<int32_t>(param.patch + offset);
242     offset += sizeof(int32_t);
243 
244     PATCH_LOGI("ZipImagePatch::ReadHeader level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
245         level_, method_, windowBits_, memLevel_, strategy_);
246     return 0;
247 }
248 
GetFileInfo() const249 std::unique_ptr<Hpackage::FileInfo> ZipImagePatch::GetFileInfo() const
250 {
251     Hpackage::ZipFileInfo *fileInfo = new(std::nothrow) ZipFileInfo;
252     if (fileInfo == nullptr) {
253         PATCH_LOGE("Failed to new file info");
254         return nullptr;
255     }
256     fileInfo->fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
257     fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
258     fileInfo->fileInfo.packedSize = 0;
259     fileInfo->fileInfo.unpackedSize = 0;
260     fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
261     fileInfo->level = level_;
262     fileInfo->method = method_;
263     fileInfo->windowBits = windowBits_;
264     fileInfo->memLevel = memLevel_;
265     fileInfo->strategy = strategy_;
266     return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
267 }
268 
ReadHeader(const PatchParam & param,PatchHeader & header,size_t & offset)269 int32_t Lz4ImagePatch::ReadHeader(const PatchParam &param, PatchHeader &header, size_t &offset)
270 {
271     if (offset + PATCH_LZ4_MIN_HEADER_LEN > param.patchSize) {
272         PATCH_LOGE("Failed to check datalen");
273         return -1;
274     }
275     header.srcStart = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
276     offset += sizeof(uint64_t);
277     header.srcLength = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
278     offset += sizeof(uint64_t);
279     header.patchOffset = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
280     offset += sizeof(uint64_t);
281     header.expandedLen = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
282     offset += sizeof(uint64_t);
283     header.targetSize = static_cast<size_t>(ReadLE<uint64_t>(param.patch + offset));
284     offset += sizeof(uint64_t);
285 
286     compressionLevel_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
287     offset += sizeof(int32_t);
288     method_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
289     offset += sizeof(int32_t);
290     blockIndependence_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
291     offset += sizeof(int32_t);
292     contentChecksumFlag_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
293     offset += sizeof(int32_t);
294     blockSizeID_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
295     offset += sizeof(int32_t);
296     autoFlush_ = static_cast<int32_t>(ReadLE<int32_t>(param.patch + offset));
297     offset += sizeof(int32_t);
298     PATCH_LOGI("ReadHeader BLOCK_LZ4 level_:%d method_:%d %d contentChecksumFlag_:%d blockSizeID_:%d %d",
299         compressionLevel_, method_, blockIndependence_, contentChecksumFlag_, blockSizeID_, autoFlush_);
300     return 0;
301 }
302 
GetFileInfo() const303 std::unique_ptr<Hpackage::FileInfo> Lz4ImagePatch::GetFileInfo() const
304 {
305     Hpackage::Lz4FileInfo *fileInfo = new(std::nothrow) Lz4FileInfo;
306     if (fileInfo == nullptr) {
307         PATCH_LOGE("Failed to new file info");
308         return nullptr;
309     }
310     fileInfo->fileInfo.packMethod = (method_ == LZ4B_MAGIC) ? PKG_COMPRESS_METHOD_LZ4_BLOCK : PKG_COMPRESS_METHOD_LZ4;
311     fileInfo->fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
312     fileInfo->fileInfo.packedSize = 0;
313     fileInfo->fileInfo.unpackedSize = 0;
314     fileInfo->fileInfo.identity = std::to_string(g_tmpFileId++);
315     fileInfo->compressionLevel = static_cast<int8_t>(compressionLevel_);
316     fileInfo->blockIndependence = static_cast<int8_t>(blockIndependence_);
317     fileInfo->contentChecksumFlag = static_cast<int8_t>(contentChecksumFlag_);
318     fileInfo->blockSizeID = static_cast<int8_t>(blockSizeID_);
319     fileInfo->autoFlush = static_cast<int8_t>(autoFlush_);
320     return std::unique_ptr<Hpackage::FileInfo>((FileInfo *)fileInfo);
321 }
322 
Init()323 int32_t CompressedFileRestore::Init()
324 {
325     SHA256_Init(&sha256Ctx_);
326     if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_ZIP) {
327         deflateAdapter_.reset(new ZipAdapter(writer_, 0, fileInfo_));
328     } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4) {
329         deflateAdapter_.reset(new Lz4FrameAdapter(writer_, 0, fileInfo_));
330     } else if (fileInfo_->packMethod == PKG_COMPRESS_METHOD_LZ4_BLOCK) {
331         deflateAdapter_.reset(new Lz4BlockAdapter(writer_, 0, fileInfo_));
332     }
333     if (deflateAdapter_ == nullptr) {
334         PATCH_LOGE("Failed to create zip adapter");
335         return -1;
336     }
337     return deflateAdapter_->Open();
338 }
339 
Write(size_t start,const BlockBuffer & buffer,size_t size)340 int32_t CompressedFileRestore::Write(size_t start, const BlockBuffer &buffer, size_t size)
341 {
342     if (size == 0) {
343         return 0;
344     }
345     dataSize_ += size;
346     SHA256_Update(&sha256Ctx_, buffer.buffer, size);
347     BlockBuffer data = { buffer.buffer, size };
348     return deflateAdapter_->WriteData(data);
349 }
350 
CompressData(size_t & originalSize,size_t & compressSize)351 int32_t CompressedFileRestore::CompressData(size_t &originalSize, size_t &compressSize)
352 {
353     int32_t ret = deflateAdapter_->FlushData(compressSize);
354     if (ret != 0) {
355         PATCH_LOGE("Failed to flush data");
356         return -1;
357     }
358     originalSize = dataSize_;
359 
360     std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH);
361     SHA256_Final(digest.data(), &sha256Ctx_);
362     BlockBuffer buffer = { digest.data(), digest.size() };
363     std::string hexDigest = ConvertSha256Hex(buffer);
364     PATCH_LOGI("CompressedFileRestore hash %zu %s ", dataSize_, hexDigest.c_str());
365     return 0;
366 }
367 } // namespace UpdatePatch
368