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 size_t signMapPreSize = signMap_.size();
105 auto entryInfo = soInfo->info;
106 auto entryInfoEnd = soInfo->info + soInfo->sectionNum;
107 auto dataInfo = CONST_STATIC_CAST(char, soInfo);
108 do {
109 if (entryInfo->fileNameOffset >= soInfo->length) {
110 return CS_ERR_SO_FILE_OFFSET;
111 }
112 if (entryInfo->fileNameSize >= (soInfo->length - entryInfo->fileNameOffset)) {
113 return CS_ERR_SO_FILE_SIZE;
114 }
115 const std::string fileName(dataInfo + entryInfo->fileNameOffset, entryInfo->fileNameSize);
116 auto pathPair = entryMap.find(fileName);
117 if (pathPair == entryMap.end()) {
118 entryInfo++;
119 continue;
120 }
121
122 if (entryInfo->signOffset >= soInfo->length) {
123 return CS_ERR_SO_SIGN_OFFSET;
124 }
125 if (entryInfo->signSize >= soInfo->length) {
126 return CS_ERR_SO_SIGN_SIZE;
127 }
128 auto info = reinterpret_cast<uintptr_t>(dataInfo + entryInfo->signOffset);
129 const std::string &targetFile = pathPair->second;
130 signMap_.emplace(targetFile, info);
131 entryInfo++;
132 } while (entryInfo < entryInfoEnd);
133
134 if (entryMap.size() != signMap_.size() - signMapPreSize) {
135 LOG_DEBUG("signMap_ size:%{public}u, signMapPreSize:%{public}u",
136 static_cast<uint32_t>(signMap_.size()), static_cast<uint32_t>(signMapPreSize));
137 return CS_ERR_NO_SIGNATURE;
138 }
139
140 return CS_SUCCESS;
141 }
142
ParseHapSignInfo(const std::string & path)143 int32_t CodeSignBlock::ParseHapSignInfo(const std::string &path)
144 {
145 auto hapInfo = GetHapSignInfo();
146 signMap_.emplace(path, reinterpret_cast<uintptr_t>(&hapInfo->signInfo));
147 return CS_SUCCESS;
148 }
149
ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock,uint32_t & blockSize)150 int32_t CodeSignBlock::ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock, uint32_t &blockSize)
151 {
152 int32_t ret = SetCodeSignBlockHeader(CONST_STATIC_CAST(CodeSignBlockHeader, codeSignBlock), blockSize);
153 if (ret != CS_SUCCESS) {
154 return ret;
155 }
156
157 auto segHeader = CONST_STATIC_CAST(SegmentHeader, codeSignBlock + sizeof(CodeSignBlockHeader));
158 if (segHeader->type != CSB_FSVERITY_INFO_SEG) {
159 return CS_ERR_SEGMENT_FSVERITY_TYPE;
160 }
161 if (segHeader->offset >= blockSize) {
162 return CS_ERR_SEGMENT_FSVERITY_OFFSET;
163 }
164 ret = SetFsVerityInfo(CONST_STATIC_CAST(FsVerityInfo, codeSignBlock + segHeader->offset));
165 if (ret != CS_SUCCESS) {
166 return ret;
167 }
168 segHeader++;
169
170 if (segHeader->type != CSB_HAP_META_SEG) {
171 return CS_ERR_SEGMENT_HAP_TYPE;
172 }
173 if (segHeader->offset >= blockSize) {
174 return CS_ERR_SEGMENT_HAP_OFFSET;
175 }
176 ret = SetHapSignInfo(CONST_STATIC_CAST(HapSignInfo, codeSignBlock + segHeader->offset));
177 if (ret != CS_SUCCESS) {
178 return ret;
179 }
180 segHeader++;
181
182 if (segHeader->type != CSB_NATIVE_LIB_INFO_SEG) {
183 return CS_ERR_SEGMENT_SO_TYPE;
184 }
185 if (segHeader->offset >= blockSize) {
186 return CS_ERR_SEGMENT_SO_OFFSET;
187 }
188 return SetNativeLibSignInfo(CONST_STATIC_CAST(NativeLibSignInfo, codeSignBlock + segHeader->offset));
189 }
190
GetCodeSignBlockBuffer(const std::string & path,ReadBuffer & signBuffer,uint32_t & size)191 int32_t CodeSignBlock::GetCodeSignBlockBuffer(const std::string &path, ReadBuffer &signBuffer, uint32_t &size)
192 {
193 ReadBuffer blobBuffer = nullptr;
194 uint32_t blobSize = 0;
195 ReadBuffer signBlockBuffer = nullptr;
196 uint32_t signBlockSize = 0;
197
198 int32_t ret = Verify::ParseHapSignatureInfo(path, signatureInfo_);
199 if (ret != Verify::VERIFY_SUCCESS) {
200 LOG_ERROR("find code sign block buffer failed. errno = %{public}d ", ret);
201 return CS_ERR_FILE_INVALID;
202 }
203
204 for (const auto &value : signatureInfo_.optionBlocks) {
205 if (value.optionalType != CSB_PROPERTY_BLOB) {
206 continue;
207 }
208
209 blobBuffer = value.optionalBlockValue.GetBufferPtr();
210 blobSize = static_cast<uint32_t>(value.optionalBlockValue.GetCapacity());
211 break;
212 }
213
214 if ((blobBuffer == nullptr) || (blobSize <= sizeof(PropertyBlobHeader))) {
215 return CS_CODE_SIGN_NOT_EXISTS;
216 }
217
218 size_t length = 0;
219 do {
220 auto blobHeader = CONST_STATIC_CAST(PropertyBlobHeader, blobBuffer + length);
221 if (blobHeader->type == HAP_CODE_SIGN_BLOCK_ID) {
222 signBlockBuffer = CONST_STATIC_CAST(char, blobHeader) + sizeof(PropertyBlobHeader);
223 signBlockSize = blobHeader->size;
224 break;
225 }
226 length += blobHeader->size + sizeof(PropertyBlobHeader);
227 } while (length < blobSize);
228
229 if ((signBlockBuffer == nullptr) || !signBlockSize) {
230 return CS_CODE_SIGN_NOT_EXISTS;
231 }
232
233 signBuffer = signBlockBuffer;
234 size = signBlockSize;
235 return CS_SUCCESS;
236 }
237
ParseCodeSignBlock(const std::string & realPath,const EntryMap & entryMap,FileType fileType)238 int32_t CodeSignBlock::ParseCodeSignBlock(const std::string &realPath,
239 const EntryMap &entryMap, FileType fileType)
240 {
241 int32_t ret;
242 ReadBuffer codeSignBlock = nullptr;
243 uint32_t codeSignSize;
244
245 ret = GetCodeSignBlockBuffer(realPath, codeSignBlock, codeSignSize);
246 if (ret != CS_SUCCESS) {
247 LOG_ERROR("Get code sign block buffer failed. errno = %{public}d ", ret);
248 return ret;
249 }
250
251 ret = ParseCodeSignBlockBaseInfo(codeSignBlock, codeSignSize);
252 if (ret != CS_SUCCESS) {
253 return ret;
254 }
255 if ((fileType == FILE_SELF) || (fileType == FILE_ALL)) {
256 ret = ParseHapSignInfo(realPath);
257 if (ret != CS_SUCCESS) {
258 return ret;
259 }
260 }
261 if ((fileType == FILE_ENTRY_ONLY) || (fileType == FILE_ALL)) {
262 ret = ParseNativeLibSignInfo(entryMap);
263 if (ret != CS_SUCCESS) {
264 return ret;
265 }
266 }
267 return CS_SUCCESS;
268 }
269 } // CodeSign namespace
270 } // Security namespace
271 } // OHOS namespace
272