• 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 
16 #include "code_sign_utils.h"
17 #include <fstream>
18 #include <string>
19 #include <asm/unistd.h>
20 #include <cstdlib>
21 #include <cstdint>
22 #include <cstdio>
23 #include <iostream>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <linux/fs.h>
28 #include <linux/fsverity.h>
29 #include <linux/stat.h>
30 #include <linux/types.h>
31 
32 #include "cs_hisysevent.h"
33 #include "cs_hitrace.h"
34 #include "code_sign_helper.h"
35 #include "constants.h"
36 #include "directory_ex.h"
37 #include "extractor.h"
38 #include "file_helper.h"
39 #include "log.h"
40 #include "stat_utils.h"
41 #include "signer_info.h"
42 #include "rust_interface.h"
43 
44 namespace OHOS {
45 namespace Security {
46 namespace CodeSign {
47 constexpr uint32_t DEFAULT_HASH_ALGORITHEM = FS_VERITY_HASH_ALG_SHA256;
48 constexpr uint32_t HASH_PAGE_SIZE = 4096;
49 
50 #define NOT_SATISFIED_RETURN(CONDITION, ERROR_CODE, LOG_MESSAGE, ...) do { \
51     if (!(CONDITION)) { \
52         LOG_ERROR(LOG_MESSAGE, ##__VA_ARGS__); \
53         return (ERROR_CODE); \
54     } \
55 } while (0)
56 
EnforceCodeSignForApp(const EntryMap & entryPath,const std::string & signatureFile)57 int32_t CodeSignUtils::EnforceCodeSignForApp(const EntryMap &entryPath,
58     const std::string &signatureFile)
59 {
60     LOG_INFO("Start to enforce");
61     // no files to enable, return directly
62     if (entryPath.empty()) {
63         return CS_SUCCESS;
64     }
65 
66     NOT_SATISFIED_RETURN(CheckFilePathValid(signatureFile, Constants::ENABLE_SIGNATURE_FILE_BASE_PATH),
67         CS_ERR_FILE_PATH, "Signature file is invalid.");
68 
69     // check whether fs-verity is supported by kernel
70     auto iter = entryPath.begin();
71     int32_t ret = CodeSignUtils::IsSupportFsVerity(iter->second);
72     if (ret != CS_SUCCESS) {
73         return ret;
74     }
75 
76     std::unique_ptr<AbilityBase::Extractor> extractor = std::make_unique<AbilityBase::Extractor>(signatureFile);
77     std::vector<std::string> signatureFileList;
78     NOT_SATISFIED_RETURN(extractor->Init(), CS_ERR_EXTRACT_FILES, "Init extractor failed.");
79     // Get signature file entry name
80     extractor->GetSpecifiedTypeFiles(signatureFileList, Constants::FSV_SIG_SUFFIX);
81 
82     for (const auto &pathPair: entryPath) {
83         const std::string &entryName = pathPair.first;
84         const std::string &targetFile = pathPair.second;
85         LOG_DEBUG("Enable entry %{public}s, path = %{public}s", entryName.c_str(), targetFile.c_str());
86         NOT_SATISFIED_RETURN(CheckFilePathValid(targetFile, Constants::ENABLE_APP_BASE_PATH),
87             CS_ERR_FILE_PATH, "App file is invalid.");
88 
89         const std::string &signatureEntry = entryName + Constants::FSV_SIG_SUFFIX;
90         NOT_SATISFIED_RETURN(std::find(signatureFileList.begin(), signatureFileList.end(), signatureEntry) !=
91             signatureFileList.end(),
92             CS_ERR_NO_SIGNATURE, "Fail to find signature for %{public}s", entryName.c_str());
93 
94         std::unique_ptr<uint8_t[]> signatureBuffer = nullptr;
95         size_t signatureSize;
96         NOT_SATISFIED_RETURN(extractor->ExtractToBufByName(signatureEntry, signatureBuffer, signatureSize),
97             CS_ERR_EXTRACT_FILES, "Extract signature failed.");
98 
99         NOT_SATISFIED_RETURN(signatureSize < UINT32_MAX, CS_ERR_INVALID_SIGNATURE, "Signature is too long.");
100 
101         ret = EnforceCodeSignForFile(targetFile, signatureBuffer.get(), static_cast<const uint32_t>(signatureSize));
102         if (ret != CS_SUCCESS) {
103             return ret;
104         }
105     }
106     LOG_INFO("Enforcing app complete");
107     return CS_SUCCESS;
108 }
109 
IsSupportFsVerity(const std::string & path)110 int32_t CodeSignUtils::IsSupportFsVerity(const std::string &path)
111 {
112     struct statx stat = {};
113     if (Statx(AT_FDCWD, path.c_str(), 0, STATX_ALL, &stat) != 0) {
114         LOG_ERROR("Get attributes failed, errno = <%{public}d, %{public}s>",
115             errno, strerror(errno));
116         return CS_ERR_FILE_INVALID;
117     }
118     if (stat.stx_attributes_mask & STATX_ATTR_VERITY) {
119         return CS_SUCCESS;
120     }
121     LOG_INFO("Fs-verity is not supported.");
122     return CS_ERR_FSVREITY_NOT_SUPPORTED;
123 }
124 
IsFsVerityEnabled(int fd)125 int32_t CodeSignUtils::IsFsVerityEnabled(int fd)
126 {
127     unsigned int flags;
128     int ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
129     if (ret < 0) {
130         LOG_ERROR("Get verity flags by ioctl failed. errno = <%{public}d, %{public}s>",
131             errno, strerror(errno));
132         return CS_ERR_FILE_INVALID;
133     }
134     if (flags & FS_VERITY_FL) {
135         return CS_SUCCESS;
136     }
137     return CS_ERR_FSVERITY_NOT_ENABLED;
138 }
139 
EnforceCodeSignForFile(const std::string & path,const ByteBuffer & signature)140 int32_t CodeSignUtils::EnforceCodeSignForFile(const std::string &path, const ByteBuffer &signature)
141 {
142     return EnforceCodeSignForFile(path, signature.GetBuffer(), signature.GetSize());
143 }
144 
EnableCodeSignForFile(const std::string & path,const struct code_sign_enable_arg & arg)145 int32_t CodeSignUtils::EnableCodeSignForFile(const std::string &path, const struct code_sign_enable_arg &arg)
146 {
147     int32_t ret;
148     int32_t error;
149     int32_t fd = open(path.c_str(), O_RDONLY);
150     if (fd < 0) {
151         LOG_ERROR("Open file failed, path = %{public}s, errno = <%{public}d, %{public}s>",
152             path.c_str(), errno, strerror(errno));
153         return CS_ERR_FILE_OPEN;
154     }
155 
156     do {
157         ret = IsFsVerityEnabled(fd);
158         if (ret == CS_SUCCESS) {
159             LOG_INFO("Fs-verity has been enabled.");
160             break;
161         } else if (ret == CS_ERR_FILE_INVALID) {
162             break;
163         }
164 
165         StartTrace(HITRACE_TAG_ACCESS_CONTROL, CODE_SIGN_ENABLE_START);
166         if (!arg.cs_version) {
167             error = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg);
168         } else {
169             error = ioctl(fd, FS_IOC_ENABLE_CODE_SIGN, &arg);
170         }
171         FinishTrace(HITRACE_TAG_ACCESS_CONTROL);
172         if (error < 0) {
173             LOG_ERROR("Enable fs-verity failed, errno = <%{public}d, %{public}s>",
174                 errno, strerror(errno));
175             ReportEnableError(path, errno);
176             ret = CS_ERR_ENABLE;
177             break;
178         }
179         ret = CS_SUCCESS;
180     } while (0);
181     close(fd);
182     LOG_INFO("Enforcing file complete and ret = %{public}d", ret);
183     return ret;
184 }
185 
ParseOwnerIdFromSignature(const ByteBuffer & sigbuffer,std::string & ownerID)186 int CodeSignUtils::ParseOwnerIdFromSignature(const ByteBuffer &sigbuffer, std::string &ownerID)
187 {
188     return SignerInfo::ParseOwnerIdFromSignature(sigbuffer, ownerID);
189 }
190 
EnforceCodeSignForFile(const std::string & path,const uint8_t * signature,const uint32_t size)191 int32_t CodeSignUtils::EnforceCodeSignForFile(const std::string &path, const uint8_t *signature,
192     const uint32_t size)
193 {
194     std::string realPath;
195 
196     if (signature == nullptr || size == 0) {
197         return CS_ERR_NO_SIGNATURE;
198     }
199     if (!OHOS::PathToRealPath(path, realPath)) {
200         return CS_ERR_FILE_PATH;
201     }
202 
203     struct code_sign_enable_arg arg = {0};
204     arg.version = 1; // version of fs-verity, must be 1
205     arg.hash_algorithm = DEFAULT_HASH_ALGORITHEM;
206     arg.block_size = HASH_PAGE_SIZE;
207     arg.sig_size = size;
208     arg.sig_ptr = reinterpret_cast<uintptr_t>(signature);
209     return EnableCodeSignForFile(realPath, arg);
210 }
211 
EnforceCodeSignForAppWithOwnerId(const std::string & ownerId,const std::string & path,const EntryMap & entryPathMap,FileType type)212 int32_t CodeSignUtils::EnforceCodeSignForAppWithOwnerId(const std::string &ownerId, const std::string &path,
213     const EntryMap &entryPathMap, FileType type)
214 {
215     LOG_INFO("Start to enforce codesign FileType:%{public}d, entryPathMap size:%{public}u, path = %{public}s",
216         type, static_cast<uint32_t>(entryPathMap.size()), path.c_str());
217     if (type == FILE_ENTRY_ADD || type == FILE_ENTRY_ONLY || type == FILE_ALL) {
218         {
219             std::lock_guard<std::mutex> lock(storedEntryMapLock_);
220             storedEntryMap_.insert(entryPathMap.begin(), entryPathMap.end());
221         }
222         if (type == FILE_ENTRY_ADD) {
223             LOG_DEBUG("Add entryPathMap complete");
224             return CS_SUCCESS;
225         }
226     } else if (type >= FILE_TYPE_MAX) {
227         return CS_ERR_PARAM_INVALID;
228     }
229     return ProcessCodeSignBlock(ownerId, path, type);
230 }
231 
ProcessCodeSignBlock(const std::string & ownerId,const std::string & path,FileType type)232 int32_t CodeSignUtils::ProcessCodeSignBlock(const std::string &ownerId, const std::string &path, FileType type)
233 {
234     std::string realPath;
235     if (!OHOS::PathToRealPath(path, realPath)) {
236         return CS_ERR_FILE_PATH;
237     }
238     int32_t ret;
239     CodeSignHelper codeSignHelper;
240     {
241         std::lock_guard<std::mutex> lock(storedEntryMapLock_);
242         ret = codeSignHelper.ParseCodeSignBlock(realPath, storedEntryMap_, type);
243         storedEntryMap_.clear();
244     }
245     if (ret != CS_SUCCESS) {
246         return HandleCodeSignBlockFailure(realPath, ret);
247     }
248     return codeSignHelper.ProcessMultiTask(ownerId, path, EnableCodeSignForFile);
249 }
250 
HandleCodeSignBlockFailure(const std::string & realPath,int32_t ret)251 int32_t CodeSignUtils::HandleCodeSignBlockFailure(const std::string &realPath, int32_t ret)
252 {
253     if ((ret == CS_CODE_SIGN_NOT_EXISTS) && InPermissiveMode()) {
254         LOG_DEBUG("Code sign not exists");
255         return CS_SUCCESS;
256     }
257     ReportParseCodeSig(realPath, ret);
258     return ret;
259 }
260 
EnforceCodeSignForApp(const std::string & path,const EntryMap & entryPathMap,FileType type)261 int32_t CodeSignUtils::EnforceCodeSignForApp(const std::string &path, const EntryMap &entryPathMap, FileType type)
262 {
263     return EnforceCodeSignForAppWithOwnerId("", path, entryPathMap, type);
264 }
265 
EnableKeyInProfile(const std::string & bundleName,const ByteBuffer & profileBuffer)266 int32_t CodeSignUtils::EnableKeyInProfile(const std::string &bundleName, const ByteBuffer &profileBuffer)
267 {
268     int ret = EnableKeyInProfileByRust(bundleName.c_str(), profileBuffer.GetBuffer(), profileBuffer.GetSize());
269     if (ret == CS_SUCCESS) {
270         return ret;
271     }
272     LOG_ERROR("Enable key in profile failed. errno = <%{public}d, %{public}s>", errno, strerror(errno));
273     return CS_ERR_PROFILE;
274 }
275 
RemoveKeyInProfile(const std::string & bundleName)276 int32_t CodeSignUtils::RemoveKeyInProfile(const std::string &bundleName)
277 {
278     int ret = RemoveKeyInProfileByRust(bundleName.c_str());
279     if (ret == CS_SUCCESS) {
280         return ret;
281     }
282     LOG_ERROR("Remove key in profile failed. errno = <%{public}d, %{public}s>", errno, strerror(errno));
283     return CS_ERR_PROFILE;
284 }
285 
InPermissiveMode()286 bool CodeSignUtils::InPermissiveMode()
287 {
288 #ifdef SUPPORT_PERMISSIVE_MODE
289     // defaults to on if file does not exsit
290     std::ifstream file(Constants::XPM_DEBUG_FS_MODE_PATH);
291     if (!file.is_open()) {
292         return false;
293     }
294 
295     std::string content;
296     file >> content;
297     file.close();
298 
299     if (content == Constants::PERMISSIVE_CODE_SIGN_MODE) {
300         LOG_DEBUG("Permissive mode is on.");
301         return true;
302     }
303     return false;
304 #else
305     return false;
306 #endif
307 }
308 
IsSupportOHCodeSign()309 bool CodeSignUtils::IsSupportOHCodeSign()
310 {
311 #ifdef SUPPORT_OH_CODE_SIGN
312     return true;
313 #else
314     return false;
315 #endif
316 }
317 }
318 }
319 }
320