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 
37 using namespace Hpackage;
38 using namespace Uscript;
39 using namespace Updater;
40 
41 const static std::string TEST_PATH_TO = "/data/fuzz/test/";
42 const static int32_t SCRIPT_TEST_PRIORITY_NUM = 3;
43 const static int32_t SCRIPT_TEST_LAST_PRIORITY = 2;
44 
GetTestCertName()45 static inline std::string GetTestCertName()
46 {
47     std::string name = TEST_PATH_TO;
48     name += "signing_cert.crt";
49     return name;
50 }
51 
GetTestPrivateKeyName()52 static inline std::string GetTestPrivateKeyName()
53 {
54     std::string name = TEST_PATH_TO;
55     name += "rsa_private_key2048.pem";
56     return name;
57 }
58 
59 class TestScriptInstructionSparseImageWrite : public Uscript::UScriptInstruction {
60 public:
TestScriptInstructionSparseImageWrite()61     TestScriptInstructionSparseImageWrite() {}
~TestScriptInstructionSparseImageWrite()62     virtual ~TestScriptInstructionSparseImageWrite() {}
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)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 
78 class TestScriptInstructionFactory : public UScriptInstructionFactory {
79 public:
CreateInstructionInstance(UScriptInstructionPtr & instr,const std::string & name)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     }
DestoryInstructionInstance(UScriptInstructionPtr & instr)87     virtual void DestoryInstructionInstance(UScriptInstructionPtr& instr)
88     {
89         delete instr;
90     }
TestScriptInstructionFactory()91     TestScriptInstructionFactory() {}
~TestScriptInstructionFactory()92     virtual ~TestScriptInstructionFactory() {}
93 };
94 
95 class UTestScriptEnv : public UScriptEnv {
96 public:
97     UScriptInstructionFactory *factory_ = nullptr;
UTestScriptEnv(Hpackage::PkgManager::PkgManagerPtr pkgManager)98     explicit UTestScriptEnv(Hpackage::PkgManager::PkgManagerPtr pkgManager) : UScriptEnv(pkgManager) {}
~UTestScriptEnv()99     ~UTestScriptEnv()
100     {
101         if (factory_ != nullptr) {
102             delete factory_;
103             factory_ = nullptr;
104         }
105     }
106 
PostMessage(const std::string & cmd,std::string content)107     virtual void PostMessage(const std::string &cmd, std::string content) {}
108 
GetInstructionFactory()109     virtual UScriptInstructionFactoryPtr GetInstructionFactory()
110     {
111         if (factory_ == nullptr) {
112             factory_ = new TestScriptInstructionFactory();
113         }
114         return factory_;
115     }
116 
GetInstructionNames() const117     virtual const std::vector<std::string> GetInstructionNames() const
118     {
119         static std::vector<std::string> updaterCmds = {"sparse_image_write"};
120         return updaterCmds;
121     }
122 
IsRetry() const123     virtual bool IsRetry() const
124     {
125         return isRetry;
126     }
127 
GetPostmsgFunc()128     virtual PostMessageFunction GetPostmsgFunc()
129     {
130         return nullptr;
131     }
132 private:
133     bool isRetry = false;
134 };
135 
136 class UScriptTest {
137 public:
UScriptTest()138     UScriptTest()
139     {
140         packageManager = PkgManager::CreatePackageInstance();
141     }
142 
~UScriptTest()143     ~UScriptTest()
144     {
145         PkgManager::ReleasePackageInstance(packageManager);
146         ScriptManager::ReleaseScriptManager();
147     }
148 
TestUscriptExecute(const std::vector<std::string> & inputFile)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 
185 protected:
BuildFileDigest(uint8_t & digest,size_t size,const std::string & packagePath)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 
CreatePackageBin(const std::vector<std::string> & inputFile)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 
292 private:
293     PkgManager::PkgManagerPtr packageManager = nullptr;
294     std::string testPackageName = "test_package.bin";
295 };
296 
ExtractAndExecuteScriptFun(const std::vector<std::string> & inputFile)297 static void ExtractAndExecuteScriptFun(const std::vector<std::string> &inputFile)
298 {
299     UScriptTest test;
300     test.TestUscriptExecute(inputFile);
301 }
302 
303 namespace OHOS {
FuzzExtractAndExecuteScript(const uint8_t * data,size_t size)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 */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)335 extern "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