1/*
2 * Copyright (c) 2023 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 "package_fuzzer.h"
17
18#include <array>
19#include <cstddef>
20#include <cstdint>
21#include <cstring>
22#include <fcntl.h>
23#include <iostream>
24#include <string>
25#include <sys/mman.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <vector>
29#include "log/log.h"
30#include "package.h"
31#include "pkg_algorithm.h"
32#include "pkg_manager.h"
33#include "pkg_manager_impl.h"
34#include "pkg_fuzz_test.h"
35#include "pkg_utils.h"
36
37using namespace Updater;
38using namespace Hpackage;
39namespace OHOS {
40class FuzzPackageUnitTest : public FuzzPkgTest {
41public:
42    FuzzPackageUnitTest() {}
43    ~FuzzPackageUnitTest() override {}
44public:
45    int TestInvalidCreatePackage()
46    {
47        std::vector<ComponentInfoExt> info;
48        uint8_t pkgType = PkgPackType::PKG_PACK_TYPE_UPGRADE;
49        int ret = CreatePackage(nullptr, info, nullptr, GetFuzzPrivateKeyName(0).c_str());
50
51        UpgradePkgInfoExt pkgInfoExt {};
52        pkgInfoExt.pkgType = pkgType;
53        ret = CreatePackage(&pkgInfoExt, info, nullptr, GetFuzzPrivateKeyName(0).c_str());
54
55        constexpr uint32_t digestLen = 32;
56        ret = VerifyPackage(nullptr, GetFuzzCertName(0).c_str(), nullptr, nullptr, digestLen);
57
58        std::string packagePath = TEST_PATH_TO + testPackageName;
59        pkgInfoExt.pkgType = pkgType;
60        ret = CreatePackage(&pkgInfoExt, info, packagePath.c_str(), GetFuzzPrivateKeyName(0).c_str());
61
62        pkgType = PkgPackType::PKG_PACK_TYPE_ZIP;
63        pkgInfoExt.pkgType = pkgType;
64        ret = CreatePackage(&pkgInfoExt, info, packagePath.c_str(), GetFuzzPrivateKeyName(0).c_str());
65
66        pkgType = PkgPackType::PKG_PACK_TYPE_LZ4;
67        pkgInfoExt.pkgType = pkgType;
68        ret = CreatePackage(&pkgInfoExt, info, packagePath.c_str(), GetFuzzPrivateKeyName(0).c_str());
69
70        pkgType = PkgPackType::PKG_PACK_TYPE_GZIP;
71        pkgInfoExt.pkgType = pkgType;
72        ret = CreatePackage(&pkgInfoExt, info, packagePath.c_str(), GetFuzzPrivateKeyName(0).c_str());
73
74        pkgType = PkgPackType::PKG_PACK_TYPE_NONE;
75        pkgInfoExt.pkgType = pkgType;
76        ret = CreatePackage(&pkgInfoExt, info, packagePath.c_str(), GetFuzzPrivateKeyName(0).c_str());
77        return ret;
78    }
79
80    int TestPackagePack(int type = PKG_DIGEST_TYPE_SHA256)
81    {
82        int32_t ret;
83        uint32_t updateFileVersion = 1000;
84        UpgradePkgInfoExt pkgInfo;
85        pkgInfo.productUpdateId = strdup("555.555.100.555");
86        pkgInfo.softwareVersion = strdup("100.100.100.100");
87        pkgInfo.date = strdup("2021-02-02");
88        pkgInfo.time = strdup("21:23:49");
89        pkgInfo.entryCount = testFileNames_.size();
90        pkgInfo.updateFileVersion = updateFileVersion;
91        pkgInfo.digestMethod = type;
92        pkgInfo.signMethod = PKG_SIGN_METHOD_RSA;
93        pkgInfo.pkgType = PKG_PACK_TYPE_UPGRADE;
94        std::string filePath;
95        uint32_t componentIdBase = 100;
96        uint8_t componentFlags = 22;
97        std::vector<ComponentInfoExt> comp(testFileNames_.size());
98        for (size_t n = 0; n < testFileNames_.size(); n++) {
99            comp[n].componentAddr = strdup(testFileNames_[n].c_str());
100            filePath = TEST_PATH_FROM;
101            filePath += testFileNames_[n].c_str();
102            comp[n].filePath = strdup(filePath.c_str());
103            comp[n].version = strdup("55555555");
104            ret = BuildFileDigest(*comp[n].digest, sizeof(comp[n].digest), filePath);
105            comp[n].size = GetFileSize(filePath);
106            comp[n].originalSize = comp[n].size;
107            comp[n].id = n + componentIdBase;
108            comp[n].resType = 1;
109            comp[n].type = 1;
110            comp[n].flags = componentFlags;
111            filePath.clear();
112        }
113        std::string packagePath = TEST_PATH_TO;
114        packagePath += testPackageName;
115        ret = CreatePackage(&pkgInfo, comp, packagePath.c_str(),
116            GetFuzzPrivateKeyName(pkgInfo.digestMethod).c_str());
117        for (size_t n = 0; n < testFileNames_.size(); n++) {
118            free(comp[n].componentAddr);
119            free(comp[n].filePath);
120            free(comp[n].version);
121        }
122        free(pkgInfo.productUpdateId);
123        free(pkgInfo.softwareVersion);
124        free(pkgInfo.date);
125        free(pkgInfo.time);
126        return ret;
127    }
128
129    int TestZipPkgCompress(int digestMethod)
130    {
131        return CreateZipPackage(testFileNames_, TEST_PATH_TO + testZipPackageName, TEST_PATH_FROM, digestMethod);
132    }
133
134    int TestPackageUnpack(int type)
135    {
136        std::vector<std::string> componentsList;
137        // 使用上面打包的包进行解析
138        int32_t ret = pkgManager_->LoadPackage(
139            testPackagePath + "test_package.zip", GetFuzzCertName(type), componentsList);
140
141        for (size_t n = 0; n < componentsList.size(); n++) {
142            PKG_LOGI("comp [%zu] file name: %s \r\n", n, (TEST_PATH_TO + componentsList[n]).c_str());
143            ExtractFile(pkgManager_, componentsList, n);
144        }
145        return ret;
146    }
147
148    int TestZipPkgDecompress(int digestMethod)
149    {
150        std::vector<std::string> componentsList;
151        int32_t ret = pkgManager_->LoadPackage(TEST_PATH_TO + testZipPackageName,
152            GetFuzzCertName(digestMethod), componentsList);
153
154        for (size_t n = 0; n < componentsList.size(); n++) {
155            PKG_LOGI("file name: %s \r\n", (TEST_PATH_TO + componentsList[n]).c_str());
156            ExtractFile(pkgManager_, componentsList, n);
157        }
158        return ret;
159    }
160
161    int TestGZipPkgCompress()
162    {
163        int ret = TestPackagePack();
164        std::vector<std::pair<std::string, ZipFileInfo>> files;
165        ZipFileInfo zipFile;
166        zipFile.fileInfo.identity = testPackageName;
167        zipFile.fileInfo.packMethod = PKG_COMPRESS_METHOD_GZIP;
168        zipFile.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
169        std::string fileName = TEST_PATH_TO + testPackageName;
170        files.push_back(std::pair<std::string, ZipFileInfo>(fileName, zipFile));
171
172        PkgInfo info;
173        info.signMethod = PKG_SIGN_METHOD_RSA;
174        info.digestMethod  = PKG_DIGEST_TYPE_SHA256;
175        info.pkgType = PKG_PACK_TYPE_GZIP;
176        ret = pkgManager_->CreatePackage(TEST_PATH_TO + testGZipPackageName,
177            GetFuzzPrivateKeyName(info.digestMethod), &info, files);
178        return ret;
179    }
180
181    int TestVerifyUpgradePackage()
182    {
183        constexpr size_t digestSize = 32;
184        std::vector<uint8_t> digest(digestSize);
185        std::string path = testPackagePath + "test_package.zip";
186        BuildFileDigest(*digest.data(), digest.capacity(), path.c_str());
187        int ret = VerifyPackage(path.c_str(), GetFuzzCertName(0).c_str(), "", digest.data(), digest.capacity());
188        ret = VerifyPackage(nullptr, nullptr, nullptr, nullptr, digest.capacity());
189        return ret;
190    }
191
192    int TestVerifyPackageWithCallback()
193    {
194        std::string path = testPackagePath + "test_package.zip";
195        int ret = VerifyPackageWithCallback(path.c_str(), GetFuzzCertName(0).c_str(),
196            [](int32_t result, uint32_t percent) { PKG_LOGI("progress: %u\n", percent); });
197
198        std::string keyPath = "";
199        ret = VerifyPackageWithCallback(path.c_str(), keyPath.c_str(),
200            [](int32_t result, uint32_t percent) { PKG_LOGI("progress: %u\n", percent); });
201
202        std::function<void(int32_t result, uint32_t percent)> cb = nullptr;
203        ret = VerifyPackageWithCallback(path.c_str(), GetFuzzCertName(0).c_str(), cb);
204
205        path = "";
206        ret = VerifyPackageWithCallback(path.c_str(), GetFuzzCertName(0).c_str(),
207            [](int32_t result, uint32_t percent) { PKG_LOGI("progress: %u\n", percent); });
208        return ret;
209    }
210
211    int TestLz4PkgCompress()
212    {
213        int ret = TestPackagePack();
214        std::vector<std::pair<std::string, Lz4FileInfo>> files;
215        Lz4FileInfo zipFile;
216        int8_t compressionLevel = 14;
217        zipFile.fileInfo.identity = testPackageName;
218        zipFile.fileInfo.packMethod = PKG_COMPRESS_METHOD_LZ4;
219        zipFile.fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
220        zipFile.compressionLevel = compressionLevel;
221        zipFile.blockSizeID = 0;
222        zipFile.contentChecksumFlag = 0;
223        zipFile.blockIndependence = 0;
224        std::string fileName = TEST_PATH_TO + testPackageName;
225        files.push_back(std::pair<std::string, Lz4FileInfo>(fileName, zipFile));
226
227        PkgInfo info;
228        info.pkgType = PKG_PACK_TYPE_LZ4;
229        info.signMethod = PKG_SIGN_METHOD_RSA;
230        info.digestMethod  = PKG_DIGEST_TYPE_SHA256;
231        ret = pkgManager_->CreatePackage(TEST_PATH_TO + testLz4PackageName,
232            GetFuzzPrivateKeyName(info.digestMethod), &info, files);
233        return ret;
234    }
235};
236
237void FUZZPackageUnitTest(const uint8_t* data, size_t size)
238{
239    FuzzPackageUnitTest test;
240    (void)test.TestLz4PkgCompress();
241    (void)test.TestInvalidCreatePackage();
242    (void)test.TestVerifyUpgradePackage();
243    (void)test.TestVerifyPackageWithCallback();
244    (void)test.TestPackagePack(PKG_DIGEST_TYPE_SHA256);
245    (void)test.TestPackageUnpack(PKG_DIGEST_TYPE_SHA256);
246    (void)test.TestZipPkgCompress(PKG_DIGEST_TYPE_SHA256);
247    (void)test.TestZipPkgDecompress(PKG_DIGEST_TYPE_SHA256);
248    (void)test.TestGZipPkgCompress();
249}
250
251void FuzzVerifyPackage(const uint8_t* data, size_t size)
252{
253    constexpr size_t digestSize = 32;
254    std::vector<uint8_t> digest(digestSize);
255    const std::string keyPath = "/data/fuzz/test/signing_cert.crt";
256    const std::string pkgPath = "/data/fuzz/test/updater.zip";
257    const std::string pkgDir = "/data/fuzz/test";
258    const std::string dataInfo = std::string(reinterpret_cast<const char*>(data), size);
259    VerifyPackage(dataInfo.c_str(), keyPath.c_str(), "", digest.data(), digest.capacity());
260    VerifyPackage(pkgPath.c_str(), dataInfo.c_str(), "", digest.data(), digest.capacity());
261    VerifyPackage(pkgPath.c_str(), keyPath.c_str(), dataInfo.c_str(), digest.data(), digest.capacity());
262    VerifyPackage(pkgPath.c_str(), keyPath.c_str(), "", data, size);
263
264    VerifyPackageWithCallback(dataInfo.c_str(), keyPath.c_str(),
265        [](int32_t result, uint32_t percent) {});
266    VerifyPackageWithCallback(pkgPath, dataInfo.c_str(), [](int32_t result, uint32_t percent) {});
267
268    ExtraPackageDir(dataInfo.c_str(), keyPath.c_str(), nullptr, pkgDir.c_str());
269    ExtraPackageDir(pkgPath.c_str(), dataInfo.c_str(), nullptr, pkgDir.c_str());
270    ExtraPackageDir(pkgPath.c_str(), keyPath.c_str(), dataInfo.c_str(), pkgDir.c_str());
271    ExtraPackageDir(pkgPath.c_str(), keyPath.c_str(), nullptr, dataInfo.c_str());
272
273    const std::string file = "updater.bin";
274    ExtraPackageFile(dataInfo.c_str(), keyPath.c_str(), file.c_str(), pkgDir.c_str());
275    ExtraPackageFile(pkgPath.c_str(), dataInfo.c_str(), file.c_str(), pkgDir.c_str());
276    ExtraPackageFile(pkgPath.c_str(), keyPath.c_str(), dataInfo.c_str(), pkgDir.c_str());
277    ExtraPackageFile(pkgPath.c_str(), keyPath.c_str(), file.c_str(), dataInfo.c_str());
278}
279}
280
281/* Fuzzer entry point */
282extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
283{
284    /* Run your code on data */
285    OHOS::FuzzVerifyPackage(data, size);
286    return 0;
287}
288
289