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