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