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 "patch/update_patch.h"
17#include <memory>
18#include <vector>
19#include "blocks_patch.h"
20#include "diffpatch.h"
21#include "image_patch.h"
22#include "openssl/sha.h"
23#include "securec.h"
24
25using namespace Hpackage;
26namespace UpdatePatch {
27int32_t UpdateApplyPatch::ApplyImagePatch(const PatchParam &param, const std::vector<uint8_t> &bonusData,
28    ImageProcessor writer, const std::string& expected)
29{
30    if (writer == nullptr) {
31        PATCH_LOGE("ApplyImagePatch : processor is null");
32        return -1;
33    }
34    std::unique_ptr<ImagePatchWriter> patchWriter = std::make_unique<ImagePatchWriter>(writer, expected, "");
35    if (patchWriter == nullptr) {
36        PATCH_LOGE("ApplyImagePatch : Failed to create patch writer");
37        return -1;
38    }
39    int32_t ret = patchWriter->Init();
40    if (ret != 0) {
41        PATCH_LOGE("ApplyImagePatch : Failed to init patch writer");
42        return -1;
43    }
44    ret = ApplyImagePatch(param, patchWriter.get(), bonusData);
45    if (ret != 0) {
46        PATCH_LOGE("ApplyImagePatch : Failed to apply image patch");
47        return -1;
48    }
49    return patchWriter->Finish();
50}
51
52bool UpdateApplyPatch::PreCheck(const PatchParam &param, const UpdatePatchWriterPtr writer)
53{
54    if (writer == nullptr) {
55        PATCH_LOGE("check param fail ");
56        return false;
57    }
58    if (param.patchSize < (std::char_traits<char>::length(PKGDIFF_MAGIC) + sizeof(int32_t))) {
59        PATCH_LOGE("patch too short to contain header ");
60        return false;
61    }
62    if (memcmp(param.patch, PKGDIFF_MAGIC, std::char_traits<char>::length(PKGDIFF_MAGIC)) != 0) {
63        PATCH_LOGE("corrupt patch file header (magic number) ");
64        return false;
65    }
66    return true;
67}
68
69int32_t UpdateApplyPatch::ApplyImagePatch(const PatchParam &param,
70    UpdatePatchWriterPtr writer, const std::vector<uint8_t> &bonusData)
71{
72    if (!PreCheck(param, writer)) {
73        return -1;
74    }
75    size_t offset = std::char_traits<char>::length(PKGDIFF_MAGIC);
76    int32_t numChunks = ImagePatch::ReadLE<int32_t>(param.patch + offset);
77    offset += sizeof(int32_t);
78
79    std::vector<uint8_t> empty;
80    for (int i = 0; i < numChunks; ++i) {
81        // each chunk's header record starts with 4 bytes.
82        if ((offset + sizeof(int32_t)) > param.patchSize) {
83            PATCH_LOGE("Failed to read chunk record ");
84            return -1;
85        }
86        int32_t type = ImagePatch::ReadLE<int32_t>(param.patch + offset);
87        PATCH_DEBUG("ApplyImagePatch numChunks[%d] type %d offset %d", i, type, offset);
88        offset += sizeof(int32_t);
89        std::unique_ptr<ImagePatch> imagePatch = nullptr;
90        switch (type) {
91            case BLOCK_NORMAL:
92                imagePatch = std::make_unique<NormalImagePatch>(writer);
93                break;
94            case BLOCK_RAW:
95                imagePatch = std::make_unique<RowImagePatch>(writer);
96                break;
97            case BLOCK_DEFLATE:
98                imagePatch = std::make_unique<ZipImagePatch>(writer, ((i == 1) ? bonusData : empty));
99                break;
100            case BLOCK_LZ4:
101                imagePatch = std::make_unique<Lz4ImagePatch>(writer, ((i == 1) ? bonusData : empty));
102                break;
103            default:
104                break;
105        }
106        if (imagePatch == nullptr) {
107            PATCH_LOGE("Failed to  creareimg patch ");
108            return -1;
109        }
110        int32_t ret = imagePatch->ApplyImagePatch(param, offset);
111        if (ret != 0) {
112            PATCH_LOGE("Apply image patch fail ");
113            return -1;
114        }
115    }
116    return 0;
117}
118
119int32_t UpdateApplyPatch::ApplyBlockPatch(const PatchBuffer &patchInfo,
120    const BlockBuffer &oldInfo, std::vector<uint8_t> &newData)
121{
122    std::unique_ptr<BlocksBufferPatch> patch = std::make_unique<BlocksBufferPatch>(patchInfo, oldInfo, newData);
123    if (patch == nullptr) {
124        PATCH_LOGE("Failed to  creare patch ");
125        return -1;
126    }
127    return patch->ApplyPatch();
128}
129
130int32_t UpdateApplyPatch::ApplyBlockPatch(const PatchBuffer &patchInfo,
131    const BlockBuffer &oldInfo, UpdatePatchWriterPtr writer)
132{
133    PkgManager* pkgManager = Hpackage::PkgManager::CreatePackageInstance();
134    if (pkgManager == nullptr) {
135        PATCH_LOGE("Failed to get pkg manager");
136        return -1;
137    }
138
139    Hpackage::PkgManager::StreamPtr stream = nullptr;
140    int32_t ret = pkgManager->CreatePkgStream(stream, "", {oldInfo.buffer, oldInfo.length});
141    if (stream == nullptr || ret != PKG_SUCCESS) {
142        PATCH_LOGE("Failed to create stream");
143        pkgManager->ClosePkgStream(stream);
144        Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
145        return -1;
146    }
147
148    std::unique_ptr<BlocksStreamPatch> patch = std::make_unique<BlocksStreamPatch>(patchInfo, stream, writer);
149    if (patch == nullptr) {
150        PATCH_LOGE("Failed to  creare patch ");
151        pkgManager->ClosePkgStream(stream);
152        Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
153        return -1;
154    }
155    ret = patch->ApplyPatch();
156    pkgManager->ClosePkgStream(stream);
157    Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
158    return ret;
159}
160
161int32_t UpdateApplyPatch::ApplyBlockPatch(const PatchBuffer &patchInfo,
162    const BlockBuffer &oldInfo, ImageProcessor writer, const std::string& expected)
163{
164    if (writer == nullptr) {
165        PATCH_LOGE("ApplyBlockPatch : processor is null");
166        return -1;
167    }
168    std::unique_ptr<ImagePatchWriter> patchWriter = std::make_unique<ImagePatchWriter>(writer, expected, "");
169    if (patchWriter == nullptr) {
170        PATCH_LOGE("ApplyBlockPatch : Failed to create patch writer");
171        return -1;
172    }
173    int32_t ret = patchWriter->Init();
174    if (ret != 0) {
175        PATCH_LOGE("ApplyBlockPatch : Failed to init patch writer");
176        return -1;
177    }
178
179    PkgManager* pkgManager = Hpackage::PkgManager::CreatePackageInstance();
180    if (pkgManager == nullptr) {
181        PATCH_LOGE("ApplyBlockPatch ::Failed to get pkg manager");
182        return -1;
183    }
184
185    Hpackage::PkgManager::StreamPtr stream = nullptr;
186    ret = pkgManager->CreatePkgStream(stream, "", {oldInfo.buffer, oldInfo.length});
187    if (stream == nullptr) {
188        PATCH_LOGE("Failed to create stream");
189        pkgManager->ClosePkgStream(stream);
190        Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
191        return -1;
192    }
193
194    std::unique_ptr<BlocksStreamPatch> patch = std::make_unique<BlocksStreamPatch>(patchInfo,
195        stream, patchWriter.get());
196    if (patch == nullptr) {
197        PATCH_LOGE("Failed to  creare patch ");
198        pkgManager->ClosePkgStream(stream);
199        Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
200        return -1;
201    }
202    ret = patch->ApplyPatch();
203    pkgManager->ClosePkgStream(stream);
204    Hpackage::PkgManager::ReleasePackageInstance(pkgManager);
205    if (ret != 0) {
206        PATCH_LOGE("Failed to applay patch ");
207        return -1;
208    }
209    return patchWriter->Finish();
210}
211
212int32_t UpdateApplyPatch::ApplyBlockPatch(const PatchBuffer &patchInfo,
213    Hpackage::PkgManager::StreamPtr stream, UpdatePatchWriterPtr writer)
214{
215    std::unique_ptr<BlocksStreamPatch> patch = std::make_unique<BlocksStreamPatch>(patchInfo, stream, writer);
216    if (patch == nullptr) {
217        PATCH_LOGE("Failed to  creare patch ");
218        return -1;
219    }
220    return patch->ApplyPatch();
221}
222
223int32_t UpdateApplyPatch::ApplyPatch(const std::string &patchName,
224    const std::string &oldName, const std::string &newName)
225{
226    PATCH_DEBUG("UpdatePatch::ApplyPatch : %s ", patchName.c_str());
227    std::vector<uint8_t> empty;
228    MemMapInfo patchData {};
229    MemMapInfo oldData {};
230    if (PatchMapFile(patchName, patchData) != 0) {
231        PATCH_LOGE("ApplyPatch : Failed to read patch file");
232        return -1;
233    }
234    if (PatchMapFile(oldName, oldData) != 0) {
235        PATCH_LOGE("ApplyPatch : Failed to read old file");
236        return -1;
237    }
238    PATCH_LOGI("UpdatePatch::ApplyPatch patchData %zu oldData %zu ", patchData.length, oldData.length);
239    std::unique_ptr<FilePatchWriter> writer = std::make_unique<FilePatchWriter>(newName);
240    if (writer == nullptr) {
241        PATCH_LOGE("Failed to create writer");
242        return -1;
243    }
244    writer->Init();
245
246    // check if image patch
247    if (patchData.length < std::char_traits<char>::length(PKGDIFF_MAGIC)) {
248        PATCH_LOGE("length error");
249        return -1;
250    }
251    if (memcmp(patchData.memory, PKGDIFF_MAGIC, std::char_traits<char>::length(PKGDIFF_MAGIC)) == 0) {
252        PatchParam param {};
253        param.patch = patchData.memory;
254        param.patchSize = patchData.length;
255        param.oldBuff = oldData.memory;
256        param.oldSize = oldData.length;
257        if (UpdatePatch::UpdateApplyPatch::ApplyImagePatch(param, writer.get(), empty) != 0) {
258            PATCH_LOGE("Failed to apply image patch file");
259            return -1;
260        }
261    } else if (memcmp(patchData.memory, BSDIFF_MAGIC, std::char_traits<char>::length(BSDIFF_MAGIC)) == 0) { // bsdiff
262        PatchBuffer patchInfo = {patchData.memory, 0, patchData.length};
263        BlockBuffer oldInfo = {oldData.memory, oldData.length};
264        if (ApplyBlockPatch(patchInfo, oldInfo, writer.get()) != 0) {
265            PATCH_LOGE("Failed to apply block patch");
266            return -1;
267        }
268    } else {
269        PATCH_LOGE("Invalid patch file");
270        return -1;
271    }
272    writer->Finish();
273    return 0;
274}
275
276int32_t ImagePatchWriter::Init()
277{
278    if (init_) {
279        PATCH_LOGE("Has beed init");
280        return -1;
281    }
282    if (writer_ == nullptr) {
283        PATCH_LOGE("Writer is null");
284        return -1;
285    }
286    SHA256_Init(&sha256Ctx_);
287    init_ = true;
288    return 0;
289}
290
291int32_t ImagePatchWriter::Write(size_t start, const BlockBuffer &buffer, size_t len)
292{
293    if (!init_) {
294        PATCH_LOGE("Failed to check init");
295        return -1;
296    }
297    if (len == 0) {
298        return 0;
299    }
300    SHA256_Update(&sha256Ctx_, buffer.buffer, len);
301    return writer_(start, buffer, len);
302}
303
304int32_t ImagePatchWriter::Finish()
305{
306    if (!init_) {
307        PATCH_LOGE("Failed to check init");
308        return -1;
309    }
310    std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH);
311    SHA256_Final(digest.data(), &sha256Ctx_);
312    BlockBuffer data = {  digest.data(), digest.size() };
313    std::string hexDigest = ConvertSha256Hex(data);
314    init_ = false;
315    int32_t ret = hexDigest.compare(expected_);
316    if (ret != 0) {
317        PATCH_LOGE("VerifySha256 SHA256 : %s expected SHA256 : %s", hexDigest.c_str(), expected_.c_str());
318        return ret;
319    }
320    return 0;
321}
322
323int32_t FilePatchWriter::Init()
324{
325    if (init_) {
326        PATCH_LOGE("Has beed init");
327        return -1;
328    }
329    if (!stream_.is_open()) {
330        stream_.open(newFileName_, std::ios::out | std::ios::binary);
331        if (stream_.fail()) {
332            PATCH_LOGE("Failed to open %s", newFileName_.c_str());
333            return -1;
334        }
335    }
336    init_ = true;
337    return 0;
338}
339
340int32_t FilePatchWriter::Write(size_t start, const BlockBuffer &buffer, size_t len)
341{
342    if (!init_) {
343        PATCH_LOGE("Failed to check init");
344        return -1;
345    }
346    if (len == 0) {
347        return 0;
348    }
349    if (!stream_.is_open()) {
350        stream_.open(newFileName_, std::ios::out | std::ios::binary);
351        if (stream_.fail()) {
352            PATCH_LOGE("Failed to open %s", newFileName_.c_str());
353            return -1;
354        }
355    }
356    stream_.write(reinterpret_cast<const char*>(buffer.buffer), len);
357    return 0;
358}
359
360int32_t FilePatchWriter::Finish()
361{
362    if (!init_) {
363        PATCH_LOGE("Failed to check init");
364        return -1;
365    }
366    PATCH_LOGI("FilePatchWriter %zu", static_cast<size_t>(stream_.tellp()));
367    stream_.close();
368    init_ = false;
369    return 0;
370}
371} // namespace UpdatePatch