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 "scriptmanager_fuzzer.h"
17 
18 #include <fcntl.h>
19 #include <iostream>
20 #include <sys/mman.h>
21 #include <unistd.h>
22 #include <vector>
23 #include "hash_data_verifier.h"
24 #include "log.h"
25 #include "pkg_stream.h"
26 #include "pkg_utils.h"
27 #include "scope_guard.h"
28 #include "script_instructionhelper.h"
29 #include "script_manager_impl.h"
30 #include "script_manager.h"
31 #include "script_unittest.h"
32 #include "script_utils.h"
33 #include "utils.h"
34 
35 using namespace Hpackage;
36 using namespace Uscript;
37 using namespace Updater;
38 
39 namespace OHOS {
40 constexpr int32_t SCRIPT_TEST_PRIORITY_NUM = 3;
41 constexpr int32_t SCRIPT_TEST_LAST_PRIORITY = 2;
42 const std::string FUZZ_TEST_PATH_FROM = "/data/fuzz/test/";
43 
44 class TestPkgManager : public TestScriptPkgManager {
45 public:
GetFileInfo(const std::string & fileId)46     const FileInfo *GetFileInfo(const std::string &fileId) override
47     {
48         static FileInfo fileInfo {};
49         static std::vector<std::string> testFileNames = {
50             "loadScript.us",
51             "test_function.us",
52             "test_if.us",
53             "test_logic.us",
54             "testscript.us",
55             "test_math.us",
56             "test_native.us",
57             "Verse-script.us",
58             "test_script.us"
59         };
60         if (std::find(testFileNames.begin(), testFileNames.end(), fileId) != testFileNames.end()) {
61             return &fileInfo;
62         }
63         if (fileId == "hash_signed_data") {
64             fileInfo.unpackedSize = GetFileSize(FUZZ_TEST_PATH_FROM + fileId);
65             return &fileInfo;
66         }
67         return nullptr;
68     }
CreatePkgStream(StreamPtr & stream,const std::string & fileName,const PkgBuffer & buffer)69     int32_t CreatePkgStream(StreamPtr &stream, const std::string &fileName, const PkgBuffer &buffer) override
70     {
71         PKG_LOGI("create pkg stream success for %s ", fileName.c_str());
72         stream = new MemoryMapStream(this, fileName, buffer, PkgStream::PkgStreamType_Buffer);
73         return PKG_SUCCESS;
74     }
ExtractFile(const std::string & fileId,StreamPtr output)75     int32_t ExtractFile(const std::string &fileId, StreamPtr output) override
76     {
77         if (fileId != "hash_signed_data") {
78             return PKG_SUCCESS;
79         }
80         if (output == nullptr) {
81             return PKG_INVALID_STREAM;
82         }
83         auto fd = open((FUZZ_TEST_PATH_FROM + fileId).c_str(), O_RDWR);
84         if (fd == -1) {
85             PKG_LOGE("file %s not existed", (FUZZ_TEST_PATH_FROM + fileId).c_str());
86             return PKG_INVALID_FILE;
87         }
88         ON_SCOPE_EXIT(close) {
89             close(fd);
90         };
91         std::string content {};
92         if (!Utils::ReadFileToString(fd, content)) {
93             PKG_LOGE("read file to string failed");
94             return PKG_INVALID_FILE;
95         }
96         auto stream = static_cast<MemoryMapStream *>(output);
97         PkgBuffer buffer = {};
98         stream->GetBuffer(buffer);
99         if (content.size() + 1 != buffer.length) {
100             PKG_LOGE("content size is not valid, %u != %u", content.size(), buffer.data.size());
101             return PKG_INVALID_FILE;
102         }
103         std::copy(content.begin(), content.end(), buffer.buffer);
104         return PKG_SUCCESS;
105     }
CreatePkgStream(StreamPtr & stream,const std::string & fileName,size_t size,int32_t type)106     int32_t CreatePkgStream(StreamPtr &stream, const std::string &fileName,
107          size_t size, int32_t type) override
108     {
109         FILE *file = nullptr;
110         std::string realFileName = fileName;
111         auto pos = fileName.rfind('/');
112         if (pos != std::string::npos) {
113             realFileName = fileName.substr(pos + 1);
114         }
115         char realPath[PATH_MAX + 1] = {};
116         if (realpath((FUZZ_TEST_PATH_FROM + realFileName).c_str(), realPath) == nullptr) {
117             LOG(ERROR) << (FUZZ_TEST_PATH_FROM + realFileName) << " realpath failed";
118             return PKG_INVALID_FILE;
119         }
120         file = fopen(realPath, "rb");
121         if (file != nullptr) {
122             stream = new FileStream(this, realFileName, file, PkgStream::PkgStreamType_Read);
123             return USCRIPT_SUCCESS;
124         }
125         PKG_LOGE("Fail to open file %s ", realFileName.c_str());
126         return PKG_INVALID_FILE;
127     }
ClosePkgStream(StreamPtr & stream)128     void ClosePkgStream(StreamPtr &stream) override
129     {
130         delete stream;
131     }
132 };
133 
134 class FuzzTestScriptInstructionSparseImageWrite : public Uscript::UScriptInstruction {
135 public:
FuzzTestScriptInstructionSparseImageWrite()136     FuzzTestScriptInstructionSparseImageWrite() {}
~FuzzTestScriptInstructionSparseImageWrite()137     virtual ~FuzzTestScriptInstructionSparseImageWrite() {}
Execute(Uscript::UScriptEnv & env,Uscript::UScriptContext & context)138     int32_t Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context) override
139     {
140         std::string partitionName = {};
141         int32_t ret = context.GetParam(0, partitionName);
142         if (ret != USCRIPT_SUCCESS) {
143             LOG(ERROR) << "Error to get param";
144             return ret;
145         }
146         LOG(INFO) << "UScriptInstructionSparseImageWrite::Execute " << partitionName;
147         if (env.GetPkgManager() != nullptr) {
148             return ret;
149         }
150         LOG(ERROR) << "Error to get pkg manager";
151         return USCRIPT_ERROR_EXECUTE;
152     }
153 };
154 
155 class FuzzTestScriptInstructionFactory : public UScriptInstructionFactory {
156 public:
CreateInstructionInstance(UScriptInstructionPtr & instr,const std::string & name)157     virtual int32_t CreateInstructionInstance(UScriptInstructionPtr& instr, const std::string& name)
158     {
159         if (name == "sparse_image_write") {
160             instr = new (std::nothrow) FuzzTestScriptInstructionSparseImageWrite();
161         }
162         return USCRIPT_SUCCESS;
163     }
DestoryInstructionInstance(UScriptInstructionPtr & instr)164     virtual void DestoryInstructionInstance(UScriptInstructionPtr& instr)
165     {
166         delete instr;
167         instr = nullptr;
168     }
FuzzTestScriptInstructionFactory()169     FuzzTestScriptInstructionFactory() {}
~FuzzTestScriptInstructionFactory()170     virtual ~FuzzTestScriptInstructionFactory() {}
171 };
172 
173 class FuzzTestScriptEnv : public UScriptEnv {
174 public:
FuzzTestScriptEnv(Hpackage::PkgManager::PkgManagerPtr pkgManager)175     explicit FuzzTestScriptEnv(Hpackage::PkgManager::PkgManagerPtr pkgManager) : UScriptEnv(pkgManager) {}
~FuzzTestScriptEnv()176     ~FuzzTestScriptEnv()
177     {
178         if (factory_ != nullptr) {
179             delete factory_;
180             factory_ = nullptr;
181         }
182     }
183 
GetInstructionFactory()184     virtual UScriptInstructionFactoryPtr GetInstructionFactory()
185     {
186         if (factory_ == nullptr) {
187             factory_ = new FuzzTestScriptInstructionFactory();
188         }
189         return factory_;
190     }
191 
PostMessage(const std::string & cmd,std::string content)192     virtual void PostMessage(const std::string &cmd, std::string content) {}
193 
GetInstructionNames() const194     virtual const std::vector<std::string> GetInstructionNames() const
195     {
196         return {"sparse_image_write"};
197     }
198 
IsRetry() const199     virtual bool IsRetry() const
200     {
201         return isRetry;
202     }
203 
GetPostmsgFunc()204     virtual PostMessageFunction GetPostmsgFunc()
205     {
206         return nullptr;
207     }
208     UScriptInstructionFactory *factory_ = nullptr;
209 private:
210     bool isRetry = false;
211 };
212 
213 class FuzzScriptTest {
214 public:
FuzzScriptTest()215     FuzzScriptTest()
216     {
217         InitUpdaterLogger("UPDATER", "updater_log.log", "updater_status.log", "error_code.log");
218     }
219 
~FuzzScriptTest()220     ~FuzzScriptTest()
221     {
222         ScriptManager::ReleaseScriptManager();
223     }
224 
TestUscriptExecute(std::string & path)225     int TestUscriptExecute(std::string &path)
226     {
227         int32_t ret {};
228         TestPkgManager packageManager;
229         auto env = std::make_unique<FuzzTestScriptEnv>(&packageManager);
230         HashDataVerifier verifier {&packageManager};
231         verifier.LoadHashDataAndPkcs7(path);
232         ScriptManager *manager = ScriptManager::GetScriptManager(env.get(), &verifier);
233         if (manager == nullptr) {
234             USCRIPT_LOGI("create manager fail ret:%d", ret);
235             return USCRIPT_INVALID_SCRIPT;
236         }
237         for (auto priority : {SCRIPT_TEST_PRIORITY_NUM, 0, 1, SCRIPT_TEST_LAST_PRIORITY}) {
238             ret = manager->ExecuteScript(priority);
239             USCRIPT_LOGI("ExecuteScript ret:%d", ret);
240         }
241         ScriptManager::ReleaseScriptManager();
242         return ret;
243     }
244 
245 protected:
SetUp()246     void SetUp() {}
TearDown()247     void TearDown() {}
TestBody()248     void TestBody() {}
249 
250 private:
251     std::vector<std::string> testFileNames_ = {
252         "loadScript.us",
253         "registerCmd.us",
254         "test_function.us",
255         "test_math.us",
256         "test_logic.us",
257         "test_native.us",
258         "test_script.us"
259         "test_if.us",
260         "testscript.us",
261         "Verse-script.us",
262     };
263 };
264 
FuzzScriptManager(const uint8_t * data,size_t size)265 void FuzzScriptManager(const uint8_t *data, size_t size)
266 {
267     FuzzScriptTest test;
268     std::string path = std::string(reinterpret_cast<const char*>(data), size);
269     test.TestUscriptExecute(path);
270 }
271 }
272 
273 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)274 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
275 {
276     /* Run your code on data */
277     OHOS::FuzzScriptManager(data, size);
278     return 0;
279 }
280 
281