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 private:
128 bool isRetry = false;
129 };
130
131 class UScriptTest {
132 public:
UScriptTest()133 UScriptTest()
134 {
135 packageManager = PkgManager::CreatePackageInstance();
136 }
137
~UScriptTest()138 ~UScriptTest()
139 {
140 PkgManager::ReleasePackageInstance(packageManager);
141 ScriptManager::ReleaseScriptManager();
142 }
143
TestUscriptExecute(const std::vector<std::string> & inputFile)144 int TestUscriptExecute(const std::vector<std::string> &inputFile)
145 {
146 CreatePackageBin(inputFile);
147 if (packageManager == nullptr) {
148 return PKG_SUCCESS;
149 }
150 std::vector<std::string> components;
151 int32_t ret = packageManager->LoadPackage(TEST_PATH_TO + testPackageName, GetTestCertName(), components);
152 if (ret != USCRIPT_SUCCESS) {
153 USCRIPT_LOGI("LoadPackage fail ret:%d", ret);
154 return USCRIPT_INVALID_SCRIPT;
155 }
156
157 UTestScriptEnv* env = new UTestScriptEnv(packageManager);
158 Hpackage::HashDataVerifier scriptVerifier {packageManager};
159 ScriptManager* manager = ScriptManager::GetScriptManager(env, &scriptVerifier);
160 if (manager == nullptr) {
161 USCRIPT_LOGI("create manager fail ret:%d", ret);
162 delete env;
163 return USCRIPT_INVALID_SCRIPT;
164 }
165 int32_t priority = SCRIPT_TEST_PRIORITY_NUM;
166 ret = manager->ExecuteScript(priority);
167 USCRIPT_LOGI("ExecuteScript ret:%d", ret);
168 priority = 0;
169 ret = manager->ExecuteScript(priority);
170 USCRIPT_LOGI("ExecuteScript ret:%d", ret);
171 priority = 1;
172 ret = manager->ExecuteScript(priority);
173 priority = SCRIPT_TEST_LAST_PRIORITY;
174 ret = manager->ExecuteScript(priority);
175 delete env;
176 ScriptManager::ReleaseScriptManager();
177 return ret;
178 }
179
180 protected:
BuildFileDigest(uint8_t & digest,size_t size,const std::string & packagePath)181 int32_t BuildFileDigest(uint8_t &digest, size_t size, const std::string &packagePath)
182 {
183 PkgManager::StreamPtr stream = nullptr;
184 int32_t ret = packageManager->CreatePkgStream(stream, packagePath, 0, PkgStream::PkgStreamType_Read);
185 if (ret != PKG_SUCCESS) {
186 PKG_LOGE("Create input stream fail %s", packagePath.c_str());
187 packageManager->ClosePkgStream(stream);
188 return ret;
189 }
190 size_t fileLen = stream->GetFileLength();
191 if (fileLen <= 0) {
192 PKG_LOGE("invalid file to load");
193 packageManager->ClosePkgStream(stream);
194 return PKG_INVALID_FILE;
195 }
196 if (fileLen > SIZE_MAX) {
197 PKG_LOGE("Invalid file len %zu to load %s", fileLen, stream->GetFileName().c_str());
198 packageManager->ClosePkgStream(stream);
199 return PKG_INVALID_FILE;
200 }
201
202 size_t buffSize = 4096;
203 PkgBuffer buff(buffSize);
204 // 整包检查
205 DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(PKG_DIGEST_TYPE_SHA256);
206 if (algorithm == nullptr) {
207 PKG_LOGE("Invalid file %s", stream->GetFileName().c_str());
208 packageManager->ClosePkgStream(stream);
209 return PKG_NOT_EXIST_ALGORITHM;
210 }
211 algorithm->Init();
212
213 size_t offset = 0;
214 size_t readLen = 0;
215 while (offset < fileLen) {
216 ret = stream->Read(buff, offset, buffSize, readLen);
217 if (ret != PKG_SUCCESS) {
218 PKG_LOGE("read buffer fail %s", stream->GetFileName().c_str());
219 packageManager->ClosePkgStream(stream);
220 return ret;
221 }
222 algorithm->Update(buff, readLen);
223
224 offset += readLen;
225 readLen = 0;
226 }
227 PkgBuffer signBuffer(&digest, size);
228 algorithm->Final(signBuffer);
229 packageManager->ClosePkgStream(stream);
230 return PKG_SUCCESS;
231 }
232
CreatePackageBin(const std::vector<std::string> & inputFile)233 int CreatePackageBin(const std::vector<std::string> &inputFile)
234 {
235 int32_t ret = PKG_SUCCESS;
236 uint32_t updateFileVersion = 1000;
237 uint32_t componentInfoIdBase = 100;
238 uint8_t componentInfoFlags = 22;
239 PKG_LOGI("\n\n ************* CreatePackageBin %s \r\n", testPackageName.c_str());
240 UpgradePkgInfoExt pkgInfo;
241 pkgInfo.softwareVersion = strdup("100.100.100.100");
242 pkgInfo.date = strdup("2021-02-02");
243 pkgInfo.time = strdup("21:23:49");
244 pkgInfo.productUpdateId = strdup("555.555.100.555");
245 pkgInfo.entryCount = inputFile.size();
246 pkgInfo.updateFileVersion = updateFileVersion;
247 pkgInfo.digestMethod = PKG_DIGEST_TYPE_SHA256;
248 pkgInfo.signMethod = PKG_SIGN_METHOD_RSA;
249 pkgInfo.pkgType = PKG_PACK_TYPE_UPGRADE;
250 std::string filePath;
251 ComponentInfoExt comp[inputFile.size()];
252 for (size_t i = 0; i < inputFile.size(); i++) {
253 comp[i].componentAddr = strdup(inputFile[i].c_str());
254 filePath = TEST_PATH_TO;
255 filePath += inputFile[i].c_str();
256 comp[i].filePath = strdup(filePath.c_str());
257 comp[i].version = strdup("55555555");
258
259 ret = BuildFileDigest(*comp[i].digest, sizeof(comp[i].digest), filePath);
260 comp[i].size = GetFileSize(filePath);
261 comp[i].originalSize = comp[i].size;
262 comp[i].id = componentInfoIdBase;
263 comp[i].resType = 1;
264 comp[i].type = 1;
265 comp[i].flags = componentInfoFlags;
266 filePath.clear();
267 }
268
269 std::string packagePath = TEST_PATH_TO;
270 packagePath += testPackageName;
271 ret = CreatePackage(&pkgInfo, comp, packagePath.c_str(), GetTestPrivateKeyName().c_str());
272 if (ret == 0) {
273 PKG_LOGI("CreatePackage success offset");
274 }
275 for (size_t i = 0; i < inputFile.size(); i++) {
276 free(comp[i].componentAddr);
277 free(comp[i].filePath);
278 free(comp[i].version);
279 }
280 free(pkgInfo.productUpdateId);
281 free(pkgInfo.softwareVersion);
282 free(pkgInfo.date);
283 free(pkgInfo.time);
284 return ret;
285 }
286
287 private:
288 PkgManager::PkgManagerPtr packageManager = nullptr;
289 std::string testPackageName = "test_package.bin";
290 };
291
ExtractAndExecuteScriptFun(const std::vector<std::string> & inputFile)292 static void ExtractAndExecuteScriptFun(const std::vector<std::string> &inputFile)
293 {
294 UScriptTest test;
295 test.TestUscriptExecute(inputFile);
296 }
297
298 namespace OHOS {
FuzzExtractAndExecuteScript(const uint8_t * data,size_t size)299 void FuzzExtractAndExecuteScript(const uint8_t* data, size_t size)
300 {
301 FILE *pFile;
302 std::vector<std::string> inputFile = {
303 "loadScript.us",
304 "registerCmd.us",
305 "test_function.us",
306 "test_if.us",
307 "test_logic.us",
308 "test_math.us",
309 "test_native.us",
310 "testscript.us",
311 "Verse-script.us",
312 "test_script.us"
313 };
314
315 pFile = fopen("test_script.us", "w+");
316 if (pFile == nullptr) {
317 LOG(ERROR) << "[fuzz]open file failed";
318 return;
319 }
320
321 (void)fwrite(data, 1, size, pFile);
322 (void)fclose(pFile);
323
324 ExtractAndExecuteScriptFun(inputFile);
325 (void)remove("test_script.us");
326 }
327 }
328
329 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)330 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
331 {
332 /* Run your code on data */
333 OHOS::FuzzExtractAndExecuteScript(data, size);
334 return 0;
335 }
336
337