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#include "update_image_block.h" 16#include <cerrno> 17#include <fcntl.h> 18#include <pthread.h> 19#include <sstream> 20#include <sys/stat.h> 21#include <sys/types.h> 22#include <unistd.h> 23#include "applypatch/block_set.h" 24#include "applypatch/store.h" 25#include "applypatch/transfer_manager.h" 26#include "applypatch/partition_record.h" 27#include "fs_manager/mount.h" 28#include "log/dump.h" 29#include "log/log.h" 30#include "updater/updater_const.h" 31#include "updater/hwfault_retry.h" 32#include "utils.h" 33 34using namespace Uscript; 35using namespace Hpackage; 36using namespace Updater; 37 38namespace Updater { 39constexpr int32_t SHA_CHECK_SECOND = 2; 40constexpr int32_t SHA_CHECK_PARAMS = 3; 41constexpr int32_t SHA_CHECK_TARGETPAIRS_INDEX = 3; 42constexpr int32_t SHA_CHECK_TARGETSHA_INDEX = 4; 43constexpr int32_t SHA_CHECK_TARGET_PARAMS = 5; 44static int ExtractNewData(const PkgBuffer &buffer, size_t size, size_t start, bool isFinish, const void* context) 45{ 46 void *p = const_cast<void *>(context); 47 WriterThreadInfo *info = static_cast<WriterThreadInfo *>(p); 48 uint8_t *addr = buffer.buffer; 49 while (size > 0) { 50 pthread_mutex_lock(&info->mutex); 51 while (info->writer == nullptr) { 52 if (!info->readyToWrite) { 53 LOG(WARNING) << "writer is not ready to write."; 54 pthread_mutex_unlock(&info->mutex); 55 return Hpackage::PKG_INVALID_STREAM; 56 } 57 pthread_cond_wait(&info->cond, &info->mutex); 58 } 59 pthread_mutex_unlock(&info->mutex); 60 size_t toWrite = std::min(size, info->writer->GetBlocksSize() - info->writer->GetTotalWritten()); 61 // No more data to write. 62 if (toWrite == 0) { 63 break; 64 } 65 bool ret = info->writer->Write(addr, toWrite, nullptr); 66 std::ostringstream logMessage; 67 logMessage << "Write " << toWrite << " byte(s) failed"; 68 if (!ret) { 69 LOG(ERROR) << logMessage.str(); 70 return Hpackage::PKG_INVALID_STREAM; 71 } 72 size -= toWrite; 73 addr += toWrite; 74 75 if (info->writer->IsWriteDone()) { 76 pthread_mutex_lock(&info->mutex); 77 info->writer.reset(); 78 pthread_cond_broadcast(&info->cond); 79 pthread_mutex_unlock(&info->mutex); 80 } 81 } 82 return Hpackage::PKG_SUCCESS; 83} 84 85static inline void CondBroadcast(WriterThreadInfo *info) 86{ 87 pthread_mutex_lock(&info->mutex); 88 info->readyToWrite = false; 89 if (info->writer != nullptr) { 90 pthread_cond_broadcast(&info->cond); 91 } 92 pthread_mutex_unlock(&info->mutex); 93} 94 95void* UnpackNewData(void *arg) 96{ 97 TransferManagerPtr tm = static_cast<TransferManagerPtr>(arg); 98 WriterThreadInfo *info = tm->GetTransferParams()->writerThreadInfo.get(); 99 Hpackage::PkgManager::StreamPtr stream = nullptr; 100 if (info->newPatch.empty()) { 101 LOG(ERROR) << "new patch file name is empty. thread quit."; 102 CondBroadcast(info); 103 return nullptr; 104 } 105 LOG(DEBUG) << "new patch file name: " << info->newPatch; 106 auto env = tm->GetTransferParams()->env; 107 const FileInfo *file = env->GetPkgManager()->GetFileInfo(info->newPatch); 108 if (file == nullptr) { 109 LOG(ERROR) << "Cannot get file info of :" << info->newPatch; 110 CondBroadcast(info); 111 return nullptr; 112 } 113 LOG(DEBUG) << info->newPatch << " info: size " << file->packedSize << " unpacked size " << 114 file->unpackedSize << " name " << file->identity; 115 int32_t ret = env->GetPkgManager()->CreatePkgStream(stream, info->newPatch, ExtractNewData, info); 116 if (ret != Hpackage::PKG_SUCCESS || stream == nullptr) { 117 LOG(ERROR) << "Cannot extract " << info->newPatch << " from package."; 118 CondBroadcast(info); 119 return nullptr; 120 } 121 ret = env->GetPkgManager()->ExtractFile(info->newPatch, stream); 122 env->GetPkgManager()->ClosePkgStream(stream); 123 LOG(DEBUG) << "new data writer ending..."; 124 // extract new data done. 125 // tell command. 126 CondBroadcast(info); 127 return nullptr; 128} 129 130static int32_t ReturnAndPushParam(int32_t returnValue, Uscript::UScriptContext &context) 131{ 132 context.PushParam(returnValue); 133 return returnValue; 134} 135 136struct UpdateBlockInfo { 137 std::string partitionName; 138 std::string transferName; 139 std::string newDataName; 140 std::string patchDataName; 141 std::string devPath; 142}; 143 144static int32_t GetUpdateBlockInfo(struct UpdateBlockInfo &infos, Uscript::UScriptEnv &env, 145 Uscript::UScriptContext &context) 146{ 147 if (context.GetParamCount() != 4) { // 4:Determine the number of parameters 148 LOG(ERROR) << "Invalid param"; 149 return ReturnAndPushParam(USCRIPT_INVALID_PARAM, context); 150 } 151 152 // Get partition Name first. 153 // Use partition name as zip file name. ${partition name}.zip 154 // load ${partition name}.zip from updater package. 155 // Try to unzip ${partition name}.zip, extract transfer.list, net.dat, patch.dat 156 size_t pos = 0; 157 int32_t ret = context.GetParam(pos++, infos.partitionName); 158 if (ret != USCRIPT_SUCCESS) { 159 LOG(ERROR) << "Error to get param 1"; 160 return ret; 161 } 162 ret = context.GetParam(pos++, infos.transferName); 163 if (ret != USCRIPT_SUCCESS) { 164 LOG(ERROR) << "Error to get param 2"; 165 return ret; 166 } 167 ret = context.GetParam(pos++, infos.newDataName); 168 if (ret != USCRIPT_SUCCESS) { 169 LOG(ERROR) << "Error to get param 3"; 170 return ret; 171 } 172 ret = context.GetParam(pos++, infos.patchDataName); 173 if (ret != USCRIPT_SUCCESS) { 174 LOG(ERROR) << "Error to get param 4"; 175 return ret; 176 } 177 178 LOG(INFO) << "ExecuteUpdateBlock::updating " << infos.partitionName << " ..."; 179 infos.devPath = GetBlockDeviceByMountPoint(infos.partitionName); 180 LOG(INFO) << "ExecuteUpdateBlock::updating dev path : " << infos.devPath; 181 if (infos.devPath.empty()) { 182 LOG(ERROR) << "cannot get block device of partition"; 183 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); 184 } 185 return USCRIPT_SUCCESS; 186} 187 188static int32_t ExecuteTransferCommand(int fd, const std::vector<std::string> &lines, TransferManagerPtr tm, 189 Uscript::UScriptContext &context, const UpdateBlockInfo &infos) 190{ 191 auto transferParams = tm->GetTransferParams(); 192 auto writerThreadInfo = transferParams->writerThreadInfo.get(); 193 194 transferParams->storeBase = std::string("/data/updater") + infos.partitionName + "_tmp"; 195 transferParams->retryFile = std::string("/data/updater") + infos.partitionName + "_retry"; 196 transferParams->devPath = infos.devPath; 197 LOG(INFO) << "Store base path is " << transferParams->storeBase; 198 int32_t ret = Store::CreateNewSpace(transferParams->storeBase, !transferParams->env->IsRetry()); 199 if (ret == -1) { 200 LOG(ERROR) << "Error to create new store space"; 201 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); 202 } 203 transferParams->storeCreated = ret; 204 205 if (!tm->CommandsParser(fd, lines)) { 206 return USCRIPT_ERROR_EXECUTE; 207 } 208 pthread_mutex_lock(&writerThreadInfo->mutex); 209 if (writerThreadInfo->readyToWrite) { 210 LOG(WARNING) << "New data writer thread is still available..."; 211 } 212 213 writerThreadInfo->readyToWrite = false; 214 pthread_cond_broadcast(&writerThreadInfo->cond); 215 pthread_mutex_unlock(&writerThreadInfo->mutex); 216 ret = pthread_join(transferParams->thread, nullptr); 217 std::ostringstream logMessage; 218 logMessage << "pthread join returned with " << ret; 219 if (ret != 0) { 220 LOG(WARNING) << logMessage.str(); 221 } 222 if (transferParams->storeCreated != -1) { 223 Store::DoFreeSpace(transferParams->storeBase); 224 } 225 return USCRIPT_SUCCESS; 226} 227 228static int InitThread(const struct UpdateBlockInfo &infos, TransferManagerPtr tm) 229{ 230 auto transferParams = tm->GetTransferParams(); 231 auto writerThreadInfo = transferParams->writerThreadInfo.get(); 232 writerThreadInfo->readyToWrite = true; 233 pthread_mutex_init(&writerThreadInfo->mutex, nullptr); 234 pthread_cond_init(&writerThreadInfo->cond, nullptr); 235 pthread_attr_t attr; 236 pthread_attr_init(&attr); 237 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 238 writerThreadInfo->newPatch = infos.newDataName; 239 int error = pthread_create(&transferParams->thread, &attr, UnpackNewData, tm); 240 return error; 241} 242 243static int32_t ExtractDiffPackageAndLoad(const UpdateBlockInfo &infos, Uscript::UScriptEnv &env, 244 Uscript::UScriptContext &context) 245{ 246 Hpackage::PkgManager::StreamPtr outStream = nullptr; 247 LOG(DEBUG) << "partitionName is " << infos.partitionName; 248 const FileInfo *info = env.GetPkgManager()->GetFileInfo(infos.partitionName); 249 if (info == nullptr) { 250 LOG(WARNING) << "Error to get file info"; 251 return USCRIPT_SUCCESS; 252 } 253 std::string diffPackage = std::string("/data/updater") + infos.partitionName; 254 int32_t ret = env.GetPkgManager()->CreatePkgStream(outStream, 255 diffPackage, info->unpackedSize, PkgStream::PkgStreamType_Write); 256 if (outStream == nullptr) { 257 LOG(ERROR) << "Error to create output stream"; 258 return USCRIPT_ERROR_EXECUTE; 259 } 260 261 ret = env.GetPkgManager()->ExtractFile(infos.partitionName, outStream); 262 if (ret != USCRIPT_SUCCESS) { 263 LOG(ERROR) << "Error to extract file"; 264 env.GetPkgManager()->ClosePkgStream(outStream); 265 return USCRIPT_ERROR_EXECUTE; 266 } 267 env.GetPkgManager()->ClosePkgStream(outStream); 268 std::string diffPackageZip = diffPackage + ".zip"; 269 if (rename(diffPackage.c_str(), diffPackageZip.c_str()) != 0) { 270 LOG(ERROR) << "rename failed"; 271 return USCRIPT_ERROR_EXECUTE; 272 } 273 LOG(DEBUG) << "Rename " << diffPackage << " to zip\nExtract " << diffPackage << " done\nReload " << diffPackageZip; 274 std::vector<std::string> diffPackageComponents; 275 ret = env.GetPkgManager()->LoadPackage(diffPackageZip, Updater::Utils::GetCertName(), diffPackageComponents); 276 if (diffPackageComponents.size() < 1) { 277 LOG(ERROR) << "Diff package is empty"; 278 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); 279 } 280 return USCRIPT_SUCCESS; 281} 282 283static int32_t DoExecuteUpdateBlock(const UpdateBlockInfo &infos, TransferManagerPtr tm, 284 Hpackage::PkgManager::StreamPtr &outStream, const std::vector<std::string> &lines, Uscript::UScriptContext &context) 285{ 286 int fd = open(infos.devPath.c_str(), O_RDWR | O_LARGEFILE); 287 auto env = tm->GetTransferParams()->env; 288 if (fd == -1) { 289 LOG(ERROR) << "Failed to open block"; 290 env->GetPkgManager()->ClosePkgStream(outStream); 291 return USCRIPT_ERROR_EXECUTE; 292 } 293 int32_t ret = ExecuteTransferCommand(fd, lines, tm, context, infos); 294 fsync(fd); 295 close(fd); 296 fd = -1; 297 env->GetPkgManager()->ClosePkgStream(outStream); 298 if (ret == USCRIPT_SUCCESS) { 299 PartitionRecord::GetInstance().RecordPartitionUpdateStatus(infos.partitionName, true); 300 } 301 return ret; 302} 303 304static int32_t ExtractFileByName(Uscript::UScriptEnv &env, const std::string &fileName, 305 Hpackage::PkgManager::StreamPtr &outStream, uint8_t *&outBuf, size_t &buffSize) 306{ 307 if (env.GetPkgManager() == nullptr) { 308 LOG(ERROR) << "Error to get pkg manager"; 309 return USCRIPT_ERROR_EXECUTE; 310 } 311 312 const FileInfo *info = env.GetPkgManager()->GetFileInfo(fileName); 313 if (info == nullptr) { 314 LOG(ERROR) << "GetFileInfo fail"; 315 return USCRIPT_ERROR_EXECUTE; 316 } 317 auto ret = env.GetPkgManager()->CreatePkgStream(outStream, 318 fileName, info->unpackedSize, PkgStream::PkgStreamType_MemoryMap); 319 if (ret != USCRIPT_SUCCESS || outStream == nullptr) { 320 LOG(ERROR) << "Error to create output stream"; 321 return USCRIPT_ERROR_EXECUTE; 322 } 323 ret = env.GetPkgManager()->ExtractFile(fileName, outStream); 324 if (ret != USCRIPT_SUCCESS) { 325 LOG(ERROR) << "Error to extract file"; 326 env.GetPkgManager()->ClosePkgStream(outStream); 327 return USCRIPT_ERROR_EXECUTE; 328 } 329 ret = outStream->GetBuffer(outBuf, buffSize); 330 LOG(DEBUG) << "outBuf data size is: " << buffSize; 331 332 return USCRIPT_SUCCESS; 333} 334 335static int32_t ExecuteUpdateBlock(Uscript::UScriptEnv &env, Uscript::UScriptContext &context) 336{ 337 UpdateBlockInfo infos {}; 338 if (GetUpdateBlockInfo(infos, env, context) != USCRIPT_SUCCESS) { 339 return USCRIPT_ERROR_EXECUTE; 340 } 341 342 if (env.IsRetry()) { 343 LOG(DEBUG) << "Retry updater, check if current partition updatered already during last time"; 344 if (PartitionRecord::GetInstance().IsPartitionUpdated(infos.partitionName)) { 345 LOG(INFO) << infos.partitionName << " already updated, skip"; 346 return USCRIPT_SUCCESS; 347 } 348 } 349 350 if (ExtractDiffPackageAndLoad(infos, env, context) != USCRIPT_SUCCESS) { 351 return USCRIPT_ERROR_EXECUTE; 352 } 353 354 uint8_t *transferListBuffer = nullptr; 355 size_t transferListSize = 0; 356 Hpackage::PkgManager::StreamPtr outStream = nullptr; 357 if (ExtractFileByName(env, infos.transferName, outStream, 358 transferListBuffer, transferListSize) != USCRIPT_SUCCESS) { 359 return USCRIPT_ERROR_EXECUTE; 360 } 361 362 std::unique_ptr<TransferManager> tm = std::make_unique<TransferManager>(); 363 364 auto transferParams = tm->GetTransferParams(); 365 /* Save Script Env to transfer manager */ 366 transferParams->env = &env; 367 368 transferParams->canWrite = true; 369 std::vector<std::string> lines = 370 Updater::Utils::SplitString(std::string(reinterpret_cast<const char*>(transferListBuffer)), "\n"); 371 // Close stream opened before. 372 env.GetPkgManager()->ClosePkgStream(outStream); 373 374 LOG(INFO) << "Start unpack new data thread done. Get patch data: " << infos.patchDataName; 375 if (ExtractFileByName(env, infos.patchDataName, outStream, 376 transferParams->patchDataBuffer, transferParams->patchDataSize) != USCRIPT_SUCCESS) { 377 return USCRIPT_ERROR_EXECUTE; 378 } 379 380 LOG(INFO) << "Ready to start a thread to handle new data processing"; 381 if (InitThread(infos, tm.get()) != 0) { 382 LOG(ERROR) << "Failed to create pthread"; 383 env.GetPkgManager()->ClosePkgStream(outStream); 384 return USCRIPT_ERROR_EXECUTE; 385 } 386 387 return DoExecuteUpdateBlock(infos, tm.get(), outStream, lines, context); 388} 389 390int32_t UScriptInstructionBlockUpdate::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context) 391{ 392 int32_t result = ExecuteUpdateBlock(env, context); 393 context.PushParam(result); 394 return result; 395} 396 397bool UScriptInstructionBlockCheck::ExecReadBlockInfo(const std::string &devPath, Uscript::UScriptContext &context, 398 time_t &mountTime, uint16_t &mountCount) 399{ 400 UPDATER_INIT_RECORD; 401 int fd = open(devPath.c_str(), O_RDWR | O_LARGEFILE); 402 if (fd == -1) { 403 LOG(ERROR) << "Failed to open file"; 404 UPDATER_LAST_WORD(false); 405 return false; 406 } 407 std::vector<uint8_t> block_buff(H_BLOCK_SIZE); 408 BlockSet blk0(std::vector<BlockPair> {BlockPair{0, 1}}); 409 410 size_t pos = 0; 411 std::vector<BlockPair>::iterator it = blk0.Begin(); 412 for (; it != blk0.End(); ++it) { 413 LOG(INFO) << "BlockSet::ReadDataFromBlock lseek64"; 414 if (lseek64(fd, static_cast<off64_t>(it->first * H_BLOCK_SIZE), SEEK_SET) == -1) { 415 LOG(ERROR) << "Failed to seek"; 416 close(fd); 417 UPDATER_LAST_WORD(false); 418 return false; 419 } 420 size_t size = (it->second - it->first) * H_BLOCK_SIZE; 421 LOG(INFO) << "BlockSet::ReadDataFromBlock Read " << size << " from block"; 422 if (!Utils::ReadFully(fd, block_buff.data() + pos, size)) { 423 LOG(ERROR) << "Failed to read"; 424 close(fd); 425 UPDATER_LAST_WORD(false); 426 return false; 427 } 428 pos += size; 429 } 430 close(fd); 431 mountTime = *reinterpret_cast<uint32_t *>(&block_buff[0x400 + 0x2C]); 432 mountCount = *reinterpret_cast<uint16_t *>(&block_buff[0x400 + 0x34]); 433 return true; 434} 435 436int32_t UScriptInstructionBlockCheck::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context) 437{ 438 if (context.GetParamCount() != 1) { 439 LOG(ERROR) << "Invalid param"; 440 UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); 441 return ReturnAndPushParam(USCRIPT_INVALID_PARAM, context); 442 } 443 if (env.IsRetry()) { 444 return ReturnAndPushParam(USCRIPT_SUCCESS, context); 445 } 446 std::string partitionName; 447 int32_t ret = context.GetParam(0, partitionName); 448 if (ret != USCRIPT_SUCCESS) { 449 LOG(ERROR) << "Failed to get param"; 450 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 451 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); 452 } 453 auto devPath = GetBlockDeviceByMountPoint(partitionName); 454 LOG(INFO) << "UScriptInstructionBlockCheck::dev path : " << devPath; 455 time_t mountTime = 0; 456 uint16_t mountCount = 0; 457 if (devPath.empty() || (!ExecReadBlockInfo(devPath, context, mountTime, mountCount))) { 458 LOG(ERROR) << "cannot get block device of partition"; 459 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 460 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); 461 } 462 463 if (mountCount > 0) { 464 std::ostringstream ostr; 465 ostr << "Device was remounted R/W " << mountCount << "times\nLast remount happened on " << 466 ctime(&mountTime) << std::endl; 467 std::string message = ostr.str(); 468 env.PostMessage("ui_log", message); 469 LOG(ERROR) << message; 470 } 471 LOG(INFO) << "UScriptInstructionBlockCheck::Execute Success"; 472 context.PushParam(USCRIPT_SUCCESS); 473 return USCRIPT_SUCCESS; 474} 475 476static std::string GetPartName(const std::string &partitionName) 477{ 478 if (partitionName.empty()) { 479 return ""; 480 } 481 return partitionName[0] == '/' ? partitionName.substr(1) : partitionName; 482} 483 484int32_t UScriptInstructionShaCheck::DoBlocksVerify(Uscript::UScriptEnv &env, const std::string &partitionName, 485 const std::string &devPath) 486{ 487 UpdateBlockInfo infos {}; 488 infos.partitionName = partitionName; 489 infos.transferName = GetPartName(partitionName) + ".transfer.list"; 490 uint8_t *transferListBuffer = nullptr; 491 size_t transferListSize = 0; 492 Hpackage::PkgManager::StreamPtr outStream = nullptr; 493 494 if (ExtractFileByName(env, infos.transferName, outStream, 495 transferListBuffer, transferListSize) != USCRIPT_SUCCESS) { 496 LOG(ERROR) << "Error to extract " << infos.transferName; 497 return USCRIPT_ERROR_EXECUTE; 498 } 499 500 std::vector<std::string> lines = 501 Updater::Utils::SplitString(std::string(reinterpret_cast<const char*>(transferListBuffer)), "\n"); 502 // Close stream opened before. 503 env.GetPkgManager()->ClosePkgStream(outStream); 504 505 std::unique_ptr<TransferManager> tm = std::make_unique<TransferManager>(); 506 auto transferParams = tm->GetTransferParams(); 507 transferParams->env = &env; 508 transferParams->canWrite = false; 509 transferParams->devPath = devPath; 510 transferParams->storeBase = std::string("/data/updater") + partitionName + "_tmp"; 511 transferParams->retryFile = std::string("/data/updater") + partitionName + "_retry"; 512 513 LOG(INFO) << "Store base path is " << transferParams->storeBase; 514 transferParams->storeCreated = Store::CreateNewSpace(transferParams->storeBase, !transferParams->env->IsRetry()); 515 if (transferParams->storeCreated == -1) { 516 LOG(ERROR) << "Error to create new store space"; 517 return USCRIPT_ERROR_EXECUTE; 518 } 519 int fd = open(devPath.c_str(), O_RDWR | O_LARGEFILE); 520 if (fd == -1) { 521 LOG(ERROR) << "Failed to open block"; 522 return USCRIPT_ERROR_EXECUTE; 523 } 524 if (!tm->CommandsParser(fd, lines)) { 525 close(fd); 526 LOG(ERROR) << "Failed to block verify"; 527 return USCRIPT_ERROR_EXECUTE; 528 } 529 if (transferParams->storeCreated != -1) { 530 Store::DoFreeSpace(transferParams->storeBase); 531 } 532 close(fd); 533 return USCRIPT_SUCCESS; 534} 535 536bool UScriptInstructionShaCheck::IsTargetShaDiff(const std::string &devPath, const ShaInfo &shaInfo) 537{ 538 std::string tgtResultSha = CalculateBlockSha(devPath, shaInfo.targetPairs); 539 if (tgtResultSha.empty()) { 540 LOG(WARNING) << "target sha is empty"; 541 return true; 542 } 543 LOG(INFO) << "tgtResultSha: " << tgtResultSha << ", shaInfo.targetSha: " << shaInfo.targetSha; 544 return (tgtResultSha != shaInfo.targetSha); 545} 546 547int UScriptInstructionShaCheck::ExecReadShaInfo(Uscript::UScriptEnv &env, const std::string &devPath, 548 const ShaInfo &shaInfo, const std::string &partitionName) 549{ 550 UPDATER_INIT_RECORD; 551 std::string resultSha = CalculateBlockSha(devPath, shaInfo.blockPairs); 552 if (resultSha != shaInfo.contrastSha && IsTargetShaDiff(devPath, shaInfo)) { 553 if (DoBlocksVerify(env, partitionName, devPath) != USCRIPT_SUCCESS) { 554 LOG(ERROR) << "Different sha256, cannot continue"; 555 LOG(ERROR) << "blockPairs:" << shaInfo.blockPairs; 556 LOG(ERROR) << "resultSha: " << resultSha << ", shaInfo.contrastSha: " << shaInfo.contrastSha; 557 PrintAbnormalBlockHash(devPath, shaInfo.blockPairs); 558 UPDATER_LAST_WORD(devPath.substr(devPath.find_last_of("/") + 1), USCRIPT_ERROR_EXECUTE); 559 env.PostMessage(UPDATER_RETRY_TAG, VERIFY_FAILED_REBOOT); 560 return USCRIPT_ERROR_EXECUTE; 561 } 562 } 563 LOG(INFO) << "UScriptInstructionShaCheck::Execute Success"; 564 return USCRIPT_SUCCESS; 565} 566 567void UScriptInstructionShaCheck::PrintAbnormalBlockHash(const std::string &devPath, const std::string &blockPairs) 568{ 569 int fd = open(devPath.c_str(), O_RDWR | O_LARGEFILE); 570 if (fd == -1) { 571 LOG(ERROR) << "Failed to open file " << devPath; 572 return; 573 } 574 575 BlockSet blk; 576 blk.ParserAndInsert(blockPairs); 577 std::vector<uint8_t> block_buff(H_BLOCK_SIZE); 578 std::vector<BlockPair>::iterator it = blk.Begin(); 579 for (; it != blk.End(); ++it) { 580 if (lseek64(fd, static_cast<off64_t>(it->first * H_BLOCK_SIZE), SEEK_SET) == -1) { 581 LOG(ERROR) << "Failed to seek"; 582 close(fd); 583 return; 584 } 585 SHA256_CTX ctx; 586 SHA256_Init(&ctx); 587 for (size_t i = it->first; i < it->second; ++i) { 588 if (!Utils::ReadFully(fd, block_buff.data(), H_BLOCK_SIZE)) { 589 LOG(ERROR) << "Failed to read"; 590 close(fd); 591 return; 592 } 593 SHA256_Update(&ctx, block_buff.data(), H_BLOCK_SIZE); 594 } 595 uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; 596 SHA256_Final(digest, &ctx); 597 LOG(ERROR) << "block id:" << it->first << "-" << it->second << 598 " hex:" << Utils::ConvertSha256Hex(digest, SHA256_DIGEST_LENGTH); 599 } 600 close(fd); 601} 602 603std::string UScriptInstructionShaCheck::CalculateBlockSha(const std::string &devPath, const std::string &blockPairs) 604{ 605 if (blockPairs.empty()) { 606 LOG(ERROR) << "Failed to get blockPairs"; 607 return ""; 608 } 609 610 int fd = open(devPath.c_str(), O_RDWR | O_LARGEFILE); 611 if (fd == -1) { 612 LOG(ERROR) << "Failed to open file"; 613 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 614 return ""; 615 } 616 617 BlockSet blk; 618 blk.ParserAndInsert(blockPairs); 619 std::vector<uint8_t> block_buff(H_BLOCK_SIZE); 620 SHA256_CTX ctx; 621 SHA256_Init(&ctx); 622 std::vector<BlockPair>::iterator it = blk.Begin(); 623 for (; it != blk.End(); ++it) { 624 if (lseek64(fd, static_cast<off64_t>(it->first * H_BLOCK_SIZE), SEEK_SET) == -1) { 625 LOG(ERROR) << "Failed to seek"; 626 close(fd); 627 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 628 return ""; 629 } 630 for (size_t i = it->first; i < it->second; ++i) { 631 if (!Utils::ReadFully(fd, block_buff.data(), H_BLOCK_SIZE)) { 632 LOG(ERROR) << "Failed to read"; 633 close(fd); 634 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 635 return ""; 636 } 637 SHA256_Update(&ctx, block_buff.data(), H_BLOCK_SIZE); 638 } 639 } 640 close(fd); 641 642 uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; 643 SHA256_Final(digest, &ctx); 644 return Utils::ConvertSha256Hex(digest, SHA256_DIGEST_LENGTH); 645} 646 647int32_t UScriptInstructionShaCheck::SetShaInfo(Uscript::UScriptContext &context, ShaInfo &shaInfo) 648{ 649 int32_t ret = context.GetParam(1, shaInfo.blockPairs); 650 if (ret != USCRIPT_SUCCESS) { 651 LOG(ERROR) << "Failed to get param blockPairs"; 652 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 653 return USCRIPT_ERROR_EXECUTE; 654 } 655 656 ret = context.GetParam(SHA_CHECK_SECOND, shaInfo.contrastSha); 657 if (ret != USCRIPT_SUCCESS) { 658 LOG(ERROR) << "Failed to get param contrastSha"; 659 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 660 return USCRIPT_ERROR_EXECUTE; 661 } 662 663 // Only three parameters can be obtained for the upgrade package of an earlier version. 664 ret = context.GetParam(SHA_CHECK_TARGETPAIRS_INDEX, shaInfo.targetPairs); 665 if (ret != USCRIPT_SUCCESS) { 666 LOG(WARNING) << "Failed to get param targetPairs"; 667 } 668 669 ret = context.GetParam(SHA_CHECK_TARGETSHA_INDEX, shaInfo.targetSha); 670 if (ret != USCRIPT_SUCCESS) { 671 LOG(WARNING) << "Failed to get param targetSha"; 672 } 673 674 return USCRIPT_SUCCESS; 675} 676 677int32_t UScriptInstructionShaCheck::Execute(Uscript::UScriptEnv &env, Uscript::UScriptContext &context) 678{ 679 int32_t paramCount = context.GetParamCount(); 680 if (paramCount != SHA_CHECK_PARAMS && paramCount != SHA_CHECK_TARGET_PARAMS) { 681 LOG(ERROR) << "Invalid param"; 682 UPDATER_LAST_WORD(USCRIPT_INVALID_PARAM); 683 return ReturnAndPushParam(USCRIPT_INVALID_PARAM, context); 684 } 685 if (env.IsRetry() && !Utils::CheckFaultInfo(VERIFY_FAILED_REBOOT)) { 686 return ReturnAndPushParam(USCRIPT_SUCCESS, context); 687 } 688 689 std::string partitionName; 690 int32_t ret = context.GetParam(0, partitionName); 691 if (ret != USCRIPT_SUCCESS) { 692 LOG(ERROR) << "Failed to get param"; 693 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 694 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); 695 } 696 697 ShaInfo shaInfo {}; 698 ret = SetShaInfo(context, shaInfo); 699 if (ret != USCRIPT_SUCCESS) { 700 LOG(ERROR) << "Failed to set sha info"; 701 return ReturnAndPushParam(ret, context); 702 } 703 704 auto devPath = GetBlockDeviceByMountPoint(partitionName); 705 LOG(INFO) << "UScriptInstructionShaCheck::dev path : " << devPath; 706 if (devPath.empty()) { 707 LOG(ERROR) << "cannot get block device of partition"; 708 UPDATER_LAST_WORD(USCRIPT_ERROR_EXECUTE); 709 return ReturnAndPushParam(USCRIPT_ERROR_EXECUTE, context); 710 } 711 ret = ExecReadShaInfo(env, devPath, shaInfo, partitionName); 712 return ReturnAndPushParam(ret, context); 713} 714} 715