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_enable_multi_task.h"
17
18 #include <fcntl.h>
19 #include <linux/fs.h>
20 #include <linux/stat.h>
21 #include <linux/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
24
25 #include "byte_buffer.h"
26 #include "cs_hisysevent.h"
27 #include "errcode.h"
28 #include "log.h"
29 #include "signer_info.h"
30 #include "stat_utils.h"
31
32 namespace OHOS {
33 namespace Security {
34 namespace CodeSign {
35 constexpr uint32_t CODE_SIGN_TASK_TIMEOUT_MS = 300000;
36 constexpr uint32_t DEFAULT_THREADS_NUM = 8;
37
CodeSignEnableMultiTask()38 CodeSignEnableMultiTask::CodeSignEnableMultiTask(): enableCodeSignTaskWorker_("EnableCodeSign"), taskCallBack_(0)
39 {
40 LOG_INFO("Tasks init.");
41 enableCodeSignTaskWorker_.Start(DEFAULT_THREADS_NUM);
42 }
43
~CodeSignEnableMultiTask()44 CodeSignEnableMultiTask::~CodeSignEnableMultiTask()
45 {
46 LOG_INFO("Tasks finish.");
47 enableCodeSignTaskWorker_.Stop();
48 }
49
AddTaskData(const std::string & targetFile,const struct code_sign_enable_arg & arg)50 void CodeSignEnableMultiTask::AddTaskData(const std::string &targetFile, const struct code_sign_enable_arg &arg)
51 {
52 enableData_.push_back(std::pair<std::string, code_sign_enable_arg>(targetFile, arg));
53 }
54
IsFsVerityEnabled(int fd)55 int32_t CodeSignEnableMultiTask::IsFsVerityEnabled(int fd)
56 {
57 unsigned int flags;
58 int ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
59 if (ret < 0) {
60 LOG_ERROR("Get verity flags by ioctl failed. errno = <%{public}d, %{public}s>",
61 errno, strerror(errno));
62 return CS_ERR_FILE_INVALID;
63 }
64 if (flags & FS_VERITY_FL) {
65 return CS_SUCCESS;
66 }
67 return CS_ERR_FSVERITY_NOT_ENABLED;
68 }
69
IsFsVerityEnabled(const std::string & path)70 int32_t CodeSignEnableMultiTask::IsFsVerityEnabled(const std::string &path)
71 {
72 int32_t fd = open(path.c_str(), O_RDONLY);
73 if (fd < 0) {
74 LOG_ERROR("Open file failed, path = %{public}s, errno = <%{public}d, %{public}s>",
75 path.c_str(), errno, strerror(errno));
76 return CS_ERR_FILE_OPEN;
77 }
78 int32_t ret = IsFsVerityEnabled(fd);
79 if (ret != CS_SUCCESS) {
80 LOG_INFO("Fs-verity is not enable for file = %{public}s.", path.c_str());
81 }
82 close(fd);
83 return ret;
84 }
85
ExecuteEnableCodeSignTask(const std::string & ownerId,const std::string & path,CallbackFunc & func)86 int32_t CodeSignEnableMultiTask::ExecuteEnableCodeSignTask(const std::string &ownerId,
87 const std::string &path, CallbackFunc &func)
88 {
89 SortTaskData();
90
91 LOG_INFO("Tasks num = %{public}zu", enableData_.size());
92 int32_t taskRet = CS_SUCCESS;
93 for (uint32_t i = 0; i < enableData_.size(); i++) {
94 LOG_DEBUG("index: %{public}d, name:%{public}s, %{public}lld",
95 i, enableData_[i].first.c_str(), enableData_[i].second.data_size);
96 ExecuteEnableCodeSignTask(i, taskRet, ownerId, path, func);
97 }
98
99 std::unique_lock<std::mutex> lock(cvLock_);
100 auto waitStatus = taskfinish_.wait_for(lock, std::chrono::milliseconds(CODE_SIGN_TASK_TIMEOUT_MS),
101 [this]() { return this->enableData_.size() == this->taskCallBack_; });
102 if (!waitStatus) {
103 LOG_ERROR("enable code sign timeout, finished tasks = %{public}u", taskCallBack_);
104 return CS_ERR_ENABLE_TIMEOUT;
105 }
106 if (taskRet != CS_SUCCESS) {
107 return taskRet;
108 }
109 int32_t ret = CS_SUCCESS;
110 for (auto &data : enableData_) {
111 const std::string &filePath = data.first;
112 if (IsFsVerityEnabled(filePath) != CS_SUCCESS) {
113 ret = CS_ERR_FSVERITY_NOT_ENABLED;
114 ReportEnableError(filePath, ret);
115 }
116 }
117 return ret;
118 }
119
SortTaskData()120 void CodeSignEnableMultiTask::SortTaskData()
121 {
122 auto compareFileDataSize = [](const std::pair<std::string, code_sign_enable_arg> &a,
123 const std::pair<std::string, code_sign_enable_arg> &b) {
124 return a.second.data_size > b.second.data_size;
125 };
126 sort(enableData_.begin(), enableData_.end(), compareFileDataSize);
127 }
128
ExecuteEnableCodeSignTask(uint32_t & index,int32_t & taskRet,const std::string & ownerId,const std::string & path,CallbackFunc & func)129 void CodeSignEnableMultiTask::ExecuteEnableCodeSignTask(uint32_t &index, int32_t &taskRet,
130 const std::string &ownerId, const std::string &path, CallbackFunc &func)
131 {
132 auto enableCodeSignTask = [this, index, &ownerId, &path, &func, &taskRet]() {
133 LOG_DEBUG("ExecuteEnableCodeSignTask task called");
134 {
135 std::unique_lock<std::mutex> lock(cvLock_);
136 if (taskRet != CS_SUCCESS) {
137 this->taskCallBack_++;
138 if (this->taskCallBack_ == this->enableData_.size()) {
139 this->taskfinish_.notify_one();
140 }
141 return;
142 }
143 }
144
145 int32_t ret = CheckOwnerId(path, ownerId,
146 reinterpret_cast<const uint8_t *>(this->enableData_[index].second.sig_ptr),
147 this->enableData_[index].second.sig_size);
148 if (ret == CS_SUCCESS) {
149 ret = func(this->enableData_[index].first, this->enableData_[index].second);
150 }
151 LOG_DEBUG("Task return info index: %{public}d, ret: %{public}d", index, ret);
152
153 std::unique_lock<std::mutex> lock(cvLock_);
154 if (taskRet == CS_SUCCESS) {
155 taskRet = ret;
156 }
157 this->taskCallBack_++;
158 if (this->taskCallBack_ == this->enableData_.size()) {
159 this->taskfinish_.notify_one();
160 }
161 };
162 enableCodeSignTaskWorker_.AddTask(enableCodeSignTask);
163 }
164
CheckOwnerId(const std::string & path,const std::string & ownerId,const uint8_t * sigPtr,uint32_t sigSize)165 int32_t CodeSignEnableMultiTask::CheckOwnerId(const std::string &path, const std::string &ownerId,
166 const uint8_t *sigPtr, uint32_t sigSize)
167 {
168 if (ownerId.empty()) {
169 return CS_SUCCESS;
170 }
171
172 int32_t ret;
173 ByteBuffer sigBuffer;
174 sigBuffer.CopyFrom(sigPtr, sigSize);
175 std::string retId;
176 ret = SignerInfo::ParseOwnerIdFromSignature(sigBuffer, retId);
177 if (ret != CS_SUCCESS) {
178 ReportInvalidOwner(path, ownerId, "invalid");
179 LOG_ERROR("get ownerId from signature failed, ret %{public}d", ret);
180 } else if (retId != ownerId) {
181 ret = CS_ERR_INVALID_OWNER_ID;
182 ReportInvalidOwner(path, ownerId, retId);
183 LOG_ERROR("invalid ownerId retId %{public}s ownerId %{public}s", retId.c_str(), ownerId.c_str());
184 }
185 return ret;
186 }
187 }
188 }
189 }