/* * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "code_sign_block.h" #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/stat.h> #include "cs_hisysevent.h" #include "cs_hitrace.h" #include "extractor.h" #include "directory_ex.h" #include "constants.h" #include "file_helper.h" #include "log.h" #include "stat_utils.h" namespace OHOS { namespace Security { namespace CodeSign { constexpr uint32_t HAP_CODE_SIGN_BLOCK_ID = 0x30000001; constexpr uint32_t CSB_PROPERTY_BLOB = 0x20000003; CodeSignBlock::CodeSignBlock() { signatureInfo_.hapSigningBlockOffset = 0; signatureInfo_.hapCentralDirOffset = 0; signatureInfo_.hapEocdOffset = 0; signatureInfo_.version = 0; } CodeSignBlock::~CodeSignBlock() { } int32_t CodeSignBlock::GetOneFileAndCodeSignInfo(std::string &targetFile, struct code_sign_enable_arg &arg) { int32_t ret; uintptr_t signInfoAddr; auto blockHeader = GetCodeSignBlockHeader(); auto blockAddrEnd = reinterpret_cast<uintptr_t>(blockHeader) + blockHeader->blockSize; ret = GetOneMapNodeFromSignMap(targetFile, signInfoAddr); if (ret == CS_SUCCESS_END) { return ret; } auto signInfo = reinterpret_cast<const SignInfo *>(signInfoAddr); auto verity = GetFsVerityInfo(); arg.version = 1; arg.cs_version = verity->version; arg.hash_algorithm = verity->hashAlgorithm; arg.block_size = 1 << verity->logBlockSize; arg.salt_ptr = reinterpret_cast<uintptr_t>(signInfo->salt); arg.salt_size = signInfo->saltSize; arg.sig_size = signInfo->signSize; arg.sig_ptr = reinterpret_cast<uintptr_t>(signInfo->signature); arg.data_size = signInfo->dataSize; arg.flags = signInfo->flags; if (!(signInfo->flags & CSB_SIGN_INFO_MERKLE_TREE)) { return CS_SUCCESS; } uint32_t extensionCount = 0; auto extensionAddr = reinterpret_cast<uintptr_t>(signInfo) + signInfo->extensionOffset; do { if (extensionAddr >= blockAddrEnd) { return CS_ERR_SIGN_EXTENSION_OFFSET_ALIGN; } auto extension = reinterpret_cast<const MerkleTreeExtension *>(extensionAddr); if (extension->type == CSB_EXTENSION_TYPE_MERKLE_TREE) { arg.tree_offset = extension->treeOffset; arg.root_hash_ptr = reinterpret_cast<uintptr_t>(extension->rootHash); break; } extensionAddr += extension->size; extensionCount++; } while (extensionCount < signInfo->extensionNum); return CS_SUCCESS; } int32_t CodeSignBlock::ParseNativeLibSignInfo(const EntryMap &entryMap) { auto soInfo = GetNativeLibSignInfo(); LOG_DEBUG("So info sectionNum:%{public}d, entryMap size:%{public}u", soInfo->sectionNum, static_cast<uint32_t>(entryMap.size())); if ((soInfo->sectionNum == 0) && entryMap.empty()) { return CS_SUCCESS; } else if (!entryMap.empty() && (soInfo->sectionNum == 0)) { return CS_ERR_NO_SIGNATURE; } std::lock_guard<std::mutex> guard(signMapMutex_); size_t signMapPreSize = signMap_.size(); auto entryInfo = soInfo->info; auto entryInfoEnd = soInfo->info + soInfo->sectionNum; auto dataInfo = CONST_STATIC_CAST(char, soInfo); do { if (entryInfo->fileNameOffset >= soInfo->length) { return CS_ERR_SO_FILE_OFFSET; } if (entryInfo->fileNameSize >= (soInfo->length - entryInfo->fileNameOffset)) { return CS_ERR_SO_FILE_SIZE; } const std::string fileName(dataInfo + entryInfo->fileNameOffset, entryInfo->fileNameSize); auto pathPair = entryMap.find(fileName); if (pathPair == entryMap.end()) { entryInfo++; continue; } if (entryInfo->signOffset >= soInfo->length) { return CS_ERR_SO_SIGN_OFFSET; } if (entryInfo->signSize >= soInfo->length) { return CS_ERR_SO_SIGN_SIZE; } auto info = reinterpret_cast<uintptr_t>(dataInfo + entryInfo->signOffset); const std::string &targetFile = pathPair->second; signMap_.emplace(targetFile, info); entryInfo++; } while (entryInfo < entryInfoEnd); if (entryMap.size() != signMap_.size() - signMapPreSize) { LOG_DEBUG("signMap_ size:%{public}u, signMapPreSize:%{public}u", static_cast<uint32_t>(signMap_.size()), static_cast<uint32_t>(signMapPreSize)); return CS_ERR_NO_SIGNATURE; } return CS_SUCCESS; } int32_t CodeSignBlock::ParseHapSignInfo(const std::string &path) { auto hapInfo = GetHapSignInfo(); std::lock_guard<std::mutex> guard(signMapMutex_); signMap_.emplace(path, reinterpret_cast<uintptr_t>(&hapInfo->signInfo)); return CS_SUCCESS; } int32_t CodeSignBlock::ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock, uint32_t &blockSize) { int32_t ret = SetCodeSignBlockHeader(CONST_STATIC_CAST(CodeSignBlockHeader, codeSignBlock), blockSize); if (ret != CS_SUCCESS) { return ret; } auto segHeader = CONST_STATIC_CAST(SegmentHeader, codeSignBlock + sizeof(CodeSignBlockHeader)); if (segHeader->type != CSB_FSVERITY_INFO_SEG) { return CS_ERR_SEGMENT_FSVERITY_TYPE; } if (segHeader->offset >= blockSize) { return CS_ERR_SEGMENT_FSVERITY_OFFSET; } ret = SetFsVerityInfo(CONST_STATIC_CAST(FsVerityInfo, codeSignBlock + segHeader->offset)); if (ret != CS_SUCCESS) { return ret; } segHeader++; if (segHeader->type != CSB_HAP_META_SEG) { return CS_ERR_SEGMENT_HAP_TYPE; } if (segHeader->offset >= blockSize) { return CS_ERR_SEGMENT_HAP_OFFSET; } ret = SetHapSignInfo(CONST_STATIC_CAST(HapSignInfo, codeSignBlock + segHeader->offset)); if (ret != CS_SUCCESS) { return ret; } segHeader++; if (segHeader->type != CSB_NATIVE_LIB_INFO_SEG) { return CS_ERR_SEGMENT_SO_TYPE; } if (segHeader->offset >= blockSize) { return CS_ERR_SEGMENT_SO_OFFSET; } return SetNativeLibSignInfo(CONST_STATIC_CAST(NativeLibSignInfo, codeSignBlock + segHeader->offset)); } int32_t CodeSignBlock::GetCodeSignBlockBuffer(const std::string &path, ReadBuffer &signBuffer, uint32_t &size) { ReadBuffer blobBuffer = nullptr; uint32_t blobSize = 0; ReadBuffer signBlockBuffer = nullptr; uint32_t signBlockSize = 0; int32_t ret = Verify::ParseHapSignatureInfo(path, signatureInfo_); if (ret != Verify::VERIFY_SUCCESS) { LOG_ERROR("find code sign block buffer failed. errno = %{public}d ", ret); return CS_ERR_FILE_INVALID; } for (const auto &value : signatureInfo_.optionBlocks) { if (value.optionalType != CSB_PROPERTY_BLOB) { continue; } blobBuffer = value.optionalBlockValue.GetBufferPtr(); blobSize = static_cast<uint32_t>(value.optionalBlockValue.GetCapacity()); break; } if ((blobBuffer == nullptr) || (blobSize <= sizeof(PropertyBlobHeader))) { return CS_CODE_SIGN_NOT_EXISTS; } size_t length = 0; do { auto blobHeader = CONST_STATIC_CAST(PropertyBlobHeader, blobBuffer + length); if (blobHeader->type == HAP_CODE_SIGN_BLOCK_ID) { signBlockBuffer = CONST_STATIC_CAST(char, blobHeader) + sizeof(PropertyBlobHeader); signBlockSize = blobHeader->size; break; } length += blobHeader->size + sizeof(PropertyBlobHeader); } while (length < blobSize); if ((signBlockBuffer == nullptr) || !signBlockSize) { return CS_CODE_SIGN_NOT_EXISTS; } signBuffer = signBlockBuffer; size = signBlockSize; return CS_SUCCESS; } int32_t CodeSignBlock::ParseCodeSignBlock(const std::string &realPath, const EntryMap &entryMap, FileType fileType) { int32_t ret; ReadBuffer codeSignBlock = nullptr; uint32_t codeSignSize; ret = GetCodeSignBlockBuffer(realPath, codeSignBlock, codeSignSize); if (ret != CS_SUCCESS) { LOG_ERROR("Get code sign block buffer failed. errno = %{public}d ", ret); return ret; } ret = ParseCodeSignBlockBaseInfo(codeSignBlock, codeSignSize); if (ret != CS_SUCCESS) { return ret; } if ((fileType == FILE_SELF) || (fileType == FILE_ALL)) { ret = ParseHapSignInfo(realPath); if (ret != CS_SUCCESS) { return ret; } } if ((fileType == FILE_ENTRY_ONLY) || (fileType == FILE_ALL)) { ret = ParseNativeLibSignInfo(entryMap); if (ret != CS_SUCCESS) { return ret; } } return CS_SUCCESS; } } // CodeSign namespace } // Security namespace } // OHOS namespace