• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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