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