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