• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "elf_code_sign_block.h"
17 #include <filesystem>
18 #include <fstream>
19 #include <securec.h>
20 
21 #include "constants.h"
22 #include "directory_ex.h"
23 #include "log.h"
24 
25 namespace OHOS {
26 namespace Security {
27 namespace CodeSign {
28 
29 constexpr uint32_t PAGE_SIZE = 4096;
30 const std::string ElfCodeSignBlock::CODE_SIGN_SECTION = ".codesign";
31 
ElfCodeSignBlock()32 ElfCodeSignBlock::ElfCodeSignBlock()
33 {
34 }
35 
~ElfCodeSignBlock()36 ElfCodeSignBlock::~ElfCodeSignBlock()
37 {
38 }
39 
EnforceCodeSign(const std::string & realPath,CallbackFunc & func)40 int32_t ElfCodeSignBlock::EnforceCodeSign(const std::string &realPath, CallbackFunc &func)
41 {
42     int32_t ret = ParseSignBlock(realPath);
43     if (ret != CS_SUCCESS) {
44         return ret;
45     }
46     auto signInfo = signInfo_;
47     struct code_sign_enable_arg arg = {0};
48     arg.version = signInfo->version;
49     arg.cs_version = signInfo->csVersion;
50     arg.hash_algorithm = signInfo->hashAlgorithm;
51     arg.block_size = 1 << signInfo->logBlockSize;
52     arg.salt_ptr = reinterpret_cast<uintptr_t>(signInfo->salt);
53     arg.salt_size = signInfo->saltSize;
54     arg.sig_size = signInfo->signSize;
55     arg.sig_ptr = reinterpret_cast<uintptr_t>(signInfo->signature);
56     arg.data_size = signInfo->dataSize;
57     arg.root_hash_ptr = reinterpret_cast<uintptr_t>(signInfo->rootHash);
58     arg.flags |= signInfo->flags;
59     return func(realPath, arg);
60 }
61 
ParseSignBlock(const std::string & realPath)62 int32_t ElfCodeSignBlock::ParseSignBlock(const std::string &realPath)
63 {
64     LOG_INFO("Start to parse sign block v3");
65     auto fileSize = std::filesystem::file_size(realPath);
66     if (fileSize < PAGE_SIZE) {
67         LOG_ERROR("file size is too small");
68         return CS_CODE_SIGN_NOT_EXISTS;
69     }
70     ELFIO::elfio elfReader;
71     if (!elfReader.load(realPath)) {
72         LOG_ERROR("failed to load input ELF file");
73         return CS_ERR_FILE_INVALID;
74     }
75     ELFIO::section *sec = elfReader.sections[CODE_SIGN_SECTION];
76     if (!sec) {
77         LOG_ERROR("codesign section is not found");
78         return CS_CODE_SIGN_NOT_EXISTS;
79     }
80     ELFIO::Elf64_Off secOffElf64 = sec->get_offset();
81     uint64_t secOff = static_cast<uint64_t>(secOffElf64);
82     if (secOff % PAGE_SIZE != 0) {
83         LOG_ERROR("codesign section offset is not aligned");
84         return CS_ERR_SECTION_OFFSET;
85     }
86     const char *data = sec->get_data();
87     uint64_t csBlockSize = sec->get_size();
88     if (csBlockSize == 0 || csBlockSize % PAGE_SIZE != 0) {
89         return CS_ERR_SECTION_SIZE;
90     }
91     signBlockBuffer_ = std::make_unique<uint8_t[]>(csBlockSize);
92     if (memcpy_s(signBlockBuffer_.get(), csBlockSize, data, csBlockSize) != EOK) {
93         return CS_ERR_MEMORY;
94     }
95     signInfo_ = reinterpret_cast<const ElfSignInfo *>(signBlockBuffer_.get());
96     return CheckElfSignInfo(csBlockSize);
97 }
98 
CheckElfSignInfo(const uint64_t csBlockSize)99 int32_t ElfCodeSignBlock::CheckElfSignInfo(const uint64_t csBlockSize)
100 {
101     if (signInfo_->type != CSB_FS_VERITY_DESCRIPTOR_TYPE) {
102         return CS_ERR_SEGMENT_FSVERITY_TYPE;
103     }
104     if (signInfo_->length > csBlockSize) {
105         LOG_ERROR("signInfo length is larger than cs block size");
106         return CS_ERR_BLOCK_SIZE;
107     }
108     if (signInfo_->version != 1) {
109         return CS_ERR_FSVERITY_VERSION;
110     }
111     if (signInfo_->logBlockSize != CSB_FSVERITY_BLOCK_SIZE) {
112         return CS_ERR_FSVERITY_BLOCK_SIZE;
113     }
114     if (signInfo_->csVersion != ELF_CS_VERSION) {
115         LOG_ERROR("csVersion is not equal to ELF_CS_VERSION");
116         return CS_ERR_BLOCK_VERSION;
117     }
118     if (signInfo_->signSize >= signInfo_->length || signInfo_->signSize == 0) {
119         return CS_ERR_SO_SIGN_SIZE;
120     }
121     return CS_SUCCESS;
122 }
123 } // CodeSign namespace
124 } // Security namespace
125 } // OHOS namespace
126