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 "extractandexecutescript_fuzzer.h"
17
18#include <array>
19#include <cstddef>
20#include <cstdint>
21#include <fcntl.h>
22#include <iostream>
23#include <string>
24#include <sys/mman.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <vector>
28#include "pkg_algorithm.h"
29#include "pkg_algo_digest.h"
30#include "pkg_utils.h"
31#include "script_instructionhelper.h"
32#include "script_manager_impl.h"
33#include "script_manager.h"
34#include "script_utils.h"
35
36
37using namespace Hpackage;
38using namespace Uscript;
39using namespace Updater;
40
41const static std::string TEST_PATH_TO = "/data/fuzz/test/";
42const static int32_t SCRIPT_TEST_PRIORITY_NUM = 3;
43const static int32_t SCRIPT_TEST_LAST_PRIORITY = 2;
44
45static inline std::string GetTestCertName()
46{
47    std::string name = TEST_PATH_TO;
48    name += "signing_cert.crt";
49    return name;
50}
51
52static inline std::string GetTestPrivateKeyName()
53{
54    std::string name = TEST_PATH_TO;
55    name += "rsa_private_key2048.pem";
56    return name;
57}
58
59class TestScriptInstructionSparseImageWrite : public Uscript::UScriptInstruction {
60public:
61    TestScriptInstructionSparseImageWrite() {}
62    virtual ~TestScriptInstructionSparseImageWrite() {}
63    int32_t Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context) override
64    {
65        /* 从参数中获取分区信息 */
66        std::string partitionName;
67        int32_t ret = context.GetParam(0, partitionName);
68        if (ret != USCRIPT_SUCCESS) {
69            return ret;
70        }
71        if (env.GetPkgManager() == nullptr) {
72            return USCRIPT_ERROR_EXECUTE;
73        }
74        return ret;
75    }
76};
77
78class TestScriptInstructionFactory : public UScriptInstructionFactory {
79public:
80    virtual int32_t CreateInstructionInstance(UScriptInstructionPtr& instr, const std::string& name)
81    {
82        if (name == "sparse_image_write") {
83            instr = new TestScriptInstructionSparseImageWrite();
84        }
85        return USCRIPT_SUCCESS;
86    }
87    virtual void DestoryInstructionInstance(UScriptInstructionPtr& instr)
88    {
89        delete instr;
90    }
91    TestScriptInstructionFactory() {}
92    virtual ~TestScriptInstructionFactory() {}
93};
94
95class UTestScriptEnv : public UScriptEnv {
96public:
97    UScriptInstructionFactory *factory_ = nullptr;
98    explicit UTestScriptEnv(Hpackage::PkgManager::PkgManagerPtr pkgManager) : UScriptEnv(pkgManager) {}
99    ~UTestScriptEnv()
100    {
101        if (factory_ != nullptr) {
102            delete factory_;
103            factory_ = nullptr;
104        }
105    }
106
107    virtual void PostMessage(const std::string &cmd, std::string content) {}
108
109    virtual UScriptInstructionFactoryPtr GetInstructionFactory()
110    {
111        if (factory_ == nullptr) {
112            factory_ = new TestScriptInstructionFactory();
113        }
114        return factory_;
115    }
116
117    virtual const std::vector<std::string> GetInstructionNames() const
118    {
119        static std::vector<std::string> updaterCmds = {"sparse_image_write"};
120        return updaterCmds;
121    }
122
123    virtual bool IsRetry() const
124    {
125        return isRetry;
126    }
127
128    virtual PostMessageFunction GetPostmsgFunc()
129    {
130        return nullptr;
131    }
132private:
133    bool isRetry = false;
134};
135
136class UScriptTest {
137public:
138    UScriptTest()
139    {
140        packageManager = PkgManager::CreatePackageInstance();
141    }
142
143    ~UScriptTest()
144    {
145        PkgManager::ReleasePackageInstance(packageManager);
146        ScriptManager::ReleaseScriptManager();
147    }
148
149    int TestUscriptExecute(const std::vector<std::string> &inputFile)
150    {
151        CreatePackageBin(inputFile);
152        if (packageManager == nullptr) {
153            return PKG_SUCCESS;
154        }
155        std::vector<std::string> components;
156        int32_t ret = packageManager->LoadPackage(TEST_PATH_TO + testPackageName, GetTestCertName(), components);
157        if (ret != USCRIPT_SUCCESS) {
158            USCRIPT_LOGI("LoadPackage fail ret:%d", ret);
159            return USCRIPT_INVALID_SCRIPT;
160        }
161
162        UTestScriptEnv* env = new UTestScriptEnv(packageManager);
163        Hpackage::HashDataVerifier scriptVerifier {packageManager};
164        ScriptManager* manager = ScriptManager::GetScriptManager(env, &scriptVerifier);
165        if (manager == nullptr) {
166            USCRIPT_LOGI("create manager fail ret:%d", ret);
167            delete env;
168            return USCRIPT_INVALID_SCRIPT;
169        }
170        int32_t priority = SCRIPT_TEST_PRIORITY_NUM;
171        ret = manager->ExecuteScript(priority);
172        USCRIPT_LOGI("ExecuteScript ret:%d", ret);
173        priority = 0;
174        ret = manager->ExecuteScript(priority);
175        USCRIPT_LOGI("ExecuteScript ret:%d", ret);
176        priority = 1;
177        ret = manager->ExecuteScript(priority);
178        priority = SCRIPT_TEST_LAST_PRIORITY;
179        ret = manager->ExecuteScript(priority);
180        delete env;
181        ScriptManager::ReleaseScriptManager();
182        return ret;
183    }
184
185protected:
186    int32_t BuildFileDigest(uint8_t &digest, size_t size, const std::string &packagePath)
187    {
188        PkgManager::StreamPtr stream = nullptr;
189        int32_t ret = packageManager->CreatePkgStream(stream, packagePath, 0, PkgStream::PkgStreamType_Read);
190        if (ret != PKG_SUCCESS) {
191            PKG_LOGE("Create input stream fail %s", packagePath.c_str());
192            packageManager->ClosePkgStream(stream);
193            return ret;
194        }
195        size_t fileLen = stream->GetFileLength();
196        if (fileLen <= 0) {
197            PKG_LOGE("invalid file to load");
198            packageManager->ClosePkgStream(stream);
199            return PKG_INVALID_FILE;
200        }
201        if (fileLen > SIZE_MAX) {
202            PKG_LOGE("Invalid file len %zu to load %s", fileLen, stream->GetFileName().c_str());
203            packageManager->ClosePkgStream(stream);
204            return PKG_INVALID_FILE;
205        }
206
207        size_t buffSize = 4096;
208        PkgBuffer buff(buffSize);
209        // 整包检查
210        DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(PKG_DIGEST_TYPE_SHA256);
211        if (algorithm == nullptr) {
212            PKG_LOGE("Invalid file %s", stream->GetFileName().c_str());
213            packageManager->ClosePkgStream(stream);
214            return PKG_NOT_EXIST_ALGORITHM;
215        }
216        algorithm->Init();
217
218        size_t offset = 0;
219        size_t readLen = 0;
220        while (offset < fileLen) {
221            ret = stream->Read(buff, offset, buffSize, readLen);
222            if (ret != PKG_SUCCESS) {
223                PKG_LOGE("read buffer fail %s", stream->GetFileName().c_str());
224                packageManager->ClosePkgStream(stream);
225                return ret;
226            }
227            algorithm->Update(buff, readLen);
228
229            offset += readLen;
230            readLen = 0;
231        }
232        PkgBuffer signBuffer(&digest, size);
233        algorithm->Final(signBuffer);
234        packageManager->ClosePkgStream(stream);
235        return PKG_SUCCESS;
236    }
237
238    int CreatePackageBin(const std::vector<std::string> &inputFile)
239    {
240        int32_t ret = PKG_SUCCESS;
241        uint32_t updateFileVersion = 1000;
242        uint32_t componentInfoIdBase = 100;
243        uint8_t componentInfoFlags = 22;
244        PKG_LOGI("\n\n ************* CreatePackageBin %s \r\n", testPackageName.c_str());
245        UpgradePkgInfoExt pkgInfo;
246        pkgInfo.softwareVersion = strdup("100.100.100.100");
247        pkgInfo.date = strdup("2021-02-02");
248        pkgInfo.time = strdup("21:23:49");
249        pkgInfo.productUpdateId = strdup("555.555.100.555");
250        pkgInfo.entryCount = inputFile.size();
251        pkgInfo.updateFileVersion = updateFileVersion;
252        pkgInfo.digestMethod = PKG_DIGEST_TYPE_SHA256;
253        pkgInfo.signMethod = PKG_SIGN_METHOD_RSA;
254        pkgInfo.pkgType = PKG_PACK_TYPE_UPGRADE;
255        std::string filePath;
256        std::vector<ComponentInfoExt> comp(inputFile.size());
257        for (size_t i = 0; i < inputFile.size(); i++) {
258            comp[i].componentAddr = strdup(inputFile[i].c_str());
259            filePath = TEST_PATH_TO;
260            filePath += inputFile[i].c_str();
261            comp[i].filePath = strdup(filePath.c_str());
262            comp[i].version = strdup("55555555");
263
264            ret = BuildFileDigest(*comp[i].digest, sizeof(comp[i].digest), filePath);
265            comp[i].size = GetFileSize(filePath);
266            comp[i].originalSize = comp[i].size;
267            comp[i].id = componentInfoIdBase;
268            comp[i].resType = 1;
269            comp[i].type = 1;
270            comp[i].flags = componentInfoFlags;
271            filePath.clear();
272        }
273
274        std::string packagePath = TEST_PATH_TO;
275        packagePath += testPackageName;
276        ret = CreatePackage(&pkgInfo, comp, packagePath.c_str(), GetTestPrivateKeyName().c_str());
277        if (ret == 0) {
278            PKG_LOGI("CreatePackage success offset");
279        }
280        for (size_t i = 0; i < inputFile.size(); i++) {
281            free(comp[i].componentAddr);
282            free(comp[i].filePath);
283            free(comp[i].version);
284        }
285        free(pkgInfo.productUpdateId);
286        free(pkgInfo.softwareVersion);
287        free(pkgInfo.date);
288        free(pkgInfo.time);
289        return ret;
290    }
291
292private:
293    PkgManager::PkgManagerPtr packageManager = nullptr;
294    std::string testPackageName = "test_package.bin";
295};
296
297static void ExtractAndExecuteScriptFun(const std::vector<std::string> &inputFile)
298{
299    UScriptTest test;
300    test.TestUscriptExecute(inputFile);
301}
302
303namespace OHOS {
304    void FuzzExtractAndExecuteScript(const uint8_t* data, size_t size)
305    {
306        FILE *pFile;
307        std::vector<std::string> inputFile = {
308            "loadScript.us",
309            "registerCmd.us",
310            "test_function.us",
311            "test_if.us",
312            "test_logic.us",
313            "test_math.us",
314            "test_native.us",
315            "testscript.us",
316            "Verse-script.us",
317            "test_script.us"
318        };
319
320        pFile = fopen("test_script.us", "w+");
321        if (pFile == nullptr) {
322            LOG(ERROR) << "[fuzz]open file failed";
323            return;
324        }
325
326        (void)fwrite(data, 1, size, pFile);
327        (void)fclose(pFile);
328
329        ExtractAndExecuteScriptFun(inputFile);
330        (void)remove("test_script.us");
331    }
332}
333
334/* Fuzzer entry point */
335extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
336{
337    /* Run your code on data */
338    OHOS::FuzzExtractAndExecuteScript(data, size);
339    return 0;
340}
341
342