1 /*
2 * Copyright (c) 2023-2024 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 "code_sign_block.h"
16 #include <sys/types.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <linux/types.h>
20 #include <linux/fs.h>
21 #include <linux/stat.h>
22 #include "cs_hisysevent.h"
23 #include "cs_hitrace.h"
24 #include "extractor.h"
25 #include "directory_ex.h"
26 #include "constants.h"
27 #include "file_helper.h"
28 #include "log.h"
29 #include "stat_utils.h"
30
31 namespace OHOS {
32 namespace Security {
33 namespace CodeSign {
34 constexpr uint32_t HAP_CODE_SIGN_BLOCK_ID = 0x30000001;
35 constexpr uint32_t CSB_PROPERTY_BLOB = 0x20000003;
36
CodeSignBlock()37 CodeSignBlock::CodeSignBlock()
38 {
39 signatureInfo_.hapSigningBlockOffset = 0;
40 signatureInfo_.hapCentralDirOffset = 0;
41 signatureInfo_.hapEocdOffset = 0;
42 signatureInfo_.version = 0;
43 }
44
~CodeSignBlock()45 CodeSignBlock::~CodeSignBlock() { }
46
GetOneFileAndCodeSignInfo(std::string & targetFile,struct code_sign_enable_arg & arg)47 int32_t CodeSignBlock::GetOneFileAndCodeSignInfo(std::string &targetFile, struct code_sign_enable_arg &arg)
48 {
49 int32_t ret;
50 uintptr_t signInfoAddr;
51 auto blockHeader = GetCodeSignBlockHeader();
52 auto blockAddrEnd = reinterpret_cast<uintptr_t>(blockHeader) + blockHeader->blockSize;
53
54 ret = GetOneMapNodeFromSignMap(targetFile, signInfoAddr);
55 if (ret == CS_SUCCESS_END) {
56 return ret;
57 }
58
59 auto signInfo = reinterpret_cast<const SignInfo *>(signInfoAddr);
60 auto verity = GetFsVerityInfo();
61 arg.version = 1;
62 arg.cs_version = verity->version;
63 arg.hash_algorithm = verity->hashAlgorithm;
64 arg.block_size = 1 << verity->logBlockSize;
65 arg.salt_ptr = reinterpret_cast<uintptr_t>(signInfo->salt);
66 arg.salt_size = signInfo->saltSize;
67 arg.sig_size = signInfo->signSize;
68 arg.sig_ptr = reinterpret_cast<uintptr_t>(signInfo->signature);
69 arg.data_size = signInfo->dataSize;
70 arg.flags = signInfo->flags;
71 if (!(signInfo->flags & CSB_SIGN_INFO_MERKLE_TREE)) {
72 return CS_SUCCESS;
73 }
74
75 uint32_t extensionCount = 0;
76 auto extensionAddr = reinterpret_cast<uintptr_t>(signInfo) + signInfo->extensionOffset;
77 do {
78 if (extensionAddr >= blockAddrEnd) {
79 return CS_ERR_SIGN_EXTENSION_OFFSET_ALIGN;
80 }
81 auto extension = reinterpret_cast<const MerkleTreeExtension *>(extensionAddr);
82 if (extension->type == CSB_EXTENSION_TYPE_MERKLE_TREE) {
83 arg.tree_offset = extension->treeOffset;
84 arg.root_hash_ptr = reinterpret_cast<uintptr_t>(extension->rootHash);
85 break;
86 }
87 extensionAddr += extension->size;
88 extensionCount++;
89 } while (extensionCount < signInfo->extensionNum);
90 return CS_SUCCESS;
91 }
92
ParseNativeLibSignInfo(const EntryMap & entryMap)93 int32_t CodeSignBlock::ParseNativeLibSignInfo(const EntryMap &entryMap)
94 {
95 auto soInfo = GetNativeLibSignInfo();
96 LOG_DEBUG("So info sectionNum:%{public}d, entryMap size:%{public}u",
97 soInfo->sectionNum, static_cast<uint32_t>(entryMap.size()));
98 if ((soInfo->sectionNum == 0) && entryMap.empty()) {
99 return CS_SUCCESS;
100 } else if (!entryMap.empty() && (soInfo->sectionNum == 0)) {
101 return CS_ERR_NO_SIGNATURE;
102 }
103
104 std::lock_guard<std::mutex> guard(signMapMutex_);
105 size_t signMapPreSize = signMap_.size();
106 auto entryInfo = soInfo->info;
107 auto entryInfoEnd = soInfo->info + soInfo->sectionNum;
108 auto dataInfo = CONST_STATIC_CAST(char, soInfo);
109 do {
110 if (entryInfo->fileNameOffset >= soInfo->length) {
111 return CS_ERR_SO_FILE_OFFSET;
112 }
113 if (entryInfo->fileNameSize >= (soInfo->length - entryInfo->fileNameOffset)) {
114 return CS_ERR_SO_FILE_SIZE;
115 }
116 const std::string fileName(dataInfo + entryInfo->fileNameOffset, entryInfo->fileNameSize);
117 auto pathPair = entryMap.find(fileName);
118 if (pathPair == entryMap.end()) {
119 entryInfo++;
120 continue;
121 }
122
123 if (entryInfo->signOffset >= soInfo->length) {
124 return CS_ERR_SO_SIGN_OFFSET;
125 }
126 if (entryInfo->signSize >= soInfo->length) {
127 return CS_ERR_SO_SIGN_SIZE;
128 }
129 auto info = reinterpret_cast<uintptr_t>(dataInfo + entryInfo->signOffset);
130 const std::string &targetFile = pathPair->second;
131 signMap_.emplace(targetFile, info);
132 entryInfo++;
133 } while (entryInfo < entryInfoEnd);
134
135 if (entryMap.size() != signMap_.size() - signMapPreSize) {
136 LOG_DEBUG("signMap_ size:%{public}u, signMapPreSize:%{public}u",
137 static_cast<uint32_t>(signMap_.size()), static_cast<uint32_t>(signMapPreSize));
138 return CS_ERR_NO_SIGNATURE;
139 }
140
141 return CS_SUCCESS;
142 }
143
ParseHapSignInfo(const std::string & path)144 int32_t CodeSignBlock::ParseHapSignInfo(const std::string &path)
145 {
146 auto hapInfo = GetHapSignInfo();
147 std::lock_guard<std::mutex> guard(signMapMutex_);
148 signMap_.emplace(path, reinterpret_cast<uintptr_t>(&hapInfo->signInfo));
149 return CS_SUCCESS;
150 }
151
ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock,uint32_t & blockSize)152 int32_t CodeSignBlock::ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock, uint32_t &blockSize)
153 {
154 int32_t ret = SetCodeSignBlockHeader(CONST_STATIC_CAST(CodeSignBlockHeader, codeSignBlock), blockSize);
155 if (ret != CS_SUCCESS) {
156 return ret;
157 }
158
159 auto segHeader = CONST_STATIC_CAST(SegmentHeader, codeSignBlock + sizeof(CodeSignBlockHeader));
160 if (segHeader->type != CSB_FSVERITY_INFO_SEG) {
161 return CS_ERR_SEGMENT_FSVERITY_TYPE;
162 }
163 if (segHeader->offset >= blockSize) {
164 return CS_ERR_SEGMENT_FSVERITY_OFFSET;
165 }
166 ret = SetFsVerityInfo(CONST_STATIC_CAST(FsVerityInfo, codeSignBlock + segHeader->offset));
167 if (ret != CS_SUCCESS) {
168 return ret;
169 }
170 segHeader++;
171
172 if (segHeader->type != CSB_HAP_META_SEG) {
173 return CS_ERR_SEGMENT_HAP_TYPE;
174 }
175 if (segHeader->offset >= blockSize) {
176 return CS_ERR_SEGMENT_HAP_OFFSET;
177 }
178 ret = SetHapSignInfo(CONST_STATIC_CAST(HapSignInfo, codeSignBlock + segHeader->offset));
179 if (ret != CS_SUCCESS) {
180 return ret;
181 }
182 segHeader++;
183
184 if (segHeader->type != CSB_NATIVE_LIB_INFO_SEG) {
185 return CS_ERR_SEGMENT_SO_TYPE;
186 }
187 if (segHeader->offset >= blockSize) {
188 return CS_ERR_SEGMENT_SO_OFFSET;
189 }
190 return SetNativeLibSignInfo(CONST_STATIC_CAST(NativeLibSignInfo, codeSignBlock + segHeader->offset));
191 }
192
GetCodeSignBlockBuffer(const std::string & path,ReadBuffer & signBuffer,uint32_t & size)193 int32_t CodeSignBlock::GetCodeSignBlockBuffer(const std::string &path, ReadBuffer &signBuffer, uint32_t &size)
194 {
195 ReadBuffer blobBuffer = nullptr;
196 uint32_t blobSize = 0;
197 ReadBuffer signBlockBuffer = nullptr;
198 uint32_t signBlockSize = 0;
199
200 int32_t ret = Verify::ParseHapSignatureInfo(path, signatureInfo_);
201 if (ret != Verify::VERIFY_SUCCESS) {
202 LOG_ERROR("find code sign block buffer failed. errno = %{public}d ", ret);
203 return CS_ERR_FILE_INVALID;
204 }
205
206 for (const auto &value : signatureInfo_.optionBlocks) {
207 if (value.optionalType != CSB_PROPERTY_BLOB) {
208 continue;
209 }
210
211 blobBuffer = value.optionalBlockValue.GetBufferPtr();
212 blobSize = static_cast<uint32_t>(value.optionalBlockValue.GetCapacity());
213 break;
214 }
215
216 if ((blobBuffer == nullptr) || (blobSize <= sizeof(PropertyBlobHeader))) {
217 return CS_CODE_SIGN_NOT_EXISTS;
218 }
219
220 size_t length = 0;
221 do {
222 auto blobHeader = CONST_STATIC_CAST(PropertyBlobHeader, blobBuffer + length);
223 if (blobHeader->type == HAP_CODE_SIGN_BLOCK_ID) {
224 signBlockBuffer = CONST_STATIC_CAST(char, blobHeader) + sizeof(PropertyBlobHeader);
225 signBlockSize = blobHeader->size;
226 break;
227 }
228 length += blobHeader->size + sizeof(PropertyBlobHeader);
229 } while (length < blobSize);
230
231 if ((signBlockBuffer == nullptr) || !signBlockSize) {
232 return CS_CODE_SIGN_NOT_EXISTS;
233 }
234
235 signBuffer = signBlockBuffer;
236 size = signBlockSize;
237 return CS_SUCCESS;
238 }
239
ParseCodeSignBlock(const std::string & realPath,const EntryMap & entryMap,FileType fileType)240 int32_t CodeSignBlock::ParseCodeSignBlock(const std::string &realPath,
241 const EntryMap &entryMap, FileType fileType)
242 {
243 int32_t ret;
244 ReadBuffer codeSignBlock = nullptr;
245 uint32_t codeSignSize;
246
247 ret = GetCodeSignBlockBuffer(realPath, codeSignBlock, codeSignSize);
248 if (ret != CS_SUCCESS) {
249 LOG_ERROR("Get code sign block buffer failed. errno = %{public}d ", ret);
250 return ret;
251 }
252
253 ret = ParseCodeSignBlockBaseInfo(codeSignBlock, codeSignSize);
254 if (ret != CS_SUCCESS) {
255 return ret;
256 }
257 if ((fileType == FILE_SELF) || (fileType == FILE_ALL)) {
258 ret = ParseHapSignInfo(realPath);
259 if (ret != CS_SUCCESS) {
260 return ret;
261 }
262 }
263 if ((fileType == FILE_ENTRY_ONLY) || (fileType == FILE_ALL)) {
264 ret = ParseNativeLibSignInfo(entryMap);
265 if (ret != CS_SUCCESS) {
266 return ret;
267 }
268 }
269 return CS_SUCCESS;
270 }
271 } // CodeSign namespace
272 } // Security namespace
273 } // OHOS namespace
274