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
ProcessExtension(uintptr_t & extensionAddr,const uintptr_t blockAddrEnd,struct code_sign_enable_arg & arg)47 int32_t CodeSignBlock::ProcessExtension(uintptr_t &extensionAddr,
48 const uintptr_t blockAddrEnd, struct code_sign_enable_arg &arg)
49 {
50 if (extensionAddr >= blockAddrEnd) {
51 LOG_ERROR("Extension address is beyond the end of the block");
52 return CS_ERR_INVALID_EXTENSION_OFFSET;
53 }
54 auto extensionHeader = reinterpret_cast<const ExtensionHeader *>(extensionAddr);
55 extensionAddr = extensionAddr + sizeof(ExtensionHeader);
56 if (extensionAddr > blockAddrEnd) {
57 LOG_ERROR("Extension header size exceeds block boundary. ExtensionHeader size: %{public}zu bytes",
58 sizeof(ExtensionHeader));
59 return CS_ERR_INVALID_EXTENSION_OFFSET;
60 }
61 LOG_DEBUG("extensionHeader->type:%{public}d, extensionHeader->size:%{public}d", extensionHeader->type,
62 extensionHeader->size);
63 switch (extensionHeader->type) {
64 case CSB_EXTENSION_TYPE_MERKLE_TREE: {
65 auto merkleExtension = reinterpret_cast<const MerkleTreeExtension *>(extensionAddr);
66 arg.tree_offset = merkleExtension->treeOffset;
67 arg.root_hash_ptr = reinterpret_cast<uintptr_t>(merkleExtension->rootHash);
68 arg.flags |= CSB_SIGN_INFO_MERKLE_TREE;
69 break;
70 }
71 case CSB_EXTENSION_TYPE_PAGE_INFO: {
72 auto pageInfoExtension = reinterpret_cast<const PageInfoExtension *>(extensionAddr);
73 arg.sig_size = pageInfoExtension->sign_size;
74 if (arg.sig_size > extensionHeader->size - sizeof(PageInfoExtension)) {
75 return CS_ERR_EXTENSION_SIGN_SIZE;
76 }
77 if (pageInfoExtension->unitSize > CSB_SIGN_INFO_MAX_PAGEINFO_UNITSIZE) {
78 return CS_ERR_INVALID_PAGE_INFO_EXTENSION;
79 }
80 arg.sig_ptr = reinterpret_cast<uintptr_t>(pageInfoExtension->signature);
81 arg.pgtypeinfo_size = pageInfoExtension->mapSize;
82 arg.pgtypeinfo_off = pageInfoExtension->mapOffset;
83 arg.cs_version = CSB_EXTENSION_TYPE_PAGE_INFO_VERSION;
84 arg.flags |= pageInfoExtension->unitSize << 1;
85 LOG_DEBUG("arg.sig_size:%{public}u, arg.pgtypeinfo_size:%{public}u, "
86 "arg.pgtypeinfo_off:%{public}llu, unitSize:%{public}u,arg.flags:%{public}u", arg.sig_size,
87 arg.pgtypeinfo_size, arg.pgtypeinfo_off, pageInfoExtension->unitSize, arg.flags);
88 break;
89 }
90 default:
91 break;
92 }
93 extensionAddr += extensionHeader->size;
94 return CS_SUCCESS;
95 }
96
GetOneFileAndCodeSignInfo(std::string & targetFile,struct code_sign_enable_arg & arg,uint32_t flag)97 int32_t CodeSignBlock::GetOneFileAndCodeSignInfo(std::string &targetFile,
98 struct code_sign_enable_arg &arg, uint32_t flag)
99 {
100 int32_t ret;
101 uintptr_t signInfoAddr;
102 auto blockHeader = GetCodeSignBlockHeader();
103 auto blockAddrEnd = reinterpret_cast<uintptr_t>(blockHeader) + blockHeader->blockSize;
104
105 ret = GetOneMapNodeFromSignMap(targetFile, signInfoAddr);
106 if (ret == CS_SUCCESS_END) {
107 return ret;
108 }
109
110 auto signInfo = reinterpret_cast<const SignInfo *>(signInfoAddr);
111 auto verity = GetFsVerityInfo();
112 arg.version = 1;
113 arg.cs_version = verity->version;
114 arg.hash_algorithm = verity->hashAlgorithm;
115 arg.block_size = 1 << verity->logBlockSize;
116 arg.salt_ptr = reinterpret_cast<uintptr_t>(signInfo->salt);
117 arg.salt_size = signInfo->saltSize;
118 arg.sig_size = signInfo->signSize;
119 arg.sig_ptr = reinterpret_cast<uintptr_t>(signInfo->signature);
120 arg.data_size = signInfo->dataSize;
121 if (!signInfo->flags) {
122 return CS_SUCCESS;
123 }
124
125 uint32_t extensionCount = 0;
126 uint32_t extensionNum = signInfo->extensionNum;
127 if ((flag & IS_UNCOMPRESSED_NATIVE_LIBS) == 0) {
128 extensionNum = std::min(signInfo->extensionNum, 1u);
129 }
130 LOG_DEBUG("flag = %{public}u, extensionNum = %{public}u, signInfo->extensionNum = %{public}u",
131 flag, extensionNum, signInfo->extensionNum);
132 auto extensionAddr = reinterpret_cast<uintptr_t>(signInfo) + signInfo->extensionOffset;
133 while (extensionCount < extensionNum) {
134 ret = ProcessExtension(extensionAddr, blockAddrEnd, arg);
135 if (ret != CS_SUCCESS) {
136 return ret;
137 }
138 extensionCount++;
139 }
140 return CS_SUCCESS;
141 }
142
ParseNativeLibSignInfo(const EntryMap & entryMap)143 int32_t CodeSignBlock::ParseNativeLibSignInfo(const EntryMap &entryMap)
144 {
145 auto soInfo = GetNativeLibSignInfo();
146 LOG_DEBUG("So info sectionNum:%{public}d, entryMap size:%{public}u",
147 soInfo->sectionNum, static_cast<uint32_t>(entryMap.size()));
148 if ((soInfo->sectionNum == 0) && entryMap.empty()) {
149 return CS_SUCCESS;
150 } else if (!entryMap.empty() && (soInfo->sectionNum == 0)) {
151 return CS_ERR_NO_SIGNATURE;
152 }
153
154 std::lock_guard<std::mutex> guard(signMapMutex_);
155 size_t signMapPreSize = signMap_.size();
156 auto entryInfo = soInfo->info;
157 auto entryInfoEnd = soInfo->info + soInfo->sectionNum;
158 auto dataInfo = CONST_STATIC_CAST(char, soInfo);
159 do {
160 if (entryInfo->fileNameOffset >= soInfo->length) {
161 return CS_ERR_SO_FILE_OFFSET;
162 }
163 if (entryInfo->fileNameSize >= (soInfo->length - entryInfo->fileNameOffset)) {
164 return CS_ERR_SO_FILE_SIZE;
165 }
166 const std::string fileName(dataInfo + entryInfo->fileNameOffset, entryInfo->fileNameSize);
167 auto pathPair = entryMap.find(fileName);
168 if (pathPair == entryMap.end()) {
169 entryInfo++;
170 continue;
171 }
172
173 if (entryInfo->signOffset >= soInfo->length) {
174 return CS_ERR_SO_SIGN_OFFSET;
175 }
176 if (entryInfo->signSize >= soInfo->length) {
177 return CS_ERR_SO_SIGN_SIZE;
178 }
179 auto info = reinterpret_cast<uintptr_t>(dataInfo + entryInfo->signOffset);
180 const std::string &targetFile = pathPair->second;
181 signMap_.emplace(targetFile, info);
182 entryInfo++;
183 } while (entryInfo < entryInfoEnd);
184
185 if (entryMap.size() != signMap_.size() - signMapPreSize) {
186 LOG_ERROR("Libs signature not found: signMap_ size:%{public}u, signMapPreSize:%{public}u",
187 static_cast<uint32_t>(signMap_.size()), static_cast<uint32_t>(signMapPreSize));
188 return CS_ERR_NO_SIGNATURE;
189 }
190
191 return CS_SUCCESS;
192 }
193
ParseHapSignInfo(const std::string & path)194 int32_t CodeSignBlock::ParseHapSignInfo(const std::string &path)
195 {
196 auto hapInfo = GetHapSignInfo();
197 std::lock_guard<std::mutex> guard(signMapMutex_);
198 signMap_.emplace(path, reinterpret_cast<uintptr_t>(&hapInfo->signInfo));
199 return CS_SUCCESS;
200 }
201
ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock,uint32_t & blockSize)202 int32_t CodeSignBlock::ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock, uint32_t &blockSize)
203 {
204 int32_t ret = SetCodeSignBlockHeader(CONST_STATIC_CAST(CodeSignBlockHeader, codeSignBlock), blockSize);
205 if (ret != CS_SUCCESS) {
206 return ret;
207 }
208
209 auto segHeader = CONST_STATIC_CAST(SegmentHeader, codeSignBlock + sizeof(CodeSignBlockHeader));
210 if (segHeader->type != CSB_FSVERITY_INFO_SEG) {
211 return CS_ERR_SEGMENT_FSVERITY_TYPE;
212 }
213 if ((segHeader->offset >= blockSize) || (sizeof(FsVerityInfo) >= (blockSize - segHeader->offset))) {
214 return CS_ERR_SEGMENT_FSVERITY_OFFSET;
215 }
216 ret = SetFsVerityInfo(CONST_STATIC_CAST(FsVerityInfo, codeSignBlock + segHeader->offset));
217 if (ret != CS_SUCCESS) {
218 return ret;
219 }
220 segHeader++;
221
222 if (segHeader->type != CSB_HAP_META_SEG) {
223 return CS_ERR_SEGMENT_HAP_TYPE;
224 }
225 if ((segHeader->offset >= blockSize) || (sizeof(HapSignInfo) >= (blockSize - segHeader->offset))) {
226 return CS_ERR_SEGMENT_HAP_OFFSET;
227 }
228 ret = SetHapSignInfo(CONST_STATIC_CAST(HapSignInfo, codeSignBlock + segHeader->offset));
229 if (ret != CS_SUCCESS) {
230 return ret;
231 }
232 segHeader++;
233
234 if (segHeader->type != CSB_NATIVE_LIB_INFO_SEG) {
235 return CS_ERR_SEGMENT_SO_TYPE;
236 }
237 if ((segHeader->offset >= blockSize) || (sizeof(NativeLibSignInfo) > (blockSize - segHeader->offset))) {
238 return CS_ERR_SEGMENT_SO_OFFSET;
239 }
240 return SetNativeLibSignInfo(CONST_STATIC_CAST(NativeLibSignInfo, codeSignBlock + segHeader->offset));
241 }
242
GetCodeSignBlockBuffer(const std::string & path,ReadBuffer & signBuffer,uint32_t & size)243 int32_t CodeSignBlock::GetCodeSignBlockBuffer(const std::string &path, ReadBuffer &signBuffer, uint32_t &size)
244 {
245 ReadBuffer blobBuffer = nullptr;
246 uint32_t blobSize = 0;
247 ReadBuffer signBlockBuffer = nullptr;
248 uint32_t signBlockSize = 0;
249
250 int32_t ret = Verify::ParseHapSignatureInfo(path, signatureInfo_);
251 if (ret != Verify::VERIFY_SUCCESS) {
252 LOG_ERROR("find code sign block buffer failed. errno = %{public}d ", ret);
253 return CS_ERR_FILE_INVALID;
254 }
255
256 for (const auto &value : signatureInfo_.optionBlocks) {
257 if (value.optionalType != CSB_PROPERTY_BLOB) {
258 continue;
259 }
260
261 blobBuffer = value.optionalBlockValue.GetBufferPtr();
262 blobSize = static_cast<uint32_t>(value.optionalBlockValue.GetCapacity());
263 break;
264 }
265
266 if ((blobBuffer == nullptr) || (blobSize <= sizeof(PropertyBlobHeader))) {
267 return CS_CODE_SIGN_NOT_EXISTS;
268 }
269
270 size_t length = 0;
271 do {
272 auto blobHeader = CONST_STATIC_CAST(PropertyBlobHeader, blobBuffer + length);
273 if (blobHeader->type == HAP_CODE_SIGN_BLOCK_ID) {
274 signBlockBuffer = CONST_STATIC_CAST(char, blobHeader) + sizeof(PropertyBlobHeader);
275 signBlockSize = blobHeader->size;
276 if ((signBlockSize > blobSize) || ((signBlockBuffer - blobBuffer) > (blobSize - signBlockSize))) {
277 return CS_ERR_BLOCK_SIZE;
278 }
279 break;
280 }
281 length += blobHeader->size + sizeof(PropertyBlobHeader);
282 } while (length < blobSize);
283
284 if ((signBlockBuffer == nullptr) || !signBlockSize) {
285 return CS_CODE_SIGN_NOT_EXISTS;
286 }
287
288 signBuffer = signBlockBuffer;
289 size = signBlockSize;
290 return CS_SUCCESS;
291 }
292
ParseCodeSignBlock(const std::string & realPath,const EntryMap & entryMap,FileType fileType)293 int32_t CodeSignBlock::ParseCodeSignBlock(const std::string &realPath,
294 const EntryMap &entryMap, FileType fileType)
295 {
296 int32_t ret;
297 ReadBuffer codeSignBlock = nullptr;
298 uint32_t codeSignSize;
299
300 ret = GetCodeSignBlockBuffer(realPath, codeSignBlock, codeSignSize);
301 if (ret != CS_SUCCESS) {
302 LOG_ERROR("Get code sign block buffer failed. errno = %{public}d ", ret);
303 return ret;
304 }
305
306 ret = ParseCodeSignBlockBaseInfo(codeSignBlock, codeSignSize);
307 if (ret != CS_SUCCESS) {
308 return ret;
309 }
310 if ((fileType == FILE_SELF) || (fileType == FILE_ALL)) {
311 ret = ParseHapSignInfo(realPath);
312 if (ret != CS_SUCCESS) {
313 return ret;
314 }
315 }
316 if ((fileType == FILE_ENTRY_ONLY) || (fileType == FILE_ALL)) {
317 ret = ParseNativeLibSignInfo(entryMap);
318 if (ret != CS_SUCCESS) {
319 return ret;
320 }
321 }
322 return CS_SUCCESS;
323 }
324 } // CodeSign namespace
325 } // Security namespace
326 } // OHOS namespace
327