• 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 
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